2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = ( function() {
8 Roo.each(document.styleSheets, function(s) {
9 if ( s.href && s.href.match(/css-bootstrap4/)) {
14 Roo.Element.prototype.visibilityMode = Roo.Element.DISPLAY;
19 * Ext JS Library 1.1.1
20 * Copyright(c) 2006-2007, Ext JS, LLC.
22 * Originally Released Under LGPL - original licence link has changed is not relivant.
25 * <script type="text/javascript">
31 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
32 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
33 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
36 * @param {Object} config The config object
38 Roo.Shadow = function(config){
39 Roo.apply(this, config);
40 if(typeof this.mode != "string"){
41 this.mode = this.defaultMode;
43 var o = this.offset, a = {h: 0};
44 var rad = Math.floor(this.offset/2);
45 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
51 a.l -= this.offset + rad;
52 a.t -= this.offset + rad;
63 a.l -= (this.offset - rad);
64 a.t -= this.offset + rad;
66 a.w -= (this.offset - rad)*2;
77 a.l -= (this.offset - rad);
78 a.t -= (this.offset - rad);
80 a.w -= (this.offset + rad + 1);
81 a.h -= (this.offset + rad);
90 Roo.Shadow.prototype = {
93 * The shadow display mode. Supports the following options:<br />
94 * sides: Shadow displays on both sides and bottom only<br />
95 * frame: Shadow displays equally on all four sides<br />
96 * drop: Traditional bottom-right drop shadow (default)
99 * @cfg {String} offset
100 * The number of pixels to offset the shadow from the element (defaults to 4)
108 * Displays the shadow under the target element
109 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
111 show : function(target){
112 target = Roo.get(target);
114 this.el = Roo.Shadow.Pool.pull();
115 if(this.el.dom.nextSibling != target.dom){
116 this.el.insertBefore(target);
119 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
121 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
124 target.getLeft(true),
129 this.el.dom.style.display = "block";
133 * Returns true if the shadow is visible, else false
135 isVisible : function(){
136 return this.el ? true : false;
140 * Direct alignment when values are already available. Show must be called at least once before
141 * calling this method to ensure it is initialized.
142 * @param {Number} left The target element left position
143 * @param {Number} top The target element top position
144 * @param {Number} width The target element width
145 * @param {Number} height The target element height
147 realign : function(l, t, w, h){
151 var a = this.adjusts, d = this.el.dom, s = d.style;
153 s.left = (l+a.l)+"px";
154 s.top = (t+a.t)+"px";
155 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
157 if(s.width != sws || s.height != shs){
161 var cn = d.childNodes;
162 var sww = Math.max(0, (sw-12))+"px";
163 cn[0].childNodes[1].style.width = sww;
164 cn[1].childNodes[1].style.width = sww;
165 cn[2].childNodes[1].style.width = sww;
166 cn[1].style.height = Math.max(0, (sh-12))+"px";
176 this.el.dom.style.display = "none";
177 Roo.Shadow.Pool.push(this.el);
183 * Adjust the z-index of this shadow
184 * @param {Number} zindex The new z-index
186 setZIndex : function(z){
189 this.el.setStyle("z-index", z);
194 // Private utility class that manages the internal Shadow cache
195 Roo.Shadow.Pool = function(){
197 var markup = Roo.isIE ?
198 '<div class="x-ie-shadow"></div>' :
199 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
204 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
205 sh.autoBoxAdjust = false;
217 * base class for bootstrap elements.
221 Roo.bootstrap = Roo.bootstrap || {};
223 * @class Roo.bootstrap.Component
224 * @extends Roo.Component
225 * Bootstrap Component base class
226 * @cfg {String} cls css class
227 * @cfg {String} style any extra css
228 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
229 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
230 * @cfg {string} dataId cutomer id
231 * @cfg {string} name Specifies name attribute
232 * @cfg {string} tooltip Text for the tooltip
233 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
234 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
237 * Do not use directly - it does not do anything..
238 * @param {Object} config The config object
243 Roo.bootstrap.Component = function(config){
244 Roo.bootstrap.Component.superclass.constructor.call(this, config);
248 * @event childrenrendered
249 * Fires when the children have been rendered..
250 * @param {Roo.bootstrap.Component} this
252 "childrenrendered" : true
261 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
264 allowDomMove : false, // to stop relocations in parent onRender...
274 * Initialize Events for the element
276 initEvents : function() { },
282 can_build_overlaid : true,
284 container_method : false,
291 // returns the parent component..
292 return Roo.ComponentMgr.get(this.parentId)
298 onRender : function(ct, position)
300 // Roo.log("Call onRender: " + this.xtype);
302 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
305 if (this.el.attr('xtype')) {
306 this.el.attr('xtypex', this.el.attr('xtype'));
307 this.el.dom.removeAttribute('xtype');
317 var cfg = Roo.apply({}, this.getAutoCreate());
319 cfg.id = this.id || Roo.id();
321 // fill in the extra attributes
322 if (this.xattr && typeof(this.xattr) =='object') {
323 for (var i in this.xattr) {
324 cfg[i] = this.xattr[i];
329 cfg.dataId = this.dataId;
333 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
336 if (this.style) { // fixme needs to support more complex style data.
337 cfg.style = this.style;
341 cfg.name = this.name;
344 this.el = ct.createChild(cfg, position);
347 this.tooltipEl().attr('tooltip', this.tooltip);
350 if(this.tabIndex !== undefined){
351 this.el.dom.setAttribute('tabIndex', this.tabIndex);
358 * Fetch the element to add children to
359 * @return {Roo.Element} defaults to this.el
361 getChildContainer : function()
366 * Fetch the element to display the tooltip on.
367 * @return {Roo.Element} defaults to this.el
369 tooltipEl : function()
374 addxtype : function(tree,cntr)
378 cn = Roo.factory(tree);
379 //Roo.log(['addxtype', cn]);
381 cn.parentType = this.xtype; //??
382 cn.parentId = this.id;
384 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
385 if (typeof(cn.container_method) == 'string') {
386 cntr = cn.container_method;
390 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
392 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
394 var build_from_html = Roo.XComponent.build_from_html;
396 var is_body = (tree.xtype == 'Body') ;
398 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
400 var self_cntr_el = Roo.get(this[cntr](false));
402 // do not try and build conditional elements
403 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
407 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
408 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
409 return this.addxtypeChild(tree,cntr, is_body);
412 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
415 return this.addxtypeChild(Roo.apply({}, tree),cntr);
418 Roo.log('skipping render');
424 if (!build_from_html) {
428 // this i think handles overlaying multiple children of the same type
429 // with the sam eelement.. - which might be buggy..
431 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
437 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
441 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
448 addxtypeChild : function (tree, cntr, is_body)
450 Roo.debug && Roo.log('addxtypeChild:' + cntr);
452 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
455 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
456 (typeof(tree['flexy:foreach']) != 'undefined');
460 skip_children = false;
461 // render the element if it's not BODY.
464 // if parent was disabled, then do not try and create the children..
465 if(!this[cntr](true)){
470 cn = Roo.factory(tree);
472 cn.parentType = this.xtype; //??
473 cn.parentId = this.id;
475 var build_from_html = Roo.XComponent.build_from_html;
478 // does the container contain child eleemnts with 'xtype' attributes.
479 // that match this xtype..
480 // note - when we render we create these as well..
481 // so we should check to see if body has xtype set.
482 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
484 var self_cntr_el = Roo.get(this[cntr](false));
485 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
487 //Roo.log(Roo.XComponent.build_from_html);
488 //Roo.log("got echild:");
491 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
492 // and are not displayed -this causes this to use up the wrong element when matching.
493 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
496 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
497 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
503 //echild.dom.removeAttribute('xtype');
505 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
506 Roo.debug && Roo.log(self_cntr_el);
507 Roo.debug && Roo.log(echild);
508 Roo.debug && Roo.log(cn);
514 // if object has flexy:if - then it may or may not be rendered.
515 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
516 // skip a flexy if element.
517 Roo.debug && Roo.log('skipping render');
518 Roo.debug && Roo.log(tree);
520 Roo.debug && Roo.log('skipping all children');
521 skip_children = true;
526 // actually if flexy:foreach is found, we really want to create
527 // multiple copies here...
529 //Roo.log(this[cntr]());
530 // some elements do not have render methods.. like the layouts...
532 if(this[cntr](true) === false){
537 cn.render && cn.render(this[cntr](true));
540 // then add the element..
547 if (typeof (tree.menu) != 'undefined') {
548 tree.menu.parentType = cn.xtype;
549 tree.menu.triggerEl = cn.el;
550 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
554 if (!tree.items || !tree.items.length) {
556 //Roo.log(["no children", this]);
561 var items = tree.items;
564 //Roo.log(items.length);
566 if (!skip_children) {
567 for(var i =0;i < items.length;i++) {
568 // Roo.log(['add child', items[i]]);
569 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
575 //Roo.log("fire childrenrendered");
577 cn.fireEvent('childrenrendered', this);
583 * Set the element that will be used to show or hide
585 setVisibilityEl : function(el)
587 this.visibilityEl = el;
591 * Get the element that will be used to show or hide
593 getVisibilityEl : function()
595 if (typeof(this.visibilityEl) == 'object') {
596 return this.visibilityEl;
599 if (typeof(this.visibilityEl) == 'string') {
600 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
607 * Show a component - removes 'hidden' class
611 if(!this.getVisibilityEl()){
615 this.getVisibilityEl().removeClass(['hidden','d-none']);
617 this.fireEvent('show', this);
622 * Hide a component - adds 'hidden' class
626 if(!this.getVisibilityEl()){
630 this.getVisibilityEl().addClass(['hidden','d-none']);
632 this.fireEvent('hide', this);
645 * @class Roo.bootstrap.Element
646 * @extends Roo.bootstrap.Component
647 * Bootstrap Element class
648 * @cfg {String} html contents of the element
649 * @cfg {String} tag tag of the element
650 * @cfg {String} cls class of the element
651 * @cfg {Boolean} preventDefault (true|false) default false
652 * @cfg {Boolean} clickable (true|false) default false
655 * Create a new Element
656 * @param {Object} config The config object
659 Roo.bootstrap.Element = function(config){
660 Roo.bootstrap.Element.superclass.constructor.call(this, config);
666 * When a element is chick
667 * @param {Roo.bootstrap.Element} this
668 * @param {Roo.EventObject} e
674 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
679 preventDefault: false,
682 getAutoCreate : function(){
686 // cls: this.cls, double assign in parent class Component.js :: onRender
693 initEvents: function()
695 Roo.bootstrap.Element.superclass.initEvents.call(this);
698 this.el.on('click', this.onClick, this);
703 onClick : function(e)
705 if(this.preventDefault){
709 this.fireEvent('click', this, e);
712 getValue : function()
714 return this.el.dom.innerHTML;
717 setValue : function(value)
719 this.el.dom.innerHTML = value;
734 * @class Roo.bootstrap.DropTarget
735 * @extends Roo.bootstrap.Element
736 * Bootstrap DropTarget class
738 * @cfg {string} name dropable name
741 * Create a new Dropable Area
742 * @param {Object} config The config object
745 Roo.bootstrap.DropTarget = function(config){
746 Roo.bootstrap.DropTarget.superclass.constructor.call(this, config);
752 * When a element is chick
753 * @param {Roo.bootstrap.Element} this
754 * @param {Roo.EventObject} e
760 Roo.extend(Roo.bootstrap.DropTarget, Roo.bootstrap.Element, {
763 getAutoCreate : function(){
768 initEvents: function()
770 Roo.bootstrap.DropTarget.superclass.initEvents.call(this);
771 this.dropZone = new Roo.dd.DropTarget(this.getEl(), {
774 drop : this.dragDrop.createDelegate(this),
775 enter : this.dragEnter.createDelegate(this),
776 out : this.dragOut.createDelegate(this),
777 over : this.dragOver.createDelegate(this)
781 this.dropZone.DDM.useCache = false // so data gets refreshed when we resize stuff
784 dragDrop : function(source,e,data)
786 // user has to decide how to impliment this.
789 //this.fireEvent('drop', this, source, e ,data);
793 dragEnter : function(n, dd, e, data)
795 // probably want to resize the element to match the dropped element..
797 this.originalSize = this.el.getSize();
798 this.el.setSize( n.el.getSize());
799 this.dropZone.DDM.refreshCache(this.name);
800 Roo.log([n, dd, e, data]);
803 dragOut : function(value)
805 // resize back to normal
807 this.el.setSize(this.originalSize);
808 this.dropZone.resetConstraints();
811 dragOver : function()
828 * @class Roo.bootstrap.Body
829 * @extends Roo.bootstrap.Component
830 * Bootstrap Body class
834 * @param {Object} config The config object
837 Roo.bootstrap.Body = function(config){
839 config = config || {};
841 Roo.bootstrap.Body.superclass.constructor.call(this, config);
842 this.el = Roo.get(config.el ? config.el : document.body );
843 if (this.cls && this.cls.length) {
844 Roo.get(document.body).addClass(this.cls);
848 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
850 is_body : true,// just to make sure it's constructed?
855 onRender : function(ct, position)
857 /* Roo.log("Roo.bootstrap.Body - onRender");
858 if (this.cls && this.cls.length) {
859 Roo.get(document.body).addClass(this.cls);
878 * @class Roo.bootstrap.ButtonGroup
879 * @extends Roo.bootstrap.Component
880 * Bootstrap ButtonGroup class
881 * @cfg {String} size lg | sm | xs (default empty normal)
882 * @cfg {String} align vertical | justified (default none)
883 * @cfg {String} direction up | down (default down)
884 * @cfg {Boolean} toolbar false | true
885 * @cfg {Boolean} btn true | false
890 * @param {Object} config The config object
893 Roo.bootstrap.ButtonGroup = function(config){
894 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
897 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
905 getAutoCreate : function(){
911 cfg.html = this.html || cfg.html;
922 if (['vertical','justified'].indexOf(this.align)!==-1) {
923 cfg.cls = 'btn-group-' + this.align;
925 if (this.align == 'justified') {
926 console.log(this.items);
930 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
931 cfg.cls += ' btn-group-' + this.size;
934 if (this.direction == 'up') {
935 cfg.cls += ' dropup' ;
941 * Add a button to the group (similar to NavItem API.)
943 addItem : function(cfg)
945 var cn = new Roo.bootstrap.Button(cfg);
947 cn.parentId = this.id;
948 cn.onRender(this.el, null);
962 * @class Roo.bootstrap.Button
963 * @extends Roo.bootstrap.Component
964 * Bootstrap Button class
965 * @cfg {String} html The button content
966 * @cfg {String} weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default
967 * @cfg {String} badge_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default (same as button)
968 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
969 * @cfg {String} size (lg|sm|xs)
970 * @cfg {String} tag (a|input|submit)
971 * @cfg {String} href empty or href
972 * @cfg {Boolean} disabled default false;
973 * @cfg {Boolean} isClose default false;
974 * @cfg {String} glyphicon depricated - use fa
975 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
976 * @cfg {String} badge text for badge
977 * @cfg {String} theme (default|glow)
978 * @cfg {Boolean} inverse dark themed version
979 * @cfg {Boolean} toggle is it a slidy toggle button
980 * @cfg {Boolean} pressed default null - if the button ahs active state
981 * @cfg {String} ontext text for on slidy toggle state
982 * @cfg {String} offtext text for off slidy toggle state
983 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
984 * @cfg {Boolean} removeClass remove the standard class..
985 * @cfg {String} target (_self|_blank|_parent|_top|other) target for a href.
986 * @cfg {Boolean} grpup if parent is a btn group - then it turns it into a toogleGroup.
989 * Create a new button
990 * @param {Object} config The config object
994 Roo.bootstrap.Button = function(config){
995 Roo.bootstrap.Button.superclass.constructor.call(this, config);
1001 * When a button is pressed
1002 * @param {Roo.bootstrap.Button} btn
1003 * @param {Roo.EventObject} e
1008 * When a button is double clicked
1009 * @param {Roo.bootstrap.Button} btn
1010 * @param {Roo.EventObject} e
1015 * After the button has been toggles
1016 * @param {Roo.bootstrap.Button} btn
1017 * @param {Roo.EventObject} e
1018 * @param {boolean} pressed (also available as button.pressed)
1024 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
1045 preventDefault: true,
1054 getAutoCreate : function(){
1062 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
1063 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
1064 this.tag = 'button';
1068 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
1070 if (this.toggle == true) {
1073 cls: 'slider-frame roo-button',
1077 'data-on-text':'ON',
1078 'data-off-text':'OFF',
1079 cls: 'slider-button',
1084 // why are we validating the weights?
1085 if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
1086 cfg.cls += ' ' + this.weight;
1093 cfg.cls += ' close';
1095 cfg["aria-hidden"] = true;
1097 cfg.html = "×";
1103 if (this.theme==='default') {
1104 cfg.cls = 'btn roo-button';
1106 //if (this.parentType != 'Navbar') {
1107 this.weight = this.weight.length ? this.weight : 'default';
1109 if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
1111 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
1112 var weight = this.weight == 'default' ? 'secondary' : this.weight;
1113 cfg.cls += ' btn-' + outline + weight;
1114 if (this.weight == 'default') {
1116 cfg.cls += ' btn-' + this.weight;
1119 } else if (this.theme==='glow') {
1122 cfg.cls = 'btn-glow roo-button';
1124 if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
1126 cfg.cls += ' ' + this.weight;
1132 this.cls += ' inverse';
1136 if (this.active || this.pressed === true) {
1137 cfg.cls += ' active';
1140 if (this.disabled) {
1141 cfg.disabled = 'disabled';
1145 Roo.log('changing to ul' );
1147 this.glyphicon = 'caret';
1148 if (Roo.bootstrap.version == 4) {
1149 this.fa = 'caret-down';
1154 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
1156 //gsRoo.log(this.parentType);
1157 if (this.parentType === 'Navbar' && !this.parent().bar) {
1158 Roo.log('changing to li?');
1167 href : this.href || '#'
1170 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
1171 cfg.cls += ' dropdown';
1178 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
1180 if (this.glyphicon) {
1181 cfg.html = ' ' + cfg.html;
1186 cls: 'glyphicon glyphicon-' + this.glyphicon
1191 cfg.html = ' ' + cfg.html;
1196 cls: 'fa fas fa-' + this.fa
1206 // cfg.cls='btn roo-button';
1210 var value = cfg.html;
1215 cls: 'glyphicon glyphicon-' + this.glyphicon,
1222 cls: 'fa fas fa-' + this.fa,
1227 var bw = this.badge_weight.length ? this.badge_weight :
1228 (this.weight.length ? this.weight : 'secondary');
1229 bw = bw == 'default' ? 'secondary' : bw;
1235 cls: 'badge badge-' + bw,
1244 cfg.cls += ' dropdown';
1245 cfg.html = typeof(cfg.html) != 'undefined' ?
1246 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
1249 if (cfg.tag !== 'a' && this.href !== '') {
1250 throw "Tag must be a to set href.";
1251 } else if (this.href.length > 0) {
1252 cfg.href = this.href;
1255 if(this.removeClass){
1260 cfg.target = this.target;
1265 initEvents: function() {
1266 // Roo.log('init events?');
1267 // Roo.log(this.el.dom);
1270 if (typeof (this.menu) != 'undefined') {
1271 this.menu.parentType = this.xtype;
1272 this.menu.triggerEl = this.el;
1273 this.addxtype(Roo.apply({}, this.menu));
1277 if (this.el.hasClass('roo-button')) {
1278 this.el.on('click', this.onClick, this);
1279 this.el.on('dblclick', this.onDblClick, this);
1281 this.el.select('.roo-button').on('click', this.onClick, this);
1282 this.el.select('.roo-button').on('dblclick', this.onDblClick, this);
1286 if(this.removeClass){
1287 this.el.on('click', this.onClick, this);
1290 if (this.group === true) {
1291 if (this.pressed === false || this.pressed === true) {
1294 this.pressed = false;
1295 this.setActive(this.pressed);
1300 this.el.enableDisplayMode();
1303 onClick : function(e)
1305 if (this.disabled) {
1309 Roo.log('button on click ');
1310 if(this.preventDefault){
1319 this.setActive(true);
1320 var pi = this.parent().items;
1321 for (var i = 0;i < pi.length;i++) {
1322 if (this == pi[i]) {
1325 if (pi[i].el.hasClass('roo-button')) {
1326 pi[i].setActive(false);
1329 this.fireEvent('click', this, e);
1333 if (this.pressed === true || this.pressed === false) {
1334 this.toggleActive(e);
1338 this.fireEvent('click', this, e);
1340 onDblClick: function(e)
1342 if (this.disabled) {
1345 if(this.preventDefault){
1348 this.fireEvent('dblclick', this, e);
1351 * Enables this button
1355 this.disabled = false;
1356 this.el.removeClass('disabled');
1360 * Disable this button
1362 disable : function()
1364 this.disabled = true;
1365 this.el.addClass('disabled');
1368 * sets the active state on/off,
1369 * @param {Boolean} state (optional) Force a particular state
1371 setActive : function(v) {
1373 this.el[v ? 'addClass' : 'removeClass']('active');
1377 * toggles the current active state
1379 toggleActive : function(e)
1381 this.setActive(!this.pressed); // this modifies pressed...
1382 this.fireEvent('toggle', this, e, this.pressed);
1385 * get the current active state
1386 * @return {boolean} true if it's active
1388 isActive : function()
1390 return this.el.hasClass('active');
1393 * set the text of the first selected button
1395 setText : function(str)
1397 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
1400 * get the text of the first selected button
1402 getText : function()
1404 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1407 setWeight : function(str)
1409 this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-' + w; } ) );
1410 this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-outline-' + w; } ) );
1412 var outline = this.outline ? 'outline-' : '';
1413 if (str == 'default') {
1414 this.el.addClass('btn-default btn-outline-secondary');
1417 this.el.addClass('btn-' + outline + str);
1422 // fixme - this is probably generic bootstrap - should go in some kind of enum file.. - like sizes.
1424 Roo.bootstrap.Button.weights = [
1444 * @class Roo.bootstrap.Column
1445 * @extends Roo.bootstrap.Component
1446 * Bootstrap Column class
1447 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1448 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1449 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1450 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1451 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1452 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1453 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1454 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1457 * @cfg {Boolean} hidden (true|false) hide the element
1458 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1459 * @cfg {String} fa (ban|check|...) font awesome icon
1460 * @cfg {Number} fasize (1|2|....) font awsome size
1462 * @cfg {String} icon (info-sign|check|...) glyphicon name
1464 * @cfg {String} html content of column.
1467 * Create a new Column
1468 * @param {Object} config The config object
1471 Roo.bootstrap.Column = function(config){
1472 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1475 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1493 getAutoCreate : function(){
1494 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1502 var sizes = ['xs','sm','md','lg'];
1503 sizes.map(function(size ,ix){
1504 //Roo.log( size + ':' + settings[size]);
1506 if (settings[size+'off'] !== false) {
1507 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1510 if (settings[size] === false) {
1514 if (!settings[size]) { // 0 = hidden
1515 cfg.cls += ' hidden-' + size + ' hidden-' + size + '-down';
1517 for (var i = ix; i > -1; i--) {
1518 cfg.cls += ' d-' + sizes[i] + '-none';
1524 cfg.cls += ' col-' + size + '-' + settings[size] + (
1525 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1531 cfg.cls += ' hidden';
1534 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1535 cfg.cls +=' alert alert-' + this.alert;
1539 if (this.html.length) {
1540 cfg.html = this.html;
1544 if (this.fasize > 1) {
1545 fasize = ' fa-' + this.fasize + 'x';
1547 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1552 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1571 * @class Roo.bootstrap.Container
1572 * @extends Roo.bootstrap.Component
1573 * Bootstrap Container class
1574 * @cfg {Boolean} jumbotron is it a jumbotron element
1575 * @cfg {String} html content of element
1576 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1577 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1578 * @cfg {String} header content of header (for panel)
1579 * @cfg {String} footer content of footer (for panel)
1580 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1581 * @cfg {String} tag (header|aside|section) type of HTML tag.
1582 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1583 * @cfg {String} fa font awesome icon
1584 * @cfg {String} icon (info-sign|check|...) glyphicon name
1585 * @cfg {Boolean} hidden (true|false) hide the element
1586 * @cfg {Boolean} expandable (true|false) default false
1587 * @cfg {Boolean} expanded (true|false) default true
1588 * @cfg {String} rheader contet on the right of header
1589 * @cfg {Boolean} clickable (true|false) default false
1593 * Create a new Container
1594 * @param {Object} config The config object
1597 Roo.bootstrap.Container = function(config){
1598 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1604 * After the panel has been expand
1606 * @param {Roo.bootstrap.Container} this
1611 * After the panel has been collapsed
1613 * @param {Roo.bootstrap.Container} this
1618 * When a element is chick
1619 * @param {Roo.bootstrap.Container} this
1620 * @param {Roo.EventObject} e
1626 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1644 getChildContainer : function() {
1650 if (this.panel.length) {
1651 return this.el.select('.panel-body',true).first();
1658 getAutoCreate : function(){
1661 tag : this.tag || 'div',
1665 if (this.jumbotron) {
1666 cfg.cls = 'jumbotron';
1671 // - this is applied by the parent..
1673 // cfg.cls = this.cls + '';
1676 if (this.sticky.length) {
1678 var bd = Roo.get(document.body);
1679 if (!bd.hasClass('bootstrap-sticky')) {
1680 bd.addClass('bootstrap-sticky');
1681 Roo.select('html',true).setStyle('height', '100%');
1684 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1688 if (this.well.length) {
1689 switch (this.well) {
1692 cfg.cls +=' well well-' +this.well;
1701 cfg.cls += ' hidden';
1705 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1706 cfg.cls +=' alert alert-' + this.alert;
1711 if (this.panel.length) {
1712 cfg.cls += ' panel panel-' + this.panel;
1714 if (this.header.length) {
1718 if(this.expandable){
1720 cfg.cls = cfg.cls + ' expandable';
1724 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1732 cls : 'panel-title',
1733 html : (this.expandable ? ' ' : '') + this.header
1737 cls: 'panel-header-right',
1743 cls : 'panel-heading',
1744 style : this.expandable ? 'cursor: pointer' : '',
1752 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1757 if (this.footer.length) {
1759 cls : 'panel-footer',
1768 body.html = this.html || cfg.html;
1769 // prefix with the icons..
1771 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1774 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1779 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1780 cfg.cls = 'container';
1786 initEvents: function()
1788 if(this.expandable){
1789 var headerEl = this.headerEl();
1792 headerEl.on('click', this.onToggleClick, this);
1797 this.el.on('click', this.onClick, this);
1802 onToggleClick : function()
1804 var headerEl = this.headerEl();
1820 if(this.fireEvent('expand', this)) {
1822 this.expanded = true;
1824 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1826 this.el.select('.panel-body',true).first().removeClass('hide');
1828 var toggleEl = this.toggleEl();
1834 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1839 collapse : function()
1841 if(this.fireEvent('collapse', this)) {
1843 this.expanded = false;
1845 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1846 this.el.select('.panel-body',true).first().addClass('hide');
1848 var toggleEl = this.toggleEl();
1854 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1858 toggleEl : function()
1860 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1864 return this.el.select('.panel-heading .fa',true).first();
1867 headerEl : function()
1869 if(!this.el || !this.panel.length || !this.header.length){
1873 return this.el.select('.panel-heading',true).first()
1878 if(!this.el || !this.panel.length){
1882 return this.el.select('.panel-body',true).first()
1885 titleEl : function()
1887 if(!this.el || !this.panel.length || !this.header.length){
1891 return this.el.select('.panel-title',true).first();
1894 setTitle : function(v)
1896 var titleEl = this.titleEl();
1902 titleEl.dom.innerHTML = v;
1905 getTitle : function()
1908 var titleEl = this.titleEl();
1914 return titleEl.dom.innerHTML;
1917 setRightTitle : function(v)
1919 var t = this.el.select('.panel-header-right',true).first();
1925 t.dom.innerHTML = v;
1928 onClick : function(e)
1932 this.fireEvent('click', this, e);
1939 * This is BS4's Card element.. - similar to our containers probably..
1943 * @class Roo.bootstrap.Card
1944 * @extends Roo.bootstrap.Component
1945 * Bootstrap Card class
1948 * possible... may not be implemented..
1949 * @cfg {String} header_image src url of image.
1950 * @cfg {String|Object} header
1951 * @cfg {Number} header_size (0|1|2|3|4|5) H1 or H2 etc.. 0 indicates default
1952 * @cfg {Number} header_weight (primary|secondary|success|info|warning|danger|light|dark)
1954 * @cfg {String} title
1955 * @cfg {String} subtitle
1956 * @cfg {String|Boolean} html -- html contents - or just use children.. use false to hide it..
1957 * @cfg {String} footer
1959 * @cfg {String} weight (primary|warning|info|danger|secondary|success|light|dark)
1961 * @cfg {String} margin (0|1|2|3|4|5|auto)
1962 * @cfg {String} margin_top (0|1|2|3|4|5|auto)
1963 * @cfg {String} margin_bottom (0|1|2|3|4|5|auto)
1964 * @cfg {String} margin_left (0|1|2|3|4|5|auto)
1965 * @cfg {String} margin_right (0|1|2|3|4|5|auto)
1966 * @cfg {String} margin_x (0|1|2|3|4|5|auto)
1967 * @cfg {String} margin_y (0|1|2|3|4|5|auto)
1969 * @cfg {String} padding (0|1|2|3|4|5)
1970 * @cfg {String} padding_top (0|1|2|3|4|5)next_to_card
1971 * @cfg {String} padding_bottom (0|1|2|3|4|5)
1972 * @cfg {String} padding_left (0|1|2|3|4|5)
1973 * @cfg {String} padding_right (0|1|2|3|4|5)
1974 * @cfg {String} padding_x (0|1|2|3|4|5)
1975 * @cfg {String} padding_y (0|1|2|3|4|5)
1977 * @cfg {String} display (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1978 * @cfg {String} display_xs (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1979 * @cfg {String} display_sm (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1980 * @cfg {String} display_lg (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1981 * @cfg {String} display_xl (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1983 * @config {Boolean} dragable if this card can be dragged.
1984 * @config {String} drag_group group for drag
1985 * @config {Boolean} dropable if this card can recieve other cards being dropped onto it..
1986 * @config {String} drop_group group for drag
1988 * @config {Boolean} collapsable can the body be collapsed.
1989 * @config {Boolean} collapsed is the body collapsed when rendered...
1990 * @config {Boolean} rotateable can the body be rotated by clicking on it..
1991 * @config {Boolean} rotated is the body rotated when rendered...
1994 * Create a new Container
1995 * @param {Object} config The config object
1998 Roo.bootstrap.Card = function(config){
1999 Roo.bootstrap.Card.superclass.constructor.call(this, config);
2005 * When a element a card is dropped
2006 * @param {Roo.bootstrap.Card} this
2009 * @param {Roo.bootstrap.Card} move_card the card being dropped?
2010 * @param {String} position 'above' or 'below'
2011 * @param {Roo.bootstrap.Card} next_to_card What card position is relative to of 'false' for empty list.
2017 * When a element a card is rotate
2018 * @param {Roo.bootstrap.Element} this
2019 * @param {Roo.Element} n the node being dropped?
2020 * @param {Boolean} rotate status
2028 Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component, {
2033 margin: '', /// may be better in component?
2063 collapsable : false,
2072 childContainer : false,
2073 dropEl : false, /// the dom placeholde element that indicates drop location.
2074 containerEl: false, // body container
2075 bodyEl: false, // card-body
2076 headerContainerEl : false, //
2079 layoutCls : function()
2083 Roo.log(this.margin_bottom.length);
2084 ['', 'top', 'bottom', 'left', 'right', 'x', 'y' ].forEach(function(v) {
2085 // in theory these can do margin_top : ml-xs-3 ??? but we don't support that yet
2087 if (('' + t['margin' + (v.length ? '_' : '') + v]).length) {
2088 cls += ' m' + (v.length ? v[0] : '') + '-' + t['margin' + (v.length ? '_' : '') + v];
2090 if (('' + t['padding' + (v.length ? '_' : '') + v]).length) {
2091 cls += ' p' + (v.length ? v[0] : '') + '-' + t['padding' + (v.length ? '_' : '') + v];
2095 ['', 'xs', 'sm', 'lg', 'xl'].forEach(function(v) {
2096 if (('' + t['display' + (v.length ? '_' : '') + v]).length) {
2097 cls += ' d' + (v.length ? '-' : '') + v + '-' + t['display' + (v.length ? '_' : '') + v]
2101 // more generic support?
2109 // Roo.log("Call onRender: " + this.xtype);
2110 /* We are looking at something like this.
2112 <img src="..." class="card-img-top" alt="...">
2113 <div class="card-body">
2114 <h5 class="card-title">Card title</h5>
2115 <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
2117 >> this bit is really the body...
2118 <div> << we will ad dthis in hopefully it will not break shit.
2120 ** card text does not actually have any styling...
2122 <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
2125 <a href="#" class="card-link">Card link</a>
2128 <div class="card-footer">
2129 <small class="text-muted">Last updated 3 mins ago</small>
2133 getAutoCreate : function(){
2141 if (this.weight.length && this.weight != 'light') {
2142 cfg.cls += ' text-white';
2144 cfg.cls += ' text-dark'; // need as it's nested..
2146 if (this.weight.length) {
2147 cfg.cls += ' bg-' + this.weight;
2150 cfg.cls += ' ' + this.layoutCls();
2153 var hdr_ctr = false;
2154 if (this.header.length) {
2156 tag : this.header_size > 0 ? 'h' + this.header_size : 'div',
2157 cls : 'card-header ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
2165 cls : 'card-header d-none ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
2171 if (this.collapsable) {
2174 cls : 'd-block user-select-none',
2178 cls : 'roo-collapse-toggle fa fa-chevron-down float-right ' + (this.collapsed ? 'collapsed' : '')
2183 hdr.cn.push(hdr_ctr);
2188 cls: 'roo-card-header-ctr' + ( this.header.length ? '' : ' d-none'),
2193 if (this.header_image.length) {
2196 cls : 'card-img-top',
2197 src: this.header_image // escape?
2202 cls : 'card-img-top d-none'
2208 cls : 'card-body' + (this.html === false ? ' d-none' : ''),
2212 if (this.collapsable || this.rotateable) {
2215 cls : 'roo-collapsable collapse ' + (this.collapsed || this.rotated ? '' : 'show'),
2222 if (this.title.length) {
2226 src: this.title // escape?
2230 if (this.subtitle.length) {
2234 src: this.subtitle // escape?
2240 cls : 'roo-card-body-ctr'
2243 if (this.html.length) {
2249 // fixme ? handle objects?
2251 if (this.footer.length) {
2254 cls : 'card-footer ' + (this.rotated ? 'd-none' : ''),
2259 cfg.cn.push({cls : 'card-footer d-none'});
2268 getCardHeader : function()
2270 var ret = this.el.select('.card-header',true).first();
2271 if (ret.hasClass('d-none')) {
2272 ret.removeClass('d-none');
2277 getCardFooter : function()
2279 var ret = this.el.select('.card-footer',true).first();
2280 if (ret.hasClass('d-none')) {
2281 ret.removeClass('d-none');
2286 getCardImageTop : function()
2288 var ret = this.el.select('.card-img-top',true).first();
2289 if (ret.hasClass('d-none')) {
2290 ret.removeClass('d-none');
2296 getChildContainer : function()
2302 return this.el.select('.roo-card-body-ctr',true).first();
2305 initEvents: function()
2307 this.bodyEl = this.el.select('.card-body',true).first();
2308 this.containerEl = this.getChildContainer();
2310 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
2311 containerScroll: true,
2312 ddGroup: this.drag_group || 'default_card_drag_group'
2314 this.dragZone.getDragData = this.getDragData.createDelegate(this);
2316 if (this.dropable) {
2317 this.dropZone = new Roo.dd.DropZone(this.el.select('.card-body',true).first() , {
2318 containerScroll: true,
2319 ddGroup: this.drop_group || 'default_card_drag_group'
2321 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
2322 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
2323 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
2324 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
2325 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
2328 if (this.collapsable) {
2329 this.el.select('.card-header',true).on('click', this.onToggleCollapse, this);
2331 if (this.rotateable) {
2332 this.el.select('.card-header',true).on('click', this.onToggleRotate, this);
2334 this.collapsableEl = this.el.select('.roo-collapsable').first();
2336 this.footerEl = this.el.select('.card-footer').first();
2337 this.collapsableToggleEl = this.el.select('.roo-collapse-toggle');
2338 this.headerContainerEl = this.el.select('.roo-card-header-ctr').first();
2339 this.headerEl = this.el.select('.card-header',true).first();
2342 this.el.addClass('roo-card-rotated');
2343 this.fireEvent('rotate', this, true);
2347 getDragData : function(e)
2349 var target = this.getEl();
2351 //this.handleSelection(e);
2356 nodes: this.getEl(),
2361 dragData.ddel = target.dom ; // the div element
2362 Roo.log(target.getWidth( ));
2363 dragData.ddel.style.width = target.getWidth() + 'px';
2370 * Part of the Roo.dd.DropZone interface. If no target node is found, the
2371 * whole Element becomes the target, and this causes the drop gesture to append.
2373 getTargetFromEvent : function(e, dragged_card_el)
2375 var target = e.getTarget();
2376 while ((target !== null) && (target.parentNode != this.containerEl.dom)) {
2377 target = target.parentNode;
2388 //Roo.log([ 'target' , target ? target.id : '--nothing--']);
2389 // see if target is one of the 'cards'...
2392 //Roo.log(this.items.length);
2395 var last_card_n = 0;
2397 for (var i = 0;i< this.items.length;i++) {
2399 if (!this.items[i].el.hasClass('card')) {
2402 pos = this.getDropPoint(e, this.items[i].el.dom);
2404 cards_len = ret.cards.length;
2405 //Roo.log(this.items[i].el.dom.id);
2406 ret.cards.push(this.items[i]);
2408 if (ret.card_n < 0 && pos == 'above') {
2409 ret.position = cards_len > 0 ? 'below' : pos;
2410 ret.items_n = i > 0 ? i - 1 : 0;
2411 ret.card_n = cards_len > 0 ? cards_len - 1 : 0;
2412 ret.card = ret.cards[ret.card_n];
2415 if (!ret.cards.length) {
2417 ret.position = 'below';
2421 // could not find a card.. stick it at the end..
2422 if (ret.card_n < 0) {
2423 ret.card_n = last_card_n;
2424 ret.card = ret.cards[last_card_n];
2425 ret.items_n = this.items.indexOf(ret.cards[last_card_n]);
2426 ret.position = 'below';
2429 if (this.items[ret.items_n].el == dragged_card_el) {
2433 if (ret.position == 'below') {
2434 var card_after = ret.card_n+1 == ret.cards.length ? false : ret.cards[ret.card_n+1];
2436 if (card_after && card_after.el == dragged_card_el) {
2443 var card_before = ret.card_n > 0 ? ret.cards[ret.card_n-1] : false;
2445 if (card_before && card_before.el == dragged_card_el) {
2452 onNodeEnter : function(n, dd, e, data){
2455 onNodeOver : function(n, dd, e, data)
2458 var target_info = this.getTargetFromEvent(e,data.source.el);
2459 if (target_info === false) {
2460 this.dropPlaceHolder('hide');
2463 Roo.log(['getTargetFromEvent', target_info ]);
2466 this.dropPlaceHolder('show', target_info,data);
2470 onNodeOut : function(n, dd, e, data){
2471 this.dropPlaceHolder('hide');
2474 onNodeDrop : function(n, dd, e, data)
2477 // call drop - return false if
2479 // this could actually fail - if the Network drops..
2480 // we will ignore this at present..- client should probably reload
2481 // the whole set of cards if stuff like that fails.
2484 var info = this.getTargetFromEvent(e,data.source.el);
2485 if (info === false) {
2488 this.dropPlaceHolder('hide');
2494 this.acceptCard(data.source, info.position, info.card, info.items_n);
2498 firstChildCard : function()
2500 for (var i = 0;i< this.items.length;i++) {
2502 if (!this.items[i].el.hasClass('card')) {
2505 return this.items[i];
2507 return this.items.length ? this.items[this.items.length-1] : false; // don't try and put stuff after the cards...
2512 * - card.acceptCard(move_card, info.position, info.card, info.items_n);
2514 acceptCard : function(move_card, position, next_to_card )
2516 if (this.fireEvent("drop", this, move_card, position, next_to_card) === false) {
2520 var to_items_n = next_to_card ? this.items.indexOf(next_to_card) : 0;
2523 var dom = move_card.el.dom;
2524 dom.parentNode.removeChild(dom);
2525 dom.style.width = ''; // clear with - which is set by drag.
2527 if (next_to_card !== false && next_to_card !== true && next_to_card.el.dom.parentNode) {
2528 var cardel = next_to_card.el.dom;
2530 if (position == 'above' ) {
2531 cardel.parentNode.insertBefore(dom, cardel);
2532 } else if (cardel.nextSibling) {
2533 cardel.parentNode.insertBefore(dom,cardel.nextSibling);
2535 cardel.parentNode.append(dom);
2538 // card container???
2539 this.containerEl.dom.append(dom);
2542 //FIXME HANDLE card = true
2544 // add this to the correct place in items.
2548 // remove Card from items.
2550 var old_parent = move_card.parent();
2552 old_parent.items = old_parent.items.filter(function(e) { return e != move_card });
2554 if (this.items.length) {
2556 //Roo.log([info.items_n, info.position, this.items.length]);
2557 for (var i =0; i < this.items.length; i++) {
2558 if (i == to_items_n && position == 'above') {
2559 nitems.push(move_card);
2561 nitems.push(this.items[i]);
2562 if (i == to_items_n && position == 'below') {
2563 nitems.push(move_card);
2566 this.items = nitems;
2567 Roo.log(this.items);
2569 this.items.push(move_card);
2572 move_card.parentId = this.id;
2580 /** Decide whether to drop above or below a View node. */
2581 getDropPoint : function(e, n, dd)
2586 if (n == this.containerEl.dom) {
2589 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
2590 var c = t + (b - t) / 2;
2591 var y = Roo.lib.Event.getPageY(e);
2598 onToggleCollapse : function(e)
2600 if (this.collapsed) {
2601 this.el.select('.roo-collapse-toggle').removeClass('collapsed');
2602 this.collapsableEl.addClass('show');
2603 this.collapsed = false;
2606 this.el.select('.roo-collapse-toggle').addClass('collapsed');
2607 this.collapsableEl.removeClass('show');
2608 this.collapsed = true;
2613 onToggleRotate : function(e)
2615 this.collapsableEl.removeClass('show');
2616 this.footerEl.removeClass('d-none');
2617 this.el.removeClass('roo-card-rotated');
2618 this.el.removeClass('d-none');
2621 this.collapsableEl.addClass('show');
2622 this.rotated = false;
2623 this.fireEvent('rotate', this, this.rotated);
2626 this.el.addClass('roo-card-rotated');
2627 this.footerEl.addClass('d-none');
2628 this.el.select('.roo-collapsable').removeClass('show');
2630 this.rotated = true;
2631 this.fireEvent('rotate', this, this.rotated);
2635 dropPlaceHolder: function (action, info, data)
2637 if (this.dropEl === false) {
2638 this.dropEl = Roo.DomHelper.append(this.containerEl, {
2642 this.dropEl.removeClass(['d-none', 'd-block']);
2643 if (action == 'hide') {
2645 this.dropEl.addClass('d-none');
2648 // FIXME - info.card == true!!!
2649 this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
2651 if (info.card !== true) {
2652 var cardel = info.card.el.dom;
2654 if (info.position == 'above') {
2655 cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
2656 } else if (cardel.nextSibling) {
2657 cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
2659 cardel.parentNode.append(this.dropEl.dom);
2662 // card container???
2663 this.containerEl.dom.append(this.dropEl.dom);
2666 this.dropEl.addClass('d-block roo-card-dropzone');
2668 this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
2675 setHeaderText: function(html)
2677 this.headerContainerEl.dom.innerHTML = html;
2686 * Card header - holder for the card header elements.
2691 * @class Roo.bootstrap.CardHeader
2692 * @extends Roo.bootstrap.Element
2693 * Bootstrap CardHeader class
2695 * Create a new Card Header - that you can embed children into
2696 * @param {Object} config The config object
2699 Roo.bootstrap.CardHeader = function(config){
2700 Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
2703 Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element, {
2706 container_method : 'getCardHeader'
2719 * Card footer - holder for the card footer elements.
2724 * @class Roo.bootstrap.CardFooter
2725 * @extends Roo.bootstrap.Element
2726 * Bootstrap CardFooter class
2728 * Create a new Card Footer - that you can embed children into
2729 * @param {Object} config The config object
2732 Roo.bootstrap.CardFooter = function(config){
2733 Roo.bootstrap.CardFooter.superclass.constructor.call(this, config);
2736 Roo.extend(Roo.bootstrap.CardFooter, Roo.bootstrap.Element, {
2739 container_method : 'getCardFooter'
2752 * Card header - holder for the card header elements.
2757 * @class Roo.bootstrap.CardImageTop
2758 * @extends Roo.bootstrap.Element
2759 * Bootstrap CardImageTop class
2761 * Create a new Card Image Top container
2762 * @param {Object} config The config object
2765 Roo.bootstrap.CardImageTop = function(config){
2766 Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
2769 Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element, {
2772 container_method : 'getCardImageTop'
2790 * @class Roo.bootstrap.Img
2791 * @extends Roo.bootstrap.Component
2792 * Bootstrap Img class
2793 * @cfg {Boolean} imgResponsive false | true
2794 * @cfg {String} border rounded | circle | thumbnail
2795 * @cfg {String} src image source
2796 * @cfg {String} alt image alternative text
2797 * @cfg {String} href a tag href
2798 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
2799 * @cfg {String} xsUrl xs image source
2800 * @cfg {String} smUrl sm image source
2801 * @cfg {String} mdUrl md image source
2802 * @cfg {String} lgUrl lg image source
2805 * Create a new Input
2806 * @param {Object} config The config object
2809 Roo.bootstrap.Img = function(config){
2810 Roo.bootstrap.Img.superclass.constructor.call(this, config);
2816 * The img click event for the img.
2817 * @param {Roo.EventObject} e
2823 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
2825 imgResponsive: true,
2835 getAutoCreate : function()
2837 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2838 return this.createSingleImg();
2843 cls: 'roo-image-responsive-group',
2848 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
2850 if(!_this[size + 'Url']){
2856 cls: (_this.imgResponsive) ? 'img-responsive' : '',
2857 html: _this.html || cfg.html,
2858 src: _this[size + 'Url']
2861 img.cls += ' roo-image-responsive-' + size;
2863 var s = ['xs', 'sm', 'md', 'lg'];
2865 s.splice(s.indexOf(size), 1);
2867 Roo.each(s, function(ss){
2868 img.cls += ' hidden-' + ss;
2871 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
2872 cfg.cls += ' img-' + _this.border;
2876 cfg.alt = _this.alt;
2889 a.target = _this.target;
2893 cfg.cn.push((_this.href) ? a : img);
2900 createSingleImg : function()
2904 cls: (this.imgResponsive) ? 'img-responsive' : '',
2906 src : 'about:blank' // just incase src get's set to undefined?!?
2909 cfg.html = this.html || cfg.html;
2911 cfg.src = this.src || cfg.src;
2913 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
2914 cfg.cls += ' img-' + this.border;
2931 a.target = this.target;
2936 return (this.href) ? a : cfg;
2939 initEvents: function()
2942 this.el.on('click', this.onClick, this);
2947 onClick : function(e)
2949 Roo.log('img onclick');
2950 this.fireEvent('click', this, e);
2953 * Sets the url of the image - used to update it
2954 * @param {String} url the url of the image
2957 setSrc : function(url)
2961 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2962 this.el.dom.src = url;
2966 this.el.select('img', true).first().dom.src = url;
2982 * @class Roo.bootstrap.Link
2983 * @extends Roo.bootstrap.Component
2984 * Bootstrap Link Class
2985 * @cfg {String} alt image alternative text
2986 * @cfg {String} href a tag href
2987 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
2988 * @cfg {String} html the content of the link.
2989 * @cfg {String} anchor name for the anchor link
2990 * @cfg {String} fa - favicon
2992 * @cfg {Boolean} preventDefault (true | false) default false
2996 * Create a new Input
2997 * @param {Object} config The config object
3000 Roo.bootstrap.Link = function(config){
3001 Roo.bootstrap.Link.superclass.constructor.call(this, config);
3007 * The img click event for the img.
3008 * @param {Roo.EventObject} e
3014 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
3018 preventDefault: false,
3024 getAutoCreate : function()
3026 var html = this.html || '';
3028 if (this.fa !== false) {
3029 html = '<i class="fa fa-' + this.fa + '"></i>';
3034 // anchor's do not require html/href...
3035 if (this.anchor === false) {
3037 cfg.href = this.href || '#';
3039 cfg.name = this.anchor;
3040 if (this.html !== false || this.fa !== false) {
3043 if (this.href !== false) {
3044 cfg.href = this.href;
3048 if(this.alt !== false){
3053 if(this.target !== false) {
3054 cfg.target = this.target;
3060 initEvents: function() {
3062 if(!this.href || this.preventDefault){
3063 this.el.on('click', this.onClick, this);
3067 onClick : function(e)
3069 if(this.preventDefault){
3072 //Roo.log('img onclick');
3073 this.fireEvent('click', this, e);
3086 * @class Roo.bootstrap.Header
3087 * @extends Roo.bootstrap.Component
3088 * Bootstrap Header class
3089 * @cfg {String} html content of header
3090 * @cfg {Number} level (1|2|3|4|5|6) default 1
3093 * Create a new Header
3094 * @param {Object} config The config object
3098 Roo.bootstrap.Header = function(config){
3099 Roo.bootstrap.Header.superclass.constructor.call(this, config);
3102 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
3110 getAutoCreate : function(){
3115 tag: 'h' + (1 *this.level),
3116 html: this.html || ''
3128 * Ext JS Library 1.1.1
3129 * Copyright(c) 2006-2007, Ext JS, LLC.
3131 * Originally Released Under LGPL - original licence link has changed is not relivant.
3134 * <script type="text/javascript">
3138 * @class Roo.bootstrap.MenuMgr
3139 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
3142 Roo.bootstrap.MenuMgr = function(){
3143 var menus, active, groups = {}, attached = false, lastShow = new Date();
3145 // private - called when first menu is created
3148 active = new Roo.util.MixedCollection();
3149 Roo.get(document).addKeyListener(27, function(){
3150 if(active.length > 0){
3158 if(active && active.length > 0){
3159 var c = active.clone();
3169 if(active.length < 1){
3170 Roo.get(document).un("mouseup", onMouseDown);
3178 var last = active.last();
3179 lastShow = new Date();
3182 Roo.get(document).on("mouseup", onMouseDown);
3187 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
3188 m.parentMenu.activeChild = m;
3189 }else if(last && last.isVisible()){
3190 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
3195 function onBeforeHide(m){
3197 m.activeChild.hide();
3199 if(m.autoHideTimer){
3200 clearTimeout(m.autoHideTimer);
3201 delete m.autoHideTimer;
3206 function onBeforeShow(m){
3207 var pm = m.parentMenu;
3208 if(!pm && !m.allowOtherMenus){
3210 }else if(pm && pm.activeChild && active != m){
3211 pm.activeChild.hide();
3215 // private this should really trigger on mouseup..
3216 function onMouseDown(e){
3217 Roo.log("on Mouse Up");
3219 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
3220 Roo.log("MenuManager hideAll");
3229 function onBeforeCheck(mi, state){
3231 var g = groups[mi.group];
3232 for(var i = 0, l = g.length; i < l; i++){
3234 g[i].setChecked(false);
3243 * Hides all menus that are currently visible
3245 hideAll : function(){
3250 register : function(menu){
3254 menus[menu.id] = menu;
3255 menu.on("beforehide", onBeforeHide);
3256 menu.on("hide", onHide);
3257 menu.on("beforeshow", onBeforeShow);
3258 menu.on("show", onShow);
3260 if(g && menu.events["checkchange"]){
3264 groups[g].push(menu);
3265 menu.on("checkchange", onCheck);
3270 * Returns a {@link Roo.menu.Menu} object
3271 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
3272 * be used to generate and return a new Menu instance.
3274 get : function(menu){
3275 if(typeof menu == "string"){ // menu id
3277 }else if(menu.events){ // menu instance
3280 /*else if(typeof menu.length == 'number'){ // array of menu items?
3281 return new Roo.bootstrap.Menu({items:menu});
3282 }else{ // otherwise, must be a config
3283 return new Roo.bootstrap.Menu(menu);
3290 unregister : function(menu){
3291 delete menus[menu.id];
3292 menu.un("beforehide", onBeforeHide);
3293 menu.un("hide", onHide);
3294 menu.un("beforeshow", onBeforeShow);
3295 menu.un("show", onShow);
3297 if(g && menu.events["checkchange"]){
3298 groups[g].remove(menu);
3299 menu.un("checkchange", onCheck);
3304 registerCheckable : function(menuItem){
3305 var g = menuItem.group;
3310 groups[g].push(menuItem);
3311 menuItem.on("beforecheckchange", onBeforeCheck);
3316 unregisterCheckable : function(menuItem){
3317 var g = menuItem.group;
3319 groups[g].remove(menuItem);
3320 menuItem.un("beforecheckchange", onBeforeCheck);
3332 * @class Roo.bootstrap.Menu
3333 * @extends Roo.bootstrap.Component
3334 * Bootstrap Menu class - container for MenuItems
3335 * @cfg {String} type (dropdown|treeview|submenu) type of menu
3336 * @cfg {bool} hidden if the menu should be hidden when rendered.
3337 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
3338 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
3342 * @param {Object} config The config object
3346 Roo.bootstrap.Menu = function(config){
3347 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
3348 if (this.registerMenu && this.type != 'treeview') {
3349 Roo.bootstrap.MenuMgr.register(this);
3356 * Fires before this menu is displayed (return false to block)
3357 * @param {Roo.menu.Menu} this
3362 * Fires before this menu is hidden (return false to block)
3363 * @param {Roo.menu.Menu} this
3368 * Fires after this menu is displayed
3369 * @param {Roo.menu.Menu} this
3374 * Fires after this menu is hidden
3375 * @param {Roo.menu.Menu} this
3380 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
3381 * @param {Roo.menu.Menu} this
3382 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3383 * @param {Roo.EventObject} e
3388 * Fires when the mouse is hovering over this menu
3389 * @param {Roo.menu.Menu} this
3390 * @param {Roo.EventObject} e
3391 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3396 * Fires when the mouse exits this menu
3397 * @param {Roo.menu.Menu} this
3398 * @param {Roo.EventObject} e
3399 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3404 * Fires when a menu item contained in this menu is clicked
3405 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
3406 * @param {Roo.EventObject} e
3410 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
3413 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
3417 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
3420 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
3422 registerMenu : true,
3424 menuItems :false, // stores the menu items..
3434 getChildContainer : function() {
3438 getAutoCreate : function(){
3440 //if (['right'].indexOf(this.align)!==-1) {
3441 // cfg.cn[1].cls += ' pull-right'
3447 cls : 'dropdown-menu' ,
3448 style : 'z-index:1000'
3452 if (this.type === 'submenu') {
3453 cfg.cls = 'submenu active';
3455 if (this.type === 'treeview') {
3456 cfg.cls = 'treeview-menu';
3461 initEvents : function() {
3463 // Roo.log("ADD event");
3464 // Roo.log(this.triggerEl.dom);
3466 this.triggerEl.on('click', this.onTriggerClick, this);
3468 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
3471 if (this.triggerEl.hasClass('nav-item')) {
3472 // dropdown toggle on the 'a' in BS4?
3473 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
3475 this.triggerEl.addClass('dropdown-toggle');
3478 this.el.on('touchstart' , this.onTouch, this);
3480 this.el.on('click' , this.onClick, this);
3482 this.el.on("mouseover", this.onMouseOver, this);
3483 this.el.on("mouseout", this.onMouseOut, this);
3487 findTargetItem : function(e)
3489 var t = e.getTarget(".dropdown-menu-item", this.el, true);
3493 //Roo.log(t); Roo.log(t.id);
3495 //Roo.log(this.menuitems);
3496 return this.menuitems.get(t.id);
3498 //return this.items.get(t.menuItemId);
3504 onTouch : function(e)
3506 Roo.log("menu.onTouch");
3507 //e.stopEvent(); this make the user popdown broken
3511 onClick : function(e)
3513 Roo.log("menu.onClick");
3515 var t = this.findTargetItem(e);
3516 if(!t || t.isContainer){
3521 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
3522 if(t == this.activeItem && t.shouldDeactivate(e)){
3523 this.activeItem.deactivate();
3524 delete this.activeItem;
3528 this.setActiveItem(t, true);
3536 Roo.log('pass click event');
3540 this.fireEvent("click", this, t, e);
3544 if(!t.href.length || t.href == '#'){
3545 (function() { _this.hide(); }).defer(100);
3550 onMouseOver : function(e){
3551 var t = this.findTargetItem(e);
3554 // if(t.canActivate && !t.disabled){
3555 // this.setActiveItem(t, true);
3559 this.fireEvent("mouseover", this, e, t);
3561 isVisible : function(){
3562 return !this.hidden;
3564 onMouseOut : function(e){
3565 var t = this.findTargetItem(e);
3568 // if(t == this.activeItem && t.shouldDeactivate(e)){
3569 // this.activeItem.deactivate();
3570 // delete this.activeItem;
3573 this.fireEvent("mouseout", this, e, t);
3578 * Displays this menu relative to another element
3579 * @param {String/HTMLElement/Roo.Element} element The element to align to
3580 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
3581 * the element (defaults to this.defaultAlign)
3582 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3584 show : function(el, pos, parentMenu)
3586 if (false === this.fireEvent("beforeshow", this)) {
3587 Roo.log("show canceled");
3590 this.parentMenu = parentMenu;
3595 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
3598 * Displays this menu at a specific xy position
3599 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
3600 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3602 showAt : function(xy, parentMenu, /* private: */_e){
3603 this.parentMenu = parentMenu;
3608 this.fireEvent("beforeshow", this);
3609 //xy = this.el.adjustForConstraints(xy);
3613 this.hideMenuItems();
3614 this.hidden = false;
3615 this.triggerEl.addClass('open');
3616 this.el.addClass('show');
3618 // reassign x when hitting right
3619 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
3620 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
3623 // reassign y when hitting bottom
3624 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
3625 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
3628 // but the list may align on trigger left or trigger top... should it be a properity?
3630 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
3635 this.fireEvent("show", this);
3641 this.doFocus.defer(50, this);
3645 doFocus : function(){
3647 this.focusEl.focus();
3652 * Hides this menu and optionally all parent menus
3653 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
3655 hide : function(deep)
3657 if (false === this.fireEvent("beforehide", this)) {
3658 Roo.log("hide canceled");
3661 this.hideMenuItems();
3662 if(this.el && this.isVisible()){
3664 if(this.activeItem){
3665 this.activeItem.deactivate();
3666 this.activeItem = null;
3668 this.triggerEl.removeClass('open');;
3669 this.el.removeClass('show');
3671 this.fireEvent("hide", this);
3673 if(deep === true && this.parentMenu){
3674 this.parentMenu.hide(true);
3678 onTriggerClick : function(e)
3680 Roo.log('trigger click');
3682 var target = e.getTarget();
3684 Roo.log(target.nodeName.toLowerCase());
3686 if(target.nodeName.toLowerCase() === 'i'){
3692 onTriggerPress : function(e)
3694 Roo.log('trigger press');
3695 //Roo.log(e.getTarget());
3696 // Roo.log(this.triggerEl.dom);
3698 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
3699 var pel = Roo.get(e.getTarget());
3700 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
3701 Roo.log('is treeview or dropdown?');
3705 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
3709 if (this.isVisible()) {
3714 this.show(this.triggerEl, '?', false);
3717 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
3724 hideMenuItems : function()
3726 Roo.log("hide Menu Items");
3731 this.el.select('.open',true).each(function(aa) {
3733 aa.removeClass('open');
3737 addxtypeChild : function (tree, cntr) {
3738 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
3740 this.menuitems.add(comp);
3752 this.getEl().dom.innerHTML = '';
3753 this.menuitems.clear();
3767 * @class Roo.bootstrap.MenuItem
3768 * @extends Roo.bootstrap.Component
3769 * Bootstrap MenuItem class
3770 * @cfg {String} html the menu label
3771 * @cfg {String} href the link
3772 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
3773 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
3774 * @cfg {Boolean} active used on sidebars to highlight active itesm
3775 * @cfg {String} fa favicon to show on left of menu item.
3776 * @cfg {Roo.bootsrap.Menu} menu the child menu.
3780 * Create a new MenuItem
3781 * @param {Object} config The config object
3785 Roo.bootstrap.MenuItem = function(config){
3786 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
3791 * The raw click event for the entire grid.
3792 * @param {Roo.bootstrap.MenuItem} this
3793 * @param {Roo.EventObject} e
3799 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
3803 preventDefault: false,
3804 isContainer : false,
3808 getAutoCreate : function(){
3810 if(this.isContainer){
3813 cls: 'dropdown-menu-item '
3823 cls : 'dropdown-item',
3828 if (this.fa !== false) {
3831 cls : 'fa fa-' + this.fa
3840 cls: 'dropdown-menu-item',
3843 if (this.parent().type == 'treeview') {
3844 cfg.cls = 'treeview-menu';
3847 cfg.cls += ' active';
3852 anc.href = this.href || cfg.cn[0].href ;
3853 ctag.html = this.html || cfg.cn[0].html ;
3857 initEvents: function()
3859 if (this.parent().type == 'treeview') {
3860 this.el.select('a').on('click', this.onClick, this);
3864 this.menu.parentType = this.xtype;
3865 this.menu.triggerEl = this.el;
3866 this.menu = this.addxtype(Roo.apply({}, this.menu));
3870 onClick : function(e)
3872 Roo.log('item on click ');
3874 if(this.preventDefault){
3877 //this.parent().hideMenuItems();
3879 this.fireEvent('click', this, e);
3898 * @class Roo.bootstrap.MenuSeparator
3899 * @extends Roo.bootstrap.Component
3900 * Bootstrap MenuSeparator class
3903 * Create a new MenuItem
3904 * @param {Object} config The config object
3908 Roo.bootstrap.MenuSeparator = function(config){
3909 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
3912 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
3914 getAutoCreate : function(){
3933 * @class Roo.bootstrap.Modal
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap Modal class
3936 * @cfg {String} title Title of dialog
3937 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
3938 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
3939 * @cfg {Boolean} specificTitle default false
3940 * @cfg {Array} buttons Array of buttons or standard button set..
3941 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
3942 * @cfg {Boolean} animate default true
3943 * @cfg {Boolean} allow_close default true
3944 * @cfg {Boolean} fitwindow default false
3945 * @cfg {Number} width fixed width - usefull for chrome extension only really.
3946 * @cfg {Number} height fixed height - usefull for chrome extension only really.
3947 * @cfg {String} size (sm|lg|xl) default empty
3948 * @cfg {Number} max_width set the max width of modal
3949 * @cfg {Boolean} editableTitle can the title be edited
3954 * Create a new Modal Dialog
3955 * @param {Object} config The config object
3958 Roo.bootstrap.Modal = function(config){
3959 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
3964 * The raw btnclick event for the button
3965 * @param {Roo.EventObject} e
3970 * Fire when dialog resize
3971 * @param {Roo.bootstrap.Modal} this
3972 * @param {Roo.EventObject} e
3976 * @event titlechanged
3977 * Fire when the editable title has been changed
3978 * @param {Roo.bootstrap.Modal} this
3979 * @param {Roo.EventObject} value
3981 "titlechanged" : true
3984 this.buttons = this.buttons || [];
3987 this.tmpl = Roo.factory(this.tmpl);
3992 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
3994 title : 'test dialog',
4004 specificTitle: false,
4006 buttonPosition: 'right',
4028 editableTitle : false,
4030 onRender : function(ct, position)
4032 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
4035 var cfg = Roo.apply({}, this.getAutoCreate());
4038 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
4040 //if (!cfg.name.length) {
4044 cfg.cls += ' ' + this.cls;
4047 cfg.style = this.style;
4049 this.el = Roo.get(document.body).createChild(cfg, position);
4051 //var type = this.el.dom.type;
4054 if(this.tabIndex !== undefined){
4055 this.el.dom.setAttribute('tabIndex', this.tabIndex);
4058 this.dialogEl = this.el.select('.modal-dialog',true).first();
4059 this.bodyEl = this.el.select('.modal-body',true).first();
4060 this.closeEl = this.el.select('.modal-header .close', true).first();
4061 this.headerEl = this.el.select('.modal-header',true).first();
4062 this.titleEl = this.el.select('.modal-title',true).first();
4063 this.footerEl = this.el.select('.modal-footer',true).first();
4065 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
4067 //this.el.addClass("x-dlg-modal");
4069 if (this.buttons.length) {
4070 Roo.each(this.buttons, function(bb) {
4071 var b = Roo.apply({}, bb);
4072 b.xns = b.xns || Roo.bootstrap;
4073 b.xtype = b.xtype || 'Button';
4074 if (typeof(b.listeners) == 'undefined') {
4075 b.listeners = { click : this.onButtonClick.createDelegate(this) };
4078 var btn = Roo.factory(b);
4080 btn.render(this.getButtonContainer());
4084 // render the children.
4087 if(typeof(this.items) != 'undefined'){
4088 var items = this.items;
4091 for(var i =0;i < items.length;i++) {
4092 nitems.push(this.addxtype(Roo.apply({}, items[i])));
4096 this.items = nitems;
4098 // where are these used - they used to be body/close/footer
4102 //this.el.addClass([this.fieldClass, this.cls]);
4106 getAutoCreate : function()
4108 // we will default to modal-body-overflow - might need to remove or make optional later.
4110 cls : 'modal-body enable-modal-body-overflow ',
4111 html : this.html || ''
4116 cls : 'modal-title',
4120 if(this.specificTitle){ // WTF is this?
4125 if (this.allow_close && Roo.bootstrap.version == 3) {
4135 if (this.editableTitle) {
4137 cls: 'form-control roo-editable-title d-none',
4143 if (this.allow_close && Roo.bootstrap.version == 4) {
4153 if(this.size.length){
4154 size = 'modal-' + this.size;
4157 var footer = Roo.bootstrap.version == 3 ?
4159 cls : 'modal-footer',
4163 cls: 'btn-' + this.buttonPosition
4168 { // BS4 uses mr-auto on left buttons....
4169 cls : 'modal-footer'
4180 cls: "modal-dialog " + size,
4183 cls : "modal-content",
4186 cls : 'modal-header',
4201 modal.cls += ' fade';
4207 getChildContainer : function() {
4212 getButtonContainer : function() {
4214 return Roo.bootstrap.version == 4 ?
4215 this.el.select('.modal-footer',true).first()
4216 : this.el.select('.modal-footer div',true).first();
4219 initEvents : function()
4221 if (this.allow_close) {
4222 this.closeEl.on('click', this.hide, this);
4224 Roo.EventManager.onWindowResize(this.resize, this, true);
4225 if (this.editableTitle) {
4226 this.headerEditEl = this.headerEl.select('.form-control',true).first();
4227 this.headerEl.on('click', function() { this.toggleHeaderInput(true) } , this);
4228 this.headerEditEl.on('keyup', function(e) {
4229 if([ e.RETURN , e.TAB , e.ESC ].indexOf(e.keyCode) > -1) {
4230 this.toggleHeaderInput(false)
4233 this.headerEditEl.on('blur', function(e) {
4234 this.toggleHeaderInput(false)
4243 this.maskEl.setSize(
4244 Roo.lib.Dom.getViewWidth(true),
4245 Roo.lib.Dom.getViewHeight(true)
4248 if (this.fitwindow) {
4252 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
4253 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
4258 if(this.max_width !== 0) {
4260 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
4263 this.setSize(w, this.height);
4267 if(this.max_height) {
4268 this.setSize(w,Math.min(
4270 Roo.lib.Dom.getViewportHeight(true) - 60
4276 if(!this.fit_content) {
4277 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
4281 this.setSize(w, Math.min(
4283 this.headerEl.getHeight() +
4284 this.footerEl.getHeight() +
4285 this.getChildHeight(this.bodyEl.dom.childNodes),
4286 Roo.lib.Dom.getViewportHeight(true) - 60)
4292 setSize : function(w,h)
4303 if (!this.rendered) {
4306 this.toggleHeaderInput(false);
4307 //this.el.setStyle('display', 'block');
4308 this.el.removeClass('hideing');
4309 this.el.dom.style.display='block';
4311 Roo.get(document.body).addClass('modal-open');
4313 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
4316 this.el.addClass('show');
4317 this.el.addClass('in');
4320 this.el.addClass('show');
4321 this.el.addClass('in');
4324 // not sure how we can show data in here..
4326 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
4329 Roo.get(document.body).addClass("x-body-masked");
4331 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
4332 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4333 this.maskEl.dom.style.display = 'block';
4334 this.maskEl.addClass('show');
4339 this.fireEvent('show', this);
4341 // set zindex here - otherwise it appears to be ignored...
4342 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4345 this.items.forEach( function(e) {
4346 e.layout ? e.layout() : false;
4354 if(this.fireEvent("beforehide", this) !== false){
4356 this.maskEl.removeClass('show');
4358 this.maskEl.dom.style.display = '';
4359 Roo.get(document.body).removeClass("x-body-masked");
4360 this.el.removeClass('in');
4361 this.el.select('.modal-dialog', true).first().setStyle('transform','');
4363 if(this.animate){ // why
4364 this.el.addClass('hideing');
4365 this.el.removeClass('show');
4367 if (!this.el.hasClass('hideing')) {
4368 return; // it's been shown again...
4371 this.el.dom.style.display='';
4373 Roo.get(document.body).removeClass('modal-open');
4374 this.el.removeClass('hideing');
4378 this.el.removeClass('show');
4379 this.el.dom.style.display='';
4380 Roo.get(document.body).removeClass('modal-open');
4383 this.fireEvent('hide', this);
4386 isVisible : function()
4389 return this.el.hasClass('show') && !this.el.hasClass('hideing');
4393 addButton : function(str, cb)
4397 var b = Roo.apply({}, { html : str } );
4398 b.xns = b.xns || Roo.bootstrap;
4399 b.xtype = b.xtype || 'Button';
4400 if (typeof(b.listeners) == 'undefined') {
4401 b.listeners = { click : cb.createDelegate(this) };
4404 var btn = Roo.factory(b);
4406 btn.render(this.getButtonContainer());
4412 setDefaultButton : function(btn)
4414 //this.el.select('.modal-footer').()
4417 resizeTo: function(w,h)
4419 this.dialogEl.setWidth(w);
4421 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
4423 this.bodyEl.setHeight(h - diff);
4425 this.fireEvent('resize', this);
4428 setContentSize : function(w, h)
4432 onButtonClick: function(btn,e)
4435 this.fireEvent('btnclick', btn.name, e);
4438 * Set the title of the Dialog
4439 * @param {String} str new Title
4441 setTitle: function(str) {
4442 this.titleEl.dom.innerHTML = str;
4446 * Set the body of the Dialog
4447 * @param {String} str new Title
4449 setBody: function(str) {
4450 this.bodyEl.dom.innerHTML = str;
4453 * Set the body of the Dialog using the template
4454 * @param {Obj} data - apply this data to the template and replace the body contents.
4456 applyBody: function(obj)
4459 Roo.log("Error - using apply Body without a template");
4462 this.tmpl.overwrite(this.bodyEl, obj);
4465 getChildHeight : function(child_nodes)
4469 child_nodes.length == 0
4474 var child_height = 0;
4476 for(var i = 0; i < child_nodes.length; i++) {
4479 * for modal with tabs...
4480 if(child_nodes[i].classList.contains('roo-layout-panel')) {
4482 var layout_childs = child_nodes[i].childNodes;
4484 for(var j = 0; j < layout_childs.length; j++) {
4486 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
4488 var layout_body_childs = layout_childs[j].childNodes;
4490 for(var k = 0; k < layout_body_childs.length; k++) {
4492 if(layout_body_childs[k].classList.contains('navbar')) {
4493 child_height += layout_body_childs[k].offsetHeight;
4497 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
4499 var layout_body_tab_childs = layout_body_childs[k].childNodes;
4501 for(var m = 0; m < layout_body_tab_childs.length; m++) {
4503 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
4504 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
4519 child_height += child_nodes[i].offsetHeight;
4520 // Roo.log(child_nodes[i].offsetHeight);
4523 return child_height;
4525 toggleHeaderInput : function(is_edit)
4527 if (!this.editableTitle) {
4528 return; // not editable.
4530 if (is_edit && this.is_header_editing) {
4531 return; // already editing..
4535 this.headerEditEl.dom.value = this.title;
4536 this.headerEditEl.removeClass('d-none');
4537 this.headerEditEl.dom.focus();
4538 this.titleEl.addClass('d-none');
4540 this.is_header_editing = true;
4543 // flip back to not editing.
4544 this.title = this.headerEditEl.dom.value;
4545 this.headerEditEl.addClass('d-none');
4546 this.titleEl.removeClass('d-none');
4547 this.titleEl.dom.innerHTML = String.format('{0}', this.title);
4548 this.is_header_editing = false;
4549 this.fireEvent('titlechanged', this, this.title);
4558 Roo.apply(Roo.bootstrap.Modal, {
4560 * Button config that displays a single OK button
4569 * Button config that displays Yes and No buttons
4585 * Button config that displays OK and Cancel buttons
4600 * Button config that displays Yes, No and Cancel buttons
4625 * messagebox - can be used as a replace
4629 * @class Roo.MessageBox
4630 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
4634 Roo.Msg.alert('Status', 'Changes saved successfully.');
4636 // Prompt for user data:
4637 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
4639 // process text value...
4643 // Show a dialog using config options:
4645 title:'Save Changes?',
4646 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
4647 buttons: Roo.Msg.YESNOCANCEL,
4654 Roo.bootstrap.MessageBox = function(){
4655 var dlg, opt, mask, waitTimer;
4656 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4657 var buttons, activeTextEl, bwidth;
4661 var handleButton = function(button){
4663 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
4667 var handleHide = function(){
4669 dlg.el.removeClass(opt.cls);
4672 // Roo.TaskMgr.stop(waitTimer);
4673 // waitTimer = null;
4678 var updateButtons = function(b){
4681 buttons["ok"].hide();
4682 buttons["cancel"].hide();
4683 buttons["yes"].hide();
4684 buttons["no"].hide();
4685 dlg.footerEl.hide();
4689 dlg.footerEl.show();
4690 for(var k in buttons){
4691 if(typeof buttons[k] != "function"){
4694 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
4695 width += buttons[k].el.getWidth()+15;
4705 var handleEsc = function(d, k, e){
4706 if(opt && opt.closable !== false){
4716 * Returns a reference to the underlying {@link Roo.BasicDialog} element
4717 * @return {Roo.BasicDialog} The BasicDialog element
4719 getDialog : function(){
4721 dlg = new Roo.bootstrap.Modal( {
4724 //constraintoviewport:false,
4726 //collapsible : false,
4731 //buttonAlign:"center",
4732 closeClick : function(){
4733 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
4736 handleButton("cancel");
4741 dlg.on("hide", handleHide);
4743 //dlg.addKeyListener(27, handleEsc);
4745 this.buttons = buttons;
4746 var bt = this.buttonText;
4747 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
4748 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
4749 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
4750 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
4752 bodyEl = dlg.bodyEl.createChild({
4754 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
4755 '<textarea class="roo-mb-textarea"></textarea>' +
4756 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
4758 msgEl = bodyEl.dom.firstChild;
4759 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
4760 textboxEl.enableDisplayMode();
4761 textboxEl.addKeyListener([10,13], function(){
4762 if(dlg.isVisible() && opt && opt.buttons){
4765 }else if(opt.buttons.yes){
4766 handleButton("yes");
4770 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
4771 textareaEl.enableDisplayMode();
4772 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
4773 progressEl.enableDisplayMode();
4775 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
4776 var pf = progressEl.dom.firstChild;
4778 pp = Roo.get(pf.firstChild);
4779 pp.setHeight(pf.offsetHeight);
4787 * Updates the message box body text
4788 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
4789 * the XHTML-compliant non-breaking space character '&#160;')
4790 * @return {Roo.MessageBox} This message box
4792 updateText : function(text)
4794 if(!dlg.isVisible() && !opt.width){
4795 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
4796 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
4798 msgEl.innerHTML = text || ' ';
4800 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
4801 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
4803 Math.min(opt.width || cw , this.maxWidth),
4804 Math.max(opt.minWidth || this.minWidth, bwidth)
4807 activeTextEl.setWidth(w);
4809 if(dlg.isVisible()){
4810 dlg.fixedcenter = false;
4812 // to big, make it scroll. = But as usual stupid IE does not support
4815 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
4816 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
4817 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
4819 bodyEl.dom.style.height = '';
4820 bodyEl.dom.style.overflowY = '';
4823 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
4825 bodyEl.dom.style.overflowX = '';
4828 dlg.setContentSize(w, bodyEl.getHeight());
4829 if(dlg.isVisible()){
4830 dlg.fixedcenter = true;
4836 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
4837 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
4838 * @param {Number} value Any number between 0 and 1 (e.g., .5)
4839 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
4840 * @return {Roo.MessageBox} This message box
4842 updateProgress : function(value, text){
4844 this.updateText(text);
4847 if (pp) { // weird bug on my firefox - for some reason this is not defined
4848 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
4849 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
4855 * Returns true if the message box is currently displayed
4856 * @return {Boolean} True if the message box is visible, else false
4858 isVisible : function(){
4859 return dlg && dlg.isVisible();
4863 * Hides the message box if it is displayed
4866 if(this.isVisible()){
4872 * Displays a new message box, or reinitializes an existing message box, based on the config options
4873 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
4874 * The following config object properties are supported:
4876 Property Type Description
4877 ---------- --------------- ------------------------------------------------------------------------------------
4878 animEl String/Element An id or Element from which the message box should animate as it opens and
4879 closes (defaults to undefined)
4880 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
4881 cancel:'Bar'}), or false to not show any buttons (defaults to false)
4882 closable Boolean False to hide the top-right close button (defaults to true). Note that
4883 progress and wait dialogs will ignore this property and always hide the
4884 close button as they can only be closed programmatically.
4885 cls String A custom CSS class to apply to the message box element
4886 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
4887 displayed (defaults to 75)
4888 fn Function A callback function to execute after closing the dialog. The arguments to the
4889 function will be btn (the name of the button that was clicked, if applicable,
4890 e.g. "ok"), and text (the value of the active text field, if applicable).
4891 Progress and wait dialogs will ignore this option since they do not respond to
4892 user actions and can only be closed programmatically, so any required function
4893 should be called by the same code after it closes the dialog.
4894 icon String A CSS class that provides a background image to be used as an icon for
4895 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
4896 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
4897 minWidth Number The minimum width in pixels of the message box (defaults to 100)
4898 modal Boolean False to allow user interaction with the page while the message box is
4899 displayed (defaults to true)
4900 msg String A string that will replace the existing message box body text (defaults
4901 to the XHTML-compliant non-breaking space character ' ')
4902 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
4903 progress Boolean True to display a progress bar (defaults to false)
4904 progressText String The text to display inside the progress bar if progress = true (defaults to '')
4905 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
4906 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
4907 title String The title text
4908 value String The string value to set into the active textbox element if displayed
4909 wait Boolean True to display a progress bar (defaults to false)
4910 width Number The width of the dialog in pixels
4917 msg: 'Please enter your address:',
4919 buttons: Roo.MessageBox.OKCANCEL,
4922 animEl: 'addAddressBtn'
4925 * @param {Object} config Configuration options
4926 * @return {Roo.MessageBox} This message box
4928 show : function(options)
4931 // this causes nightmares if you show one dialog after another
4932 // especially on callbacks..
4934 if(this.isVisible()){
4937 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
4938 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
4939 Roo.log("New Dialog Message:" + options.msg )
4940 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
4941 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
4944 var d = this.getDialog();
4946 d.setTitle(opt.title || " ");
4947 d.closeEl.setDisplayed(opt.closable !== false);
4948 activeTextEl = textboxEl;
4949 opt.prompt = opt.prompt || (opt.multiline ? true : false);
4954 textareaEl.setHeight(typeof opt.multiline == "number" ?
4955 opt.multiline : this.defaultTextHeight);
4956 activeTextEl = textareaEl;
4965 progressEl.setDisplayed(opt.progress === true);
4967 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
4969 this.updateProgress(0);
4970 activeTextEl.dom.value = opt.value || "";
4972 dlg.setDefaultButton(activeTextEl);
4974 var bs = opt.buttons;
4978 }else if(bs && bs.yes){
4979 db = buttons["yes"];
4981 dlg.setDefaultButton(db);
4983 bwidth = updateButtons(opt.buttons);
4984 this.updateText(opt.msg);
4986 d.el.addClass(opt.cls);
4988 d.proxyDrag = opt.proxyDrag === true;
4989 d.modal = opt.modal !== false;
4990 d.mask = opt.modal !== false ? mask : false;
4992 // force it to the end of the z-index stack so it gets a cursor in FF
4993 document.body.appendChild(dlg.el.dom);
4994 d.animateTarget = null;
4995 d.show(options.animEl);
5001 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
5002 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
5003 * and closing the message box when the process is complete.
5004 * @param {String} title The title bar text
5005 * @param {String} msg The message box body text
5006 * @return {Roo.MessageBox} This message box
5008 progress : function(title, msg){
5015 minWidth: this.minProgressWidth,
5022 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
5023 * If a callback function is passed it will be called after the user clicks the button, and the
5024 * id of the button that was clicked will be passed as the only parameter to the callback
5025 * (could also be the top-right close button).
5026 * @param {String} title The title bar text
5027 * @param {String} msg The message box body text
5028 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5029 * @param {Object} scope (optional) The scope of the callback function
5030 * @return {Roo.MessageBox} This message box
5032 alert : function(title, msg, fn, scope)
5047 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
5048 * interaction while waiting for a long-running process to complete that does not have defined intervals.
5049 * You are responsible for closing the message box when the process is complete.
5050 * @param {String} msg The message box body text
5051 * @param {String} title (optional) The title bar text
5052 * @return {Roo.MessageBox} This message box
5054 wait : function(msg, title){
5065 waitTimer = Roo.TaskMgr.start({
5067 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
5075 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
5076 * If a callback function is passed it will be called after the user clicks either button, and the id of the
5077 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
5078 * @param {String} title The title bar text
5079 * @param {String} msg The message box body text
5080 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5081 * @param {Object} scope (optional) The scope of the callback function
5082 * @return {Roo.MessageBox} This message box
5084 confirm : function(title, msg, fn, scope){
5088 buttons: this.YESNO,
5097 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
5098 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
5099 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
5100 * (could also be the top-right close button) and the text that was entered will be passed as the two
5101 * parameters to the callback.
5102 * @param {String} title The title bar text
5103 * @param {String} msg The message box body text
5104 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5105 * @param {Object} scope (optional) The scope of the callback function
5106 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
5107 * property, or the height in pixels to create the textbox (defaults to false / single-line)
5108 * @return {Roo.MessageBox} This message box
5110 prompt : function(title, msg, fn, scope, multiline){
5114 buttons: this.OKCANCEL,
5119 multiline: multiline,
5126 * Button config that displays a single OK button
5131 * Button config that displays Yes and No buttons
5134 YESNO : {yes:true, no:true},
5136 * Button config that displays OK and Cancel buttons
5139 OKCANCEL : {ok:true, cancel:true},
5141 * Button config that displays Yes, No and Cancel buttons
5144 YESNOCANCEL : {yes:true, no:true, cancel:true},
5147 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
5150 defaultTextHeight : 75,
5152 * The maximum width in pixels of the message box (defaults to 600)
5157 * The minimum width in pixels of the message box (defaults to 100)
5162 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
5163 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
5166 minProgressWidth : 250,
5168 * An object containing the default button text strings that can be overriden for localized language support.
5169 * Supported properties are: ok, cancel, yes and no.
5170 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
5183 * Shorthand for {@link Roo.MessageBox}
5185 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
5186 Roo.Msg = Roo.Msg || Roo.MessageBox;
5195 * @class Roo.bootstrap.Navbar
5196 * @extends Roo.bootstrap.Component
5197 * Bootstrap Navbar class
5200 * Create a new Navbar
5201 * @param {Object} config The config object
5205 Roo.bootstrap.Navbar = function(config){
5206 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
5210 * @event beforetoggle
5211 * Fire before toggle the menu
5212 * @param {Roo.EventObject} e
5214 "beforetoggle" : true
5218 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
5227 getAutoCreate : function(){
5230 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
5234 initEvents :function ()
5236 //Roo.log(this.el.select('.navbar-toggle',true));
5237 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
5244 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
5246 var size = this.el.getSize();
5247 this.maskEl.setSize(size.width, size.height);
5248 this.maskEl.enableDisplayMode("block");
5257 getChildContainer : function()
5259 if (this.el && this.el.select('.collapse').getCount()) {
5260 return this.el.select('.collapse',true).first();
5275 onToggle : function()
5278 if(this.fireEvent('beforetoggle', this) === false){
5281 var ce = this.el.select('.navbar-collapse',true).first();
5283 if (!ce.hasClass('show')) {
5293 * Expand the navbar pulldown
5295 expand : function ()
5298 var ce = this.el.select('.navbar-collapse',true).first();
5299 if (ce.hasClass('collapsing')) {
5302 ce.dom.style.height = '';
5304 ce.addClass('in'); // old...
5305 ce.removeClass('collapse');
5306 ce.addClass('show');
5307 var h = ce.getHeight();
5309 ce.removeClass('show');
5310 // at this point we should be able to see it..
5311 ce.addClass('collapsing');
5313 ce.setHeight(0); // resize it ...
5314 ce.on('transitionend', function() {
5315 //Roo.log('done transition');
5316 ce.removeClass('collapsing');
5317 ce.addClass('show');
5318 ce.removeClass('collapse');
5320 ce.dom.style.height = '';
5321 }, this, { single: true} );
5323 ce.dom.scrollTop = 0;
5326 * Collapse the navbar pulldown
5328 collapse : function()
5330 var ce = this.el.select('.navbar-collapse',true).first();
5332 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
5333 // it's collapsed or collapsing..
5336 ce.removeClass('in'); // old...
5337 ce.setHeight(ce.getHeight());
5338 ce.removeClass('show');
5339 ce.addClass('collapsing');
5341 ce.on('transitionend', function() {
5342 ce.dom.style.height = '';
5343 ce.removeClass('collapsing');
5344 ce.addClass('collapse');
5345 }, this, { single: true} );
5365 * @class Roo.bootstrap.NavSimplebar
5366 * @extends Roo.bootstrap.Navbar
5367 * Bootstrap Sidebar class
5369 * @cfg {Boolean} inverse is inverted color
5371 * @cfg {String} type (nav | pills | tabs)
5372 * @cfg {Boolean} arrangement stacked | justified
5373 * @cfg {String} align (left | right) alignment
5375 * @cfg {Boolean} main (true|false) main nav bar? default false
5376 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
5378 * @cfg {String} tag (header|footer|nav|div) default is nav
5380 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
5384 * Create a new Sidebar
5385 * @param {Object} config The config object
5389 Roo.bootstrap.NavSimplebar = function(config){
5390 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
5393 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
5409 getAutoCreate : function(){
5413 tag : this.tag || 'div',
5414 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
5416 if (['light','white'].indexOf(this.weight) > -1) {
5417 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5419 cfg.cls += ' bg-' + this.weight;
5422 cfg.cls += ' navbar-inverse';
5426 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
5428 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
5437 cls: 'nav nav-' + this.xtype,
5443 this.type = this.type || 'nav';
5444 if (['tabs','pills'].indexOf(this.type) != -1) {
5445 cfg.cn[0].cls += ' nav-' + this.type
5449 if (this.type!=='nav') {
5450 Roo.log('nav type must be nav/tabs/pills')
5452 cfg.cn[0].cls += ' navbar-nav'
5458 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
5459 cfg.cn[0].cls += ' nav-' + this.arrangement;
5463 if (this.align === 'right') {
5464 cfg.cn[0].cls += ' navbar-right';
5489 * navbar-expand-md fixed-top
5493 * @class Roo.bootstrap.NavHeaderbar
5494 * @extends Roo.bootstrap.NavSimplebar
5495 * Bootstrap Sidebar class
5497 * @cfg {String} brand what is brand
5498 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
5499 * @cfg {String} brand_href href of the brand
5500 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
5501 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
5502 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
5503 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
5506 * Create a new Sidebar
5507 * @param {Object} config The config object
5511 Roo.bootstrap.NavHeaderbar = function(config){
5512 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
5516 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
5523 desktopCenter : false,
5526 getAutoCreate : function(){
5529 tag: this.nav || 'nav',
5530 cls: 'navbar navbar-expand-md',
5536 if (this.desktopCenter) {
5537 cn.push({cls : 'container', cn : []});
5545 cls: 'navbar-toggle navbar-toggler',
5546 'data-toggle': 'collapse',
5551 html: 'Toggle navigation'
5555 cls: 'icon-bar navbar-toggler-icon'
5568 cn.push( Roo.bootstrap.version == 4 ? btn : {
5570 cls: 'navbar-header',
5579 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
5583 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
5585 if (['light','white'].indexOf(this.weight) > -1) {
5586 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5588 cfg.cls += ' bg-' + this.weight;
5591 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
5592 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
5594 // tag can override this..
5596 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
5599 if (this.brand !== '') {
5600 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
5601 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
5603 href: this.brand_href ? this.brand_href : '#',
5604 cls: 'navbar-brand',
5612 cfg.cls += ' main-nav';
5620 getHeaderChildContainer : function()
5622 if (this.srButton && this.el.select('.navbar-header').getCount()) {
5623 return this.el.select('.navbar-header',true).first();
5626 return this.getChildContainer();
5629 getChildContainer : function()
5632 return this.el.select('.roo-navbar-collapse',true).first();
5637 initEvents : function()
5639 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
5641 if (this.autohide) {
5646 Roo.get(document).on('scroll',function(e) {
5647 var ns = Roo.get(document).getScroll().top;
5648 var os = prevScroll;
5652 ft.removeClass('slideDown');
5653 ft.addClass('slideUp');
5656 ft.removeClass('slideUp');
5657 ft.addClass('slideDown');
5678 * @class Roo.bootstrap.NavSidebar
5679 * @extends Roo.bootstrap.Navbar
5680 * Bootstrap Sidebar class
5683 * Create a new Sidebar
5684 * @param {Object} config The config object
5688 Roo.bootstrap.NavSidebar = function(config){
5689 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
5692 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
5694 sidebar : true, // used by Navbar Item and NavbarGroup at present...
5696 getAutoCreate : function(){
5701 cls: 'sidebar sidebar-nav'
5723 * @class Roo.bootstrap.NavGroup
5724 * @extends Roo.bootstrap.Component
5725 * Bootstrap NavGroup class
5726 * @cfg {String} align (left|right)
5727 * @cfg {Boolean} inverse
5728 * @cfg {String} type (nav|pills|tab) default nav
5729 * @cfg {String} navId - reference Id for navbar.
5733 * Create a new nav group
5734 * @param {Object} config The config object
5737 Roo.bootstrap.NavGroup = function(config){
5738 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
5741 Roo.bootstrap.NavGroup.register(this);
5745 * Fires when the active item changes
5746 * @param {Roo.bootstrap.NavGroup} this
5747 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
5748 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
5755 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
5766 getAutoCreate : function()
5768 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
5774 if (Roo.bootstrap.version == 4) {
5775 if (['tabs','pills'].indexOf(this.type) != -1) {
5776 cfg.cls += ' nav-' + this.type;
5778 // trying to remove so header bar can right align top?
5779 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
5780 // do not use on header bar...
5781 cfg.cls += ' navbar-nav';
5786 if (['tabs','pills'].indexOf(this.type) != -1) {
5787 cfg.cls += ' nav-' + this.type
5789 if (this.type !== 'nav') {
5790 Roo.log('nav type must be nav/tabs/pills')
5792 cfg.cls += ' navbar-nav'
5796 if (this.parent() && this.parent().sidebar) {
5799 cls: 'dashboard-menu sidebar-menu'
5805 if (this.form === true) {
5808 cls: 'navbar-form form-inline'
5810 //nav navbar-right ml-md-auto
5811 if (this.align === 'right') {
5812 cfg.cls += ' navbar-right ml-md-auto';
5814 cfg.cls += ' navbar-left';
5818 if (this.align === 'right') {
5819 cfg.cls += ' navbar-right ml-md-auto';
5821 cfg.cls += ' mr-auto';
5825 cfg.cls += ' navbar-inverse';
5833 * sets the active Navigation item
5834 * @param {Roo.bootstrap.NavItem} the new current navitem
5836 setActiveItem : function(item)
5839 Roo.each(this.navItems, function(v){
5844 v.setActive(false, true);
5851 item.setActive(true, true);
5852 this.fireEvent('changed', this, item, prev);
5857 * gets the active Navigation item
5858 * @return {Roo.bootstrap.NavItem} the current navitem
5860 getActive : function()
5864 Roo.each(this.navItems, function(v){
5875 indexOfNav : function()
5879 Roo.each(this.navItems, function(v,i){
5890 * adds a Navigation item
5891 * @param {Roo.bootstrap.NavItem} the navitem to add
5893 addItem : function(cfg)
5895 if (this.form && Roo.bootstrap.version == 4) {
5898 var cn = new Roo.bootstrap.NavItem(cfg);
5900 cn.parentId = this.id;
5901 cn.onRender(this.el, null);
5905 * register a Navigation item
5906 * @param {Roo.bootstrap.NavItem} the navitem to add
5908 register : function(item)
5910 this.navItems.push( item);
5911 item.navId = this.navId;
5916 * clear all the Navigation item
5919 clearAll : function()
5922 this.el.dom.innerHTML = '';
5925 getNavItem: function(tabId)
5928 Roo.each(this.navItems, function(e) {
5929 if (e.tabId == tabId) {
5939 setActiveNext : function()
5941 var i = this.indexOfNav(this.getActive());
5942 if (i > this.navItems.length) {
5945 this.setActiveItem(this.navItems[i+1]);
5947 setActivePrev : function()
5949 var i = this.indexOfNav(this.getActive());
5953 this.setActiveItem(this.navItems[i-1]);
5955 clearWasActive : function(except) {
5956 Roo.each(this.navItems, function(e) {
5957 if (e.tabId != except.tabId && e.was_active) {
5958 e.was_active = false;
5965 getWasActive : function ()
5968 Roo.each(this.navItems, function(e) {
5983 Roo.apply(Roo.bootstrap.NavGroup, {
5987 * register a Navigation Group
5988 * @param {Roo.bootstrap.NavGroup} the navgroup to add
5990 register : function(navgrp)
5992 this.groups[navgrp.navId] = navgrp;
5996 * fetch a Navigation Group based on the navigation ID
5997 * @param {string} the navgroup to add
5998 * @returns {Roo.bootstrap.NavGroup} the navgroup
6000 get: function(navId) {
6001 if (typeof(this.groups[navId]) == 'undefined') {
6003 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
6005 return this.groups[navId] ;
6020 * @class Roo.bootstrap.NavItem
6021 * @extends Roo.bootstrap.Component
6022 * Bootstrap Navbar.NavItem class
6023 * @cfg {String} href link to
6024 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
6026 * @cfg {String} html content of button
6027 * @cfg {String} badge text inside badge
6028 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
6029 * @cfg {String} glyphicon DEPRICATED - use fa
6030 * @cfg {String} icon DEPRICATED - use fa
6031 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
6032 * @cfg {Boolean} active Is item active
6033 * @cfg {Boolean} disabled Is item disabled
6035 * @cfg {Boolean} preventDefault (true | false) default false
6036 * @cfg {String} tabId the tab that this item activates.
6037 * @cfg {String} tagtype (a|span) render as a href or span?
6038 * @cfg {Boolean} animateRef (true|false) link to element default false
6041 * Create a new Navbar Item
6042 * @param {Object} config The config object
6044 Roo.bootstrap.NavItem = function(config){
6045 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
6050 * The raw click event for the entire grid.
6051 * @param {Roo.EventObject} e
6056 * Fires when the active item active state changes
6057 * @param {Roo.bootstrap.NavItem} this
6058 * @param {boolean} state the new state
6064 * Fires when scroll to element
6065 * @param {Roo.bootstrap.NavItem} this
6066 * @param {Object} options
6067 * @param {Roo.EventObject} e
6075 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
6084 preventDefault : false,
6092 button_outline : false,
6096 getAutoCreate : function(){
6104 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
6106 if (this.disabled) {
6107 cfg.cls += ' disabled';
6111 if (this.button_weight.length) {
6112 cfg.tag = this.href ? 'a' : 'button';
6113 cfg.html = this.html || '';
6114 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
6116 cfg.href = this.href;
6119 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
6122 // menu .. should add dropdown-menu class - so no need for carat..
6124 if (this.badge !== '') {
6126 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
6131 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
6135 href : this.href || "#",
6136 html: this.html || ''
6139 if (this.tagtype == 'a') {
6140 cfg.cn[0].cls = 'nav-link';
6143 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
6146 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
6148 if(this.glyphicon) {
6149 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
6154 cfg.cn[0].html += " <span class='caret'></span>";
6158 if (this.badge !== '') {
6160 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
6168 onRender : function(ct, position)
6170 // Roo.log("Call onRender: " + this.xtype);
6171 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
6175 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
6176 this.navLink = this.el.select('.nav-link',true).first();
6181 initEvents: function()
6183 if (typeof (this.menu) != 'undefined') {
6184 this.menu.parentType = this.xtype;
6185 this.menu.triggerEl = this.el;
6186 this.menu = this.addxtype(Roo.apply({}, this.menu));
6189 this.el.select('a',true).on('click', this.onClick, this);
6191 if(this.tagtype == 'span'){
6192 this.el.select('span',true).on('click', this.onClick, this);
6195 // at this point parent should be available..
6196 this.parent().register(this);
6199 onClick : function(e)
6201 if (e.getTarget('.dropdown-menu-item')) {
6202 // did you click on a menu itemm.... - then don't trigger onclick..
6207 this.preventDefault ||
6210 Roo.log("NavItem - prevent Default?");
6214 if (this.disabled) {
6218 var tg = Roo.bootstrap.TabGroup.get(this.navId);
6219 if (tg && tg.transition) {
6220 Roo.log("waiting for the transitionend");
6226 //Roo.log("fire event clicked");
6227 if(this.fireEvent('click', this, e) === false){
6231 if(this.tagtype == 'span'){
6235 //Roo.log(this.href);
6236 var ael = this.el.select('a',true).first();
6239 if(ael && this.animateRef && this.href.indexOf('#') > -1){
6240 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
6241 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
6242 return; // ignore... - it's a 'hash' to another page.
6244 Roo.log("NavItem - prevent Default?");
6246 this.scrollToElement(e);
6250 var p = this.parent();
6252 if (['tabs','pills'].indexOf(p.type)!==-1) {
6253 if (typeof(p.setActiveItem) !== 'undefined') {
6254 p.setActiveItem(this);
6258 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
6259 if (p.parentType == 'NavHeaderbar' && !this.menu) {
6260 // remove the collapsed menu expand...
6261 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
6265 isActive: function () {
6268 setActive : function(state, fire, is_was_active)
6270 if (this.active && !state && this.navId) {
6271 this.was_active = true;
6272 var nv = Roo.bootstrap.NavGroup.get(this.navId);
6274 nv.clearWasActive(this);
6278 this.active = state;
6281 this.el.removeClass('active');
6282 this.navLink ? this.navLink.removeClass('active') : false;
6283 } else if (!this.el.hasClass('active')) {
6285 this.el.addClass('active');
6286 if (Roo.bootstrap.version == 4 && this.navLink ) {
6287 this.navLink.addClass('active');
6292 this.fireEvent('changed', this, state);
6295 // show a panel if it's registered and related..
6297 if (!this.navId || !this.tabId || !state || is_was_active) {
6301 var tg = Roo.bootstrap.TabGroup.get(this.navId);
6305 var pan = tg.getPanelByName(this.tabId);
6309 // if we can not flip to new panel - go back to old nav highlight..
6310 if (false == tg.showPanel(pan)) {
6311 var nv = Roo.bootstrap.NavGroup.get(this.navId);
6313 var onav = nv.getWasActive();
6315 onav.setActive(true, false, true);
6324 // this should not be here...
6325 setDisabled : function(state)
6327 this.disabled = state;
6329 this.el.removeClass('disabled');
6330 } else if (!this.el.hasClass('disabled')) {
6331 this.el.addClass('disabled');
6337 * Fetch the element to display the tooltip on.
6338 * @return {Roo.Element} defaults to this.el
6340 tooltipEl : function()
6342 return this.el.select('' + this.tagtype + '', true).first();
6345 scrollToElement : function(e)
6347 var c = document.body;
6350 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
6352 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
6353 c = document.documentElement;
6356 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
6362 var o = target.calcOffsetsTo(c);
6369 this.fireEvent('scrollto', this, options, e);
6371 Roo.get(c).scrollTo('top', options.value, true);
6384 * <span> icon </span>
6385 * <span> text </span>
6386 * <span>badge </span>
6390 * @class Roo.bootstrap.NavSidebarItem
6391 * @extends Roo.bootstrap.NavItem
6392 * Bootstrap Navbar.NavSidebarItem class
6393 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
6394 * {Boolean} open is the menu open
6395 * {Boolean} buttonView use button as the tigger el rather that a (default false)
6396 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
6397 * {String} buttonSize (sm|md|lg)the extra classes for the button
6398 * {Boolean} showArrow show arrow next to the text (default true)
6400 * Create a new Navbar Button
6401 * @param {Object} config The config object
6403 Roo.bootstrap.NavSidebarItem = function(config){
6404 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
6409 * The raw click event for the entire grid.
6410 * @param {Roo.EventObject} e
6415 * Fires when the active item active state changes
6416 * @param {Roo.bootstrap.NavSidebarItem} this
6417 * @param {boolean} state the new state
6425 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
6427 badgeWeight : 'default',
6433 buttonWeight : 'default',
6439 getAutoCreate : function(){
6444 href : this.href || '#',
6450 if(this.buttonView){
6453 href : this.href || '#',
6454 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
6467 cfg.cls += ' active';
6470 if (this.disabled) {
6471 cfg.cls += ' disabled';
6474 cfg.cls += ' open x-open';
6477 if (this.glyphicon || this.icon) {
6478 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
6479 a.cn.push({ tag : 'i', cls : c }) ;
6482 if(!this.buttonView){
6485 html : this.html || ''
6492 if (this.badge !== '') {
6493 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
6499 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
6502 a.cls += ' dropdown-toggle treeview' ;
6508 initEvents : function()
6510 if (typeof (this.menu) != 'undefined') {
6511 this.menu.parentType = this.xtype;
6512 this.menu.triggerEl = this.el;
6513 this.menu = this.addxtype(Roo.apply({}, this.menu));
6516 this.el.on('click', this.onClick, this);
6518 if(this.badge !== ''){
6519 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
6524 onClick : function(e)
6531 if(this.preventDefault){
6535 this.fireEvent('click', this, e);
6538 disable : function()
6540 this.setDisabled(true);
6545 this.setDisabled(false);
6548 setDisabled : function(state)
6550 if(this.disabled == state){
6554 this.disabled = state;
6557 this.el.addClass('disabled');
6561 this.el.removeClass('disabled');
6566 setActive : function(state)
6568 if(this.active == state){
6572 this.active = state;
6575 this.el.addClass('active');
6579 this.el.removeClass('active');
6584 isActive: function ()
6589 setBadge : function(str)
6595 this.badgeEl.dom.innerHTML = str;
6613 * @class Roo.bootstrap.breadcrumb.Nav
6614 * @extends Roo.bootstrap.Component
6615 * Bootstrap Breadcrumb Nav Class
6617 * @children Roo.bootstrap.breadcrumb.Item
6620 * Create a new breadcrumb.Nav
6621 * @param {Object} config The config object
6624 Roo.namespace('Roo.bootstrap.breadcrumb');
6626 Roo.bootstrap.breadcrumb.Nav = function(config){
6627 Roo.bootstrap.breadcrumb.Nav.superclass.constructor.call(this, config);
6632 Roo.extend(Roo.bootstrap.breadcrumb.Nav, Roo.bootstrap.Component, {
6634 getAutoCreate : function()
6651 initEvents: function()
6653 this.olEl = this.el.select('ol',true).first();
6655 getChildContainer : function()
6671 * @class Roo.bootstrap.breadcrumb.Nav
6672 * @extends Roo.bootstrap.Component
6673 * Bootstrap Breadcrumb Nav Class
6675 * @children Roo.bootstrap.breadcrumb.Component
6676 * @cfg {String} html the content of the link.
6677 * @cfg {String} href where it links to if '#' is used the link will be handled by onClick.
6678 * @cfg {Boolean} active is it active
6682 * Create a new breadcrumb.Nav
6683 * @param {Object} config The config object
6686 Roo.bootstrap.breadcrumb.Item = function(config){
6687 Roo.bootstrap.breadcrumb.Item.superclass.constructor.call(this, config);
6692 * The img click event for the img.
6693 * @param {Roo.EventObject} e
6700 Roo.extend(Roo.bootstrap.breadcrumb.Item, Roo.bootstrap.Component, {
6705 getAutoCreate : function()
6710 cls : 'breadcrumb-item' + (this.active ? ' active' : '')
6712 if (this.href !== false) {
6719 cfg.html = this.html;
6725 initEvents: function()
6728 this.el.select('a', true).first().onClick(this.onClick, this)
6732 onClick : function(e)
6735 this.fireEvent('click',this, e);
6748 * @class Roo.bootstrap.Row
6749 * @extends Roo.bootstrap.Component
6750 * Bootstrap Row class (contains columns...)
6754 * @param {Object} config The config object
6757 Roo.bootstrap.Row = function(config){
6758 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6761 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6763 getAutoCreate : function(){
6782 * @class Roo.bootstrap.Pagination
6783 * @extends Roo.bootstrap.Component
6784 * Bootstrap Pagination class
6785 * @cfg {String} size xs | sm | md | lg
6786 * @cfg {Boolean} inverse false | true
6789 * Create a new Pagination
6790 * @param {Object} config The config object
6793 Roo.bootstrap.Pagination = function(config){
6794 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6797 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6803 getAutoCreate : function(){
6809 cfg.cls += ' inverse';
6815 cfg.cls += " " + this.cls;
6833 * @class Roo.bootstrap.PaginationItem
6834 * @extends Roo.bootstrap.Component
6835 * Bootstrap PaginationItem class
6836 * @cfg {String} html text
6837 * @cfg {String} href the link
6838 * @cfg {Boolean} preventDefault (true | false) default true
6839 * @cfg {Boolean} active (true | false) default false
6840 * @cfg {Boolean} disabled default false
6844 * Create a new PaginationItem
6845 * @param {Object} config The config object
6849 Roo.bootstrap.PaginationItem = function(config){
6850 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6855 * The raw click event for the entire grid.
6856 * @param {Roo.EventObject} e
6862 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6866 preventDefault: true,
6871 getAutoCreate : function(){
6877 href : this.href ? this.href : '#',
6878 html : this.html ? this.html : ''
6888 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6892 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6898 initEvents: function() {
6900 this.el.on('click', this.onClick, this);
6903 onClick : function(e)
6905 Roo.log('PaginationItem on click ');
6906 if(this.preventDefault){
6914 this.fireEvent('click', this, e);
6930 * @class Roo.bootstrap.Slider
6931 * @extends Roo.bootstrap.Component
6932 * Bootstrap Slider class
6935 * Create a new Slider
6936 * @param {Object} config The config object
6939 Roo.bootstrap.Slider = function(config){
6940 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6943 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6945 getAutoCreate : function(){
6949 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6953 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6965 * Ext JS Library 1.1.1
6966 * Copyright(c) 2006-2007, Ext JS, LLC.
6968 * Originally Released Under LGPL - original licence link has changed is not relivant.
6971 * <script type="text/javascript">
6976 * @class Roo.grid.ColumnModel
6977 * @extends Roo.util.Observable
6978 * This is the default implementation of a ColumnModel used by the Grid. It defines
6979 * the columns in the grid.
6982 var colModel = new Roo.grid.ColumnModel([
6983 {header: "Ticker", width: 60, sortable: true, locked: true},
6984 {header: "Company Name", width: 150, sortable: true},
6985 {header: "Market Cap.", width: 100, sortable: true},
6986 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6987 {header: "Employees", width: 100, sortable: true, resizable: false}
6992 * The config options listed for this class are options which may appear in each
6993 * individual column definition.
6994 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
6996 * @param {Object} config An Array of column config objects. See this class's
6997 * config objects for details.
6999 Roo.grid.ColumnModel = function(config){
7001 * The config passed into the constructor
7003 this.config = config;
7006 // if no id, create one
7007 // if the column does not have a dataIndex mapping,
7008 // map it to the order it is in the config
7009 for(var i = 0, len = config.length; i < len; i++){
7011 if(typeof c.dataIndex == "undefined"){
7014 if(typeof c.renderer == "string"){
7015 c.renderer = Roo.util.Format[c.renderer];
7017 if(typeof c.id == "undefined"){
7020 if(c.editor && c.editor.xtype){
7021 c.editor = Roo.factory(c.editor, Roo.grid);
7023 if(c.editor && c.editor.isFormField){
7024 c.editor = new Roo.grid.GridEditor(c.editor);
7026 this.lookup[c.id] = c;
7030 * The width of columns which have no width specified (defaults to 100)
7033 this.defaultWidth = 100;
7036 * Default sortable of columns which have no sortable specified (defaults to false)
7039 this.defaultSortable = false;
7043 * @event widthchange
7044 * Fires when the width of a column changes.
7045 * @param {ColumnModel} this
7046 * @param {Number} columnIndex The column index
7047 * @param {Number} newWidth The new width
7049 "widthchange": true,
7051 * @event headerchange
7052 * Fires when the text of a header changes.
7053 * @param {ColumnModel} this
7054 * @param {Number} columnIndex The column index
7055 * @param {Number} newText The new header text
7057 "headerchange": true,
7059 * @event hiddenchange
7060 * Fires when a column is hidden or "unhidden".
7061 * @param {ColumnModel} this
7062 * @param {Number} columnIndex The column index
7063 * @param {Boolean} hidden true if hidden, false otherwise
7065 "hiddenchange": true,
7067 * @event columnmoved
7068 * Fires when a column is moved.
7069 * @param {ColumnModel} this
7070 * @param {Number} oldIndex
7071 * @param {Number} newIndex
7073 "columnmoved" : true,
7075 * @event columlockchange
7076 * Fires when a column's locked state is changed
7077 * @param {ColumnModel} this
7078 * @param {Number} colIndex
7079 * @param {Boolean} locked true if locked
7081 "columnlockchange" : true
7083 Roo.grid.ColumnModel.superclass.constructor.call(this);
7085 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
7087 * @cfg {String} header The header text to display in the Grid view.
7090 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
7091 * {@link Roo.data.Record} definition from which to draw the column's value. If not
7092 * specified, the column's index is used as an index into the Record's data Array.
7095 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
7096 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
7099 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
7100 * Defaults to the value of the {@link #defaultSortable} property.
7101 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
7104 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
7107 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
7110 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
7113 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
7116 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
7117 * given the cell's data value. See {@link #setRenderer}. If not specified, the
7118 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
7119 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
7122 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
7125 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
7128 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
7131 * @cfg {String} cursor (Optional)
7134 * @cfg {String} tooltip (Optional)
7137 * @cfg {Number} xs (Optional)
7140 * @cfg {Number} sm (Optional)
7143 * @cfg {Number} md (Optional)
7146 * @cfg {Number} lg (Optional)
7149 * Returns the id of the column at the specified index.
7150 * @param {Number} index The column index
7151 * @return {String} the id
7153 getColumnId : function(index){
7154 return this.config[index].id;
7158 * Returns the column for a specified id.
7159 * @param {String} id The column id
7160 * @return {Object} the column
7162 getColumnById : function(id){
7163 return this.lookup[id];
7168 * Returns the column for a specified dataIndex.
7169 * @param {String} dataIndex The column dataIndex
7170 * @return {Object|Boolean} the column or false if not found
7172 getColumnByDataIndex: function(dataIndex){
7173 var index = this.findColumnIndex(dataIndex);
7174 return index > -1 ? this.config[index] : false;
7178 * Returns the index for a specified column id.
7179 * @param {String} id The column id
7180 * @return {Number} the index, or -1 if not found
7182 getIndexById : function(id){
7183 for(var i = 0, len = this.config.length; i < len; i++){
7184 if(this.config[i].id == id){
7192 * Returns the index for a specified column dataIndex.
7193 * @param {String} dataIndex The column dataIndex
7194 * @return {Number} the index, or -1 if not found
7197 findColumnIndex : function(dataIndex){
7198 for(var i = 0, len = this.config.length; i < len; i++){
7199 if(this.config[i].dataIndex == dataIndex){
7207 moveColumn : function(oldIndex, newIndex){
7208 var c = this.config[oldIndex];
7209 this.config.splice(oldIndex, 1);
7210 this.config.splice(newIndex, 0, c);
7211 this.dataMap = null;
7212 this.fireEvent("columnmoved", this, oldIndex, newIndex);
7215 isLocked : function(colIndex){
7216 return this.config[colIndex].locked === true;
7219 setLocked : function(colIndex, value, suppressEvent){
7220 if(this.isLocked(colIndex) == value){
7223 this.config[colIndex].locked = value;
7225 this.fireEvent("columnlockchange", this, colIndex, value);
7229 getTotalLockedWidth : function(){
7231 for(var i = 0; i < this.config.length; i++){
7232 if(this.isLocked(i) && !this.isHidden(i)){
7233 this.totalWidth += this.getColumnWidth(i);
7239 getLockedCount : function(){
7240 for(var i = 0, len = this.config.length; i < len; i++){
7241 if(!this.isLocked(i)){
7246 return this.config.length;
7250 * Returns the number of columns.
7253 getColumnCount : function(visibleOnly){
7254 if(visibleOnly === true){
7256 for(var i = 0, len = this.config.length; i < len; i++){
7257 if(!this.isHidden(i)){
7263 return this.config.length;
7267 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
7268 * @param {Function} fn
7269 * @param {Object} scope (optional)
7270 * @return {Array} result
7272 getColumnsBy : function(fn, scope){
7274 for(var i = 0, len = this.config.length; i < len; i++){
7275 var c = this.config[i];
7276 if(fn.call(scope||this, c, i) === true){
7284 * Returns true if the specified column is sortable.
7285 * @param {Number} col The column index
7288 isSortable : function(col){
7289 if(typeof this.config[col].sortable == "undefined"){
7290 return this.defaultSortable;
7292 return this.config[col].sortable;
7296 * Returns the rendering (formatting) function defined for the column.
7297 * @param {Number} col The column index.
7298 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
7300 getRenderer : function(col){
7301 if(!this.config[col].renderer){
7302 return Roo.grid.ColumnModel.defaultRenderer;
7304 return this.config[col].renderer;
7308 * Sets the rendering (formatting) function for a column.
7309 * @param {Number} col The column index
7310 * @param {Function} fn The function to use to process the cell's raw data
7311 * to return HTML markup for the grid view. The render function is called with
7312 * the following parameters:<ul>
7313 * <li>Data value.</li>
7314 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
7315 * <li>css A CSS style string to apply to the table cell.</li>
7316 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
7317 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
7318 * <li>Row index</li>
7319 * <li>Column index</li>
7320 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
7322 setRenderer : function(col, fn){
7323 this.config[col].renderer = fn;
7327 * Returns the width for the specified column.
7328 * @param {Number} col The column index
7331 getColumnWidth : function(col){
7332 return this.config[col].width * 1 || this.defaultWidth;
7336 * Sets the width for a column.
7337 * @param {Number} col The column index
7338 * @param {Number} width The new width
7340 setColumnWidth : function(col, width, suppressEvent){
7341 this.config[col].width = width;
7342 this.totalWidth = null;
7344 this.fireEvent("widthchange", this, col, width);
7349 * Returns the total width of all columns.
7350 * @param {Boolean} includeHidden True to include hidden column widths
7353 getTotalWidth : function(includeHidden){
7354 if(!this.totalWidth){
7355 this.totalWidth = 0;
7356 for(var i = 0, len = this.config.length; i < len; i++){
7357 if(includeHidden || !this.isHidden(i)){
7358 this.totalWidth += this.getColumnWidth(i);
7362 return this.totalWidth;
7366 * Returns the header for the specified column.
7367 * @param {Number} col The column index
7370 getColumnHeader : function(col){
7371 return this.config[col].header;
7375 * Sets the header for a column.
7376 * @param {Number} col The column index
7377 * @param {String} header The new header
7379 setColumnHeader : function(col, header){
7380 this.config[col].header = header;
7381 this.fireEvent("headerchange", this, col, header);
7385 * Returns the tooltip for the specified column.
7386 * @param {Number} col The column index
7389 getColumnTooltip : function(col){
7390 return this.config[col].tooltip;
7393 * Sets the tooltip for a column.
7394 * @param {Number} col The column index
7395 * @param {String} tooltip The new tooltip
7397 setColumnTooltip : function(col, tooltip){
7398 this.config[col].tooltip = tooltip;
7402 * Returns the dataIndex for the specified column.
7403 * @param {Number} col The column index
7406 getDataIndex : function(col){
7407 return this.config[col].dataIndex;
7411 * Sets the dataIndex for a column.
7412 * @param {Number} col The column index
7413 * @param {Number} dataIndex The new dataIndex
7415 setDataIndex : function(col, dataIndex){
7416 this.config[col].dataIndex = dataIndex;
7422 * Returns true if the cell is editable.
7423 * @param {Number} colIndex The column index
7424 * @param {Number} rowIndex The row index - this is nto actually used..?
7427 isCellEditable : function(colIndex, rowIndex){
7428 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
7432 * Returns the editor defined for the cell/column.
7433 * return false or null to disable editing.
7434 * @param {Number} colIndex The column index
7435 * @param {Number} rowIndex The row index
7438 getCellEditor : function(colIndex, rowIndex){
7439 return this.config[colIndex].editor;
7443 * Sets if a column is editable.
7444 * @param {Number} col The column index
7445 * @param {Boolean} editable True if the column is editable
7447 setEditable : function(col, editable){
7448 this.config[col].editable = editable;
7453 * Returns true if the column is hidden.
7454 * @param {Number} colIndex The column index
7457 isHidden : function(colIndex){
7458 return this.config[colIndex].hidden;
7463 * Returns true if the column width cannot be changed
7465 isFixed : function(colIndex){
7466 return this.config[colIndex].fixed;
7470 * Returns true if the column can be resized
7473 isResizable : function(colIndex){
7474 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7477 * Sets if a column is hidden.
7478 * @param {Number} colIndex The column index
7479 * @param {Boolean} hidden True if the column is hidden
7481 setHidden : function(colIndex, hidden){
7482 this.config[colIndex].hidden = hidden;
7483 this.totalWidth = null;
7484 this.fireEvent("hiddenchange", this, colIndex, hidden);
7488 * Sets the editor for a column.
7489 * @param {Number} col The column index
7490 * @param {Object} editor The editor object
7492 setEditor : function(col, editor){
7493 this.config[col].editor = editor;
7497 Roo.grid.ColumnModel.defaultRenderer = function(value)
7499 if(typeof value == "object") {
7502 if(typeof value == "string" && value.length < 1){
7506 return String.format("{0}", value);
7509 // Alias for backwards compatibility
7510 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7513 * Ext JS Library 1.1.1
7514 * Copyright(c) 2006-2007, Ext JS, LLC.
7516 * Originally Released Under LGPL - original licence link has changed is not relivant.
7519 * <script type="text/javascript">
7523 * @class Roo.LoadMask
7524 * A simple utility class for generically masking elements while loading data. If the element being masked has
7525 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7526 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7527 * element's UpdateManager load indicator and will be destroyed after the initial load.
7529 * Create a new LoadMask
7530 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7531 * @param {Object} config The config object
7533 Roo.LoadMask = function(el, config){
7534 this.el = Roo.get(el);
7535 Roo.apply(this, config);
7537 this.store.on('beforeload', this.onBeforeLoad, this);
7538 this.store.on('load', this.onLoad, this);
7539 this.store.on('loadexception', this.onLoadException, this);
7540 this.removeMask = false;
7542 var um = this.el.getUpdateManager();
7543 um.showLoadIndicator = false; // disable the default indicator
7544 um.on('beforeupdate', this.onBeforeLoad, this);
7545 um.on('update', this.onLoad, this);
7546 um.on('failure', this.onLoad, this);
7547 this.removeMask = true;
7551 Roo.LoadMask.prototype = {
7553 * @cfg {Boolean} removeMask
7554 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7555 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7559 * The text to display in a centered loading message box (defaults to 'Loading...')
7563 * @cfg {String} msgCls
7564 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7566 msgCls : 'x-mask-loading',
7569 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7575 * Disables the mask to prevent it from being displayed
7577 disable : function(){
7578 this.disabled = true;
7582 * Enables the mask so that it can be displayed
7584 enable : function(){
7585 this.disabled = false;
7588 onLoadException : function()
7592 if (typeof(arguments[3]) != 'undefined') {
7593 Roo.MessageBox.alert("Error loading",arguments[3]);
7597 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7598 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7605 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7610 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7614 onBeforeLoad : function(){
7616 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7621 destroy : function(){
7623 this.store.un('beforeload', this.onBeforeLoad, this);
7624 this.store.un('load', this.onLoad, this);
7625 this.store.un('loadexception', this.onLoadException, this);
7627 var um = this.el.getUpdateManager();
7628 um.un('beforeupdate', this.onBeforeLoad, this);
7629 um.un('update', this.onLoad, this);
7630 um.un('failure', this.onLoad, this);
7641 * @class Roo.bootstrap.Table
7642 * @extends Roo.bootstrap.Component
7643 * Bootstrap Table class
7644 * @cfg {String} cls table class
7645 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7646 * @cfg {String} bgcolor Specifies the background color for a table
7647 * @cfg {Number} border Specifies whether the table cells should have borders or not
7648 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7649 * @cfg {Number} cellspacing Specifies the space between cells
7650 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7651 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7652 * @cfg {String} sortable Specifies that the table should be sortable
7653 * @cfg {String} summary Specifies a summary of the content of a table
7654 * @cfg {Number} width Specifies the width of a table
7655 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7657 * @cfg {boolean} striped Should the rows be alternative striped
7658 * @cfg {boolean} bordered Add borders to the table
7659 * @cfg {boolean} hover Add hover highlighting
7660 * @cfg {boolean} condensed Format condensed
7661 * @cfg {boolean} responsive Format condensed
7662 * @cfg {Boolean} loadMask (true|false) default false
7663 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7664 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7665 * @cfg {Boolean} rowSelection (true|false) default false
7666 * @cfg {Boolean} cellSelection (true|false) default false
7667 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7668 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7669 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7670 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7674 * Create a new Table
7675 * @param {Object} config The config object
7678 Roo.bootstrap.Table = function(config){
7679 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7684 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7685 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7686 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7687 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7689 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7691 this.sm.grid = this;
7692 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7693 this.sm = this.selModel;
7694 this.sm.xmodule = this.xmodule || false;
7697 if (this.cm && typeof(this.cm.config) == 'undefined') {
7698 this.colModel = new Roo.grid.ColumnModel(this.cm);
7699 this.cm = this.colModel;
7700 this.cm.xmodule = this.xmodule || false;
7703 this.store= Roo.factory(this.store, Roo.data);
7704 this.ds = this.store;
7705 this.ds.xmodule = this.xmodule || false;
7708 if (this.footer && this.store) {
7709 this.footer.dataSource = this.ds;
7710 this.footer = Roo.factory(this.footer);
7717 * Fires when a cell is clicked
7718 * @param {Roo.bootstrap.Table} this
7719 * @param {Roo.Element} el
7720 * @param {Number} rowIndex
7721 * @param {Number} columnIndex
7722 * @param {Roo.EventObject} e
7726 * @event celldblclick
7727 * Fires when a cell is double 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
7734 "celldblclick" : true,
7737 * Fires when a row is clicked
7738 * @param {Roo.bootstrap.Table} this
7739 * @param {Roo.Element} el
7740 * @param {Number} rowIndex
7741 * @param {Roo.EventObject} e
7745 * @event rowdblclick
7746 * Fires when a row is double clicked
7747 * @param {Roo.bootstrap.Table} this
7748 * @param {Roo.Element} el
7749 * @param {Number} rowIndex
7750 * @param {Roo.EventObject} e
7752 "rowdblclick" : true,
7755 * Fires when a mouseover occur
7756 * @param {Roo.bootstrap.Table} this
7757 * @param {Roo.Element} el
7758 * @param {Number} rowIndex
7759 * @param {Number} columnIndex
7760 * @param {Roo.EventObject} e
7765 * Fires when a mouseout 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 row is rendered, so you can change add a style to it.
7776 * @param {Roo.bootstrap.Table} this
7777 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7781 * @event rowsrendered
7782 * Fires when all the rows have been rendered
7783 * @param {Roo.bootstrap.Table} this
7785 'rowsrendered' : true,
7787 * @event contextmenu
7788 * The raw contextmenu event for the entire grid.
7789 * @param {Roo.EventObject} e
7791 "contextmenu" : true,
7793 * @event rowcontextmenu
7794 * Fires when a row is right clicked
7795 * @param {Roo.bootstrap.Table} this
7796 * @param {Number} rowIndex
7797 * @param {Roo.EventObject} e
7799 "rowcontextmenu" : true,
7801 * @event cellcontextmenu
7802 * Fires when a cell is right clicked
7803 * @param {Roo.bootstrap.Table} this
7804 * @param {Number} rowIndex
7805 * @param {Number} cellIndex
7806 * @param {Roo.EventObject} e
7808 "cellcontextmenu" : true,
7810 * @event headercontextmenu
7811 * Fires when a header is right clicked
7812 * @param {Roo.bootstrap.Table} this
7813 * @param {Number} columnIndex
7814 * @param {Roo.EventObject} e
7816 "headercontextmenu" : true
7820 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7846 rowSelection : false,
7847 cellSelection : false,
7850 // Roo.Element - the tbody
7852 // Roo.Element - thead element
7855 container: false, // used by gridpanel...
7861 auto_hide_footer : false,
7863 getAutoCreate : function()
7865 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7872 if (this.scrollBody) {
7873 cfg.cls += ' table-body-fixed';
7876 cfg.cls += ' table-striped';
7880 cfg.cls += ' table-hover';
7882 if (this.bordered) {
7883 cfg.cls += ' table-bordered';
7885 if (this.condensed) {
7886 cfg.cls += ' table-condensed';
7888 if (this.responsive) {
7889 cfg.cls += ' table-responsive';
7893 cfg.cls+= ' ' +this.cls;
7896 // this lot should be simplifed...
7909 ].forEach(function(k) {
7917 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7920 if(this.store || this.cm){
7921 if(this.headerShow){
7922 cfg.cn.push(this.renderHeader());
7925 cfg.cn.push(this.renderBody());
7927 if(this.footerShow){
7928 cfg.cn.push(this.renderFooter());
7930 // where does this come from?
7931 //cfg.cls+= ' TableGrid';
7934 return { cn : [ cfg ] };
7937 initEvents : function()
7939 if(!this.store || !this.cm){
7942 if (this.selModel) {
7943 this.selModel.initEvents();
7947 //Roo.log('initEvents with ds!!!!');
7949 this.mainBody = this.el.select('tbody', true).first();
7950 this.mainHead = this.el.select('thead', true).first();
7951 this.mainFoot = this.el.select('tfoot', true).first();
7957 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7958 e.on('click', _this.sort, _this);
7961 this.mainBody.on("click", this.onClick, this);
7962 this.mainBody.on("dblclick", this.onDblClick, this);
7964 // why is this done????? = it breaks dialogs??
7965 //this.parent().el.setStyle('position', 'relative');
7969 this.footer.parentId = this.id;
7970 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7973 this.el.select('tfoot tr td').first().addClass('hide');
7978 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7981 this.store.on('load', this.onLoad, this);
7982 this.store.on('beforeload', this.onBeforeLoad, this);
7983 this.store.on('update', this.onUpdate, this);
7984 this.store.on('add', this.onAdd, this);
7985 this.store.on("clear", this.clear, this);
7987 this.el.on("contextmenu", this.onContextMenu, this);
7989 this.mainBody.on('scroll', this.onBodyScroll, this);
7991 this.cm.on("headerchange", this.onHeaderChange, this);
7993 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
7997 onContextMenu : function(e, t)
7999 this.processEvent("contextmenu", e);
8002 processEvent : function(name, e)
8004 if (name != 'touchstart' ) {
8005 this.fireEvent(name, e);
8008 var t = e.getTarget();
8010 var cell = Roo.get(t);
8016 if(cell.findParent('tfoot', false, true)){
8020 if(cell.findParent('thead', false, true)){
8022 if(e.getTarget().nodeName.toLowerCase() != 'th'){
8023 cell = Roo.get(t).findParent('th', false, true);
8025 Roo.log("failed to find th in thead?");
8026 Roo.log(e.getTarget());
8031 var cellIndex = cell.dom.cellIndex;
8033 var ename = name == 'touchstart' ? 'click' : name;
8034 this.fireEvent("header" + ename, this, cellIndex, e);
8039 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8040 cell = Roo.get(t).findParent('td', false, true);
8042 Roo.log("failed to find th in tbody?");
8043 Roo.log(e.getTarget());
8048 var row = cell.findParent('tr', false, true);
8049 var cellIndex = cell.dom.cellIndex;
8050 var rowIndex = row.dom.rowIndex - 1;
8054 this.fireEvent("row" + name, this, rowIndex, e);
8058 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
8064 onMouseover : function(e, el)
8066 var cell = Roo.get(el);
8072 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8073 cell = cell.findParent('td', false, true);
8076 var row = cell.findParent('tr', false, true);
8077 var cellIndex = cell.dom.cellIndex;
8078 var rowIndex = row.dom.rowIndex - 1; // start from 0
8080 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
8084 onMouseout : function(e, el)
8086 var cell = Roo.get(el);
8092 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8093 cell = cell.findParent('td', false, true);
8096 var row = cell.findParent('tr', false, true);
8097 var cellIndex = cell.dom.cellIndex;
8098 var rowIndex = row.dom.rowIndex - 1; // start from 0
8100 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
8104 onClick : function(e, el)
8106 var cell = Roo.get(el);
8108 if(!cell || (!this.cellSelection && !this.rowSelection)){
8112 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8113 cell = cell.findParent('td', false, true);
8116 if(!cell || typeof(cell) == 'undefined'){
8120 var row = cell.findParent('tr', false, true);
8122 if(!row || typeof(row) == 'undefined'){
8126 var cellIndex = cell.dom.cellIndex;
8127 var rowIndex = this.getRowIndex(row);
8129 // why??? - should these not be based on SelectionModel?
8130 if(this.cellSelection){
8131 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
8134 if(this.rowSelection){
8135 this.fireEvent('rowclick', this, row, rowIndex, e);
8141 onDblClick : function(e,el)
8143 var cell = Roo.get(el);
8145 if(!cell || (!this.cellSelection && !this.rowSelection)){
8149 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8150 cell = cell.findParent('td', false, true);
8153 if(!cell || typeof(cell) == 'undefined'){
8157 var row = cell.findParent('tr', false, true);
8159 if(!row || typeof(row) == 'undefined'){
8163 var cellIndex = cell.dom.cellIndex;
8164 var rowIndex = this.getRowIndex(row);
8166 if(this.cellSelection){
8167 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
8170 if(this.rowSelection){
8171 this.fireEvent('rowdblclick', this, row, rowIndex, e);
8175 sort : function(e,el)
8177 var col = Roo.get(el);
8179 if(!col.hasClass('sortable')){
8183 var sort = col.attr('sort');
8186 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
8190 this.store.sortInfo = {field : sort, direction : dir};
8193 Roo.log("calling footer first");
8194 this.footer.onClick('first');
8197 this.store.load({ params : { start : 0 } });
8201 renderHeader : function()
8209 this.totalWidth = 0;
8211 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8213 var config = cm.config[i];
8217 cls : 'x-hcol-' + i,
8219 html: cm.getColumnHeader(i)
8224 if(typeof(config.sortable) != 'undefined' && config.sortable){
8226 c.html = '<i class="glyphicon"></i>' + c.html;
8229 // could use BS4 hidden-..-down
8231 if(typeof(config.lgHeader) != 'undefined'){
8232 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
8235 if(typeof(config.mdHeader) != 'undefined'){
8236 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
8239 if(typeof(config.smHeader) != 'undefined'){
8240 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
8243 if(typeof(config.xsHeader) != 'undefined'){
8244 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
8251 if(typeof(config.tooltip) != 'undefined'){
8252 c.tooltip = config.tooltip;
8255 if(typeof(config.colspan) != 'undefined'){
8256 c.colspan = config.colspan;
8259 if(typeof(config.hidden) != 'undefined' && config.hidden){
8260 c.style += ' display:none;';
8263 if(typeof(config.dataIndex) != 'undefined'){
8264 c.sort = config.dataIndex;
8269 if(typeof(config.align) != 'undefined' && config.align.length){
8270 c.style += ' text-align:' + config.align + ';';
8273 if(typeof(config.width) != 'undefined'){
8274 c.style += ' width:' + config.width + 'px;';
8275 this.totalWidth += config.width;
8277 this.totalWidth += 100; // assume minimum of 100 per column?
8280 if(typeof(config.cls) != 'undefined'){
8281 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
8284 ['xs','sm','md','lg'].map(function(size){
8286 if(typeof(config[size]) == 'undefined'){
8290 if (!config[size]) { // 0 = hidden
8291 // BS 4 '0' is treated as hide that column and below.
8292 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
8296 c.cls += ' col-' + size + '-' + config[size] + (
8297 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8309 renderBody : function()
8319 colspan : this.cm.getColumnCount()
8329 renderFooter : function()
8339 colspan : this.cm.getColumnCount()
8353 // Roo.log('ds onload');
8358 var ds = this.store;
8360 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
8361 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
8362 if (_this.store.sortInfo) {
8364 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
8365 e.select('i', true).addClass(['glyphicon-arrow-up']);
8368 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
8369 e.select('i', true).addClass(['glyphicon-arrow-down']);
8374 var tbody = this.mainBody;
8376 if(ds.getCount() > 0){
8377 ds.data.each(function(d,rowIndex){
8378 var row = this.renderRow(cm, ds, rowIndex);
8380 tbody.createChild(row);
8384 if(row.cellObjects.length){
8385 Roo.each(row.cellObjects, function(r){
8386 _this.renderCellObject(r);
8393 var tfoot = this.el.select('tfoot', true).first();
8395 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
8397 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
8399 var total = this.ds.getTotalCount();
8401 if(this.footer.pageSize < total){
8402 this.mainFoot.show();
8406 Roo.each(this.el.select('tbody td', true).elements, function(e){
8407 e.on('mouseover', _this.onMouseover, _this);
8410 Roo.each(this.el.select('tbody td', true).elements, function(e){
8411 e.on('mouseout', _this.onMouseout, _this);
8413 this.fireEvent('rowsrendered', this);
8419 onUpdate : function(ds,record)
8421 this.refreshRow(record);
8425 onRemove : function(ds, record, index, isUpdate){
8426 if(isUpdate !== true){
8427 this.fireEvent("beforerowremoved", this, index, record);
8429 var bt = this.mainBody.dom;
8431 var rows = this.el.select('tbody > tr', true).elements;
8433 if(typeof(rows[index]) != 'undefined'){
8434 bt.removeChild(rows[index].dom);
8437 // if(bt.rows[index]){
8438 // bt.removeChild(bt.rows[index]);
8441 if(isUpdate !== true){
8442 //this.stripeRows(index);
8443 //this.syncRowHeights(index, index);
8445 this.fireEvent("rowremoved", this, index, record);
8449 onAdd : function(ds, records, rowIndex)
8451 //Roo.log('on Add called');
8452 // - note this does not handle multiple adding very well..
8453 var bt = this.mainBody.dom;
8454 for (var i =0 ; i < records.length;i++) {
8455 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
8456 //Roo.log(records[i]);
8457 //Roo.log(this.store.getAt(rowIndex+i));
8458 this.insertRow(this.store, rowIndex + i, false);
8465 refreshRow : function(record){
8466 var ds = this.store, index;
8467 if(typeof record == 'number'){
8469 record = ds.getAt(index);
8471 index = ds.indexOf(record);
8473 return; // should not happen - but seems to
8476 this.insertRow(ds, index, true);
8478 this.onRemove(ds, record, index+1, true);
8480 //this.syncRowHeights(index, index);
8482 this.fireEvent("rowupdated", this, index, record);
8485 insertRow : function(dm, rowIndex, isUpdate){
8488 this.fireEvent("beforerowsinserted", this, rowIndex);
8490 //var s = this.getScrollState();
8491 var row = this.renderRow(this.cm, this.store, rowIndex);
8492 // insert before rowIndex..
8493 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8497 if(row.cellObjects.length){
8498 Roo.each(row.cellObjects, function(r){
8499 _this.renderCellObject(r);
8504 this.fireEvent("rowsinserted", this, rowIndex);
8505 //this.syncRowHeights(firstRow, lastRow);
8506 //this.stripeRows(firstRow);
8513 getRowDom : function(rowIndex)
8515 var rows = this.el.select('tbody > tr', true).elements;
8517 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8520 // returns the object tree for a tr..
8523 renderRow : function(cm, ds, rowIndex)
8525 var d = ds.getAt(rowIndex);
8529 cls : 'x-row-' + rowIndex,
8533 var cellObjects = [];
8535 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8536 var config = cm.config[i];
8538 var renderer = cm.getRenderer(i);
8542 if(typeof(renderer) !== 'undefined'){
8543 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8545 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8546 // and are rendered into the cells after the row is rendered - using the id for the element.
8548 if(typeof(value) === 'object'){
8558 rowIndex : rowIndex,
8563 this.fireEvent('rowclass', this, rowcfg);
8567 cls : rowcfg.rowClass + ' x-col-' + i,
8569 html: (typeof(value) === 'object') ? '' : value
8576 if(typeof(config.colspan) != 'undefined'){
8577 td.colspan = config.colspan;
8580 if(typeof(config.hidden) != 'undefined' && config.hidden){
8581 td.style += ' display:none;';
8584 if(typeof(config.align) != 'undefined' && config.align.length){
8585 td.style += ' text-align:' + config.align + ';';
8587 if(typeof(config.valign) != 'undefined' && config.valign.length){
8588 td.style += ' vertical-align:' + config.valign + ';';
8591 if(typeof(config.width) != 'undefined'){
8592 td.style += ' width:' + config.width + 'px;';
8595 if(typeof(config.cursor) != 'undefined'){
8596 td.style += ' cursor:' + config.cursor + ';';
8599 if(typeof(config.cls) != 'undefined'){
8600 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8603 ['xs','sm','md','lg'].map(function(size){
8605 if(typeof(config[size]) == 'undefined'){
8611 if (!config[size]) { // 0 = hidden
8612 // BS 4 '0' is treated as hide that column and below.
8613 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8617 td.cls += ' col-' + size + '-' + config[size] + (
8618 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8628 row.cellObjects = cellObjects;
8636 onBeforeLoad : function()
8645 this.el.select('tbody', true).first().dom.innerHTML = '';
8648 * Show or hide a row.
8649 * @param {Number} rowIndex to show or hide
8650 * @param {Boolean} state hide
8652 setRowVisibility : function(rowIndex, state)
8654 var bt = this.mainBody.dom;
8656 var rows = this.el.select('tbody > tr', true).elements;
8658 if(typeof(rows[rowIndex]) == 'undefined'){
8661 rows[rowIndex].dom.style.display = state ? '' : 'none';
8665 getSelectionModel : function(){
8667 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8669 return this.selModel;
8672 * Render the Roo.bootstrap object from renderder
8674 renderCellObject : function(r)
8678 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8680 var t = r.cfg.render(r.container);
8683 Roo.each(r.cfg.cn, function(c){
8685 container: t.getChildContainer(),
8688 _this.renderCellObject(child);
8693 getRowIndex : function(row)
8697 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8708 * Returns the grid's underlying element = used by panel.Grid
8709 * @return {Element} The element
8711 getGridEl : function(){
8715 * Forces a resize - used by panel.Grid
8716 * @return {Element} The element
8718 autoSize : function()
8720 //var ctr = Roo.get(this.container.dom.parentElement);
8721 var ctr = Roo.get(this.el.dom);
8723 var thd = this.getGridEl().select('thead',true).first();
8724 var tbd = this.getGridEl().select('tbody', true).first();
8725 var tfd = this.getGridEl().select('tfoot', true).first();
8727 var cw = ctr.getWidth();
8728 this.getGridEl().select('tfoot tr, tfoot td',true).setWidth(cw);
8732 tbd.setWidth(ctr.getWidth());
8733 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8734 // this needs fixing for various usage - currently only hydra job advers I think..
8736 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8738 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8741 cw = Math.max(cw, this.totalWidth);
8742 this.getGridEl().select('tbody tr',true).setWidth(cw);
8744 // resize 'expandable coloumn?
8746 return; // we doe not have a view in this design..
8749 onBodyScroll: function()
8751 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8753 this.mainHead.setStyle({
8754 'position' : 'relative',
8755 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8761 var scrollHeight = this.mainBody.dom.scrollHeight;
8763 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8765 var height = this.mainBody.getHeight();
8767 if(scrollHeight - height == scrollTop) {
8769 var total = this.ds.getTotalCount();
8771 if(this.footer.cursor + this.footer.pageSize < total){
8773 this.footer.ds.load({
8775 start : this.footer.cursor + this.footer.pageSize,
8776 limit : this.footer.pageSize
8786 onHeaderChange : function()
8788 var header = this.renderHeader();
8789 var table = this.el.select('table', true).first();
8791 this.mainHead.remove();
8792 this.mainHead = table.createChild(header, this.mainBody, false);
8795 onHiddenChange : function(colModel, colIndex, hidden)
8797 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8798 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8800 this.CSS.updateRule(thSelector, "display", "");
8801 this.CSS.updateRule(tdSelector, "display", "");
8804 this.CSS.updateRule(thSelector, "display", "none");
8805 this.CSS.updateRule(tdSelector, "display", "none");
8808 this.onHeaderChange();
8812 setColumnWidth: function(col_index, width)
8814 // width = "md-2 xs-2..."
8815 if(!this.colModel.config[col_index]) {
8819 var w = width.split(" ");
8821 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8823 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8826 for(var j = 0; j < w.length; j++) {
8832 var size_cls = w[j].split("-");
8834 if(!Number.isInteger(size_cls[1] * 1)) {
8838 if(!this.colModel.config[col_index][size_cls[0]]) {
8842 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8846 h_row[0].classList.replace(
8847 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8848 "col-"+size_cls[0]+"-"+size_cls[1]
8851 for(var i = 0; i < rows.length; i++) {
8853 var size_cls = w[j].split("-");
8855 if(!Number.isInteger(size_cls[1] * 1)) {
8859 if(!this.colModel.config[col_index][size_cls[0]]) {
8863 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8867 rows[i].classList.replace(
8868 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8869 "col-"+size_cls[0]+"-"+size_cls[1]
8873 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8888 * @class Roo.bootstrap.TableCell
8889 * @extends Roo.bootstrap.Component
8890 * Bootstrap TableCell class
8891 * @cfg {String} html cell contain text
8892 * @cfg {String} cls cell class
8893 * @cfg {String} tag cell tag (td|th) default td
8894 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8895 * @cfg {String} align Aligns the content in a cell
8896 * @cfg {String} axis Categorizes cells
8897 * @cfg {String} bgcolor Specifies the background color of a cell
8898 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8899 * @cfg {Number} colspan Specifies the number of columns a cell should span
8900 * @cfg {String} headers Specifies one or more header cells a cell is related to
8901 * @cfg {Number} height Sets the height of a cell
8902 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8903 * @cfg {Number} rowspan Sets the number of rows a cell should span
8904 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8905 * @cfg {String} valign Vertical aligns the content in a cell
8906 * @cfg {Number} width Specifies the width of a cell
8909 * Create a new TableCell
8910 * @param {Object} config The config object
8913 Roo.bootstrap.TableCell = function(config){
8914 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8917 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8937 getAutoCreate : function(){
8938 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8958 cfg.align=this.align
8964 cfg.bgcolor=this.bgcolor
8967 cfg.charoff=this.charoff
8970 cfg.colspan=this.colspan
8973 cfg.headers=this.headers
8976 cfg.height=this.height
8979 cfg.nowrap=this.nowrap
8982 cfg.rowspan=this.rowspan
8985 cfg.scope=this.scope
8988 cfg.valign=this.valign
8991 cfg.width=this.width
9010 * @class Roo.bootstrap.TableRow
9011 * @extends Roo.bootstrap.Component
9012 * Bootstrap TableRow class
9013 * @cfg {String} cls row class
9014 * @cfg {String} align Aligns the content in a table row
9015 * @cfg {String} bgcolor Specifies a background color for a table row
9016 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
9017 * @cfg {String} valign Vertical aligns the content in a table row
9020 * Create a new TableRow
9021 * @param {Object} config The config object
9024 Roo.bootstrap.TableRow = function(config){
9025 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
9028 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
9036 getAutoCreate : function(){
9037 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
9047 cfg.align = this.align;
9050 cfg.bgcolor = this.bgcolor;
9053 cfg.charoff = this.charoff;
9056 cfg.valign = this.valign;
9074 * @class Roo.bootstrap.TableBody
9075 * @extends Roo.bootstrap.Component
9076 * Bootstrap TableBody class
9077 * @cfg {String} cls element class
9078 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
9079 * @cfg {String} align Aligns the content inside the element
9080 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
9081 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
9084 * Create a new TableBody
9085 * @param {Object} config The config object
9088 Roo.bootstrap.TableBody = function(config){
9089 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
9092 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
9100 getAutoCreate : function(){
9101 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
9115 cfg.align = this.align;
9118 cfg.charoff = this.charoff;
9121 cfg.valign = this.valign;
9128 // initEvents : function()
9135 // this.store = Roo.factory(this.store, Roo.data);
9136 // this.store.on('load', this.onLoad, this);
9138 // this.store.load();
9142 // onLoad: function ()
9144 // this.fireEvent('load', this);
9154 * Ext JS Library 1.1.1
9155 * Copyright(c) 2006-2007, Ext JS, LLC.
9157 * Originally Released Under LGPL - original licence link has changed is not relivant.
9160 * <script type="text/javascript">
9163 // as we use this in bootstrap.
9164 Roo.namespace('Roo.form');
9166 * @class Roo.form.Action
9167 * Internal Class used to handle form actions
9169 * @param {Roo.form.BasicForm} el The form element or its id
9170 * @param {Object} config Configuration options
9175 // define the action interface
9176 Roo.form.Action = function(form, options){
9178 this.options = options || {};
9181 * Client Validation Failed
9184 Roo.form.Action.CLIENT_INVALID = 'client';
9186 * Server Validation Failed
9189 Roo.form.Action.SERVER_INVALID = 'server';
9191 * Connect to Server Failed
9194 Roo.form.Action.CONNECT_FAILURE = 'connect';
9196 * Reading Data from Server Failed
9199 Roo.form.Action.LOAD_FAILURE = 'load';
9201 Roo.form.Action.prototype = {
9203 failureType : undefined,
9204 response : undefined,
9208 run : function(options){
9213 success : function(response){
9218 handleResponse : function(response){
9222 // default connection failure
9223 failure : function(response){
9225 this.response = response;
9226 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9227 this.form.afterAction(this, false);
9230 processResponse : function(response){
9231 this.response = response;
9232 if(!response.responseText){
9235 this.result = this.handleResponse(response);
9239 // utility functions used internally
9240 getUrl : function(appendParams){
9241 var url = this.options.url || this.form.url || this.form.el.dom.action;
9243 var p = this.getParams();
9245 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
9251 getMethod : function(){
9252 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
9255 getParams : function(){
9256 var bp = this.form.baseParams;
9257 var p = this.options.params;
9259 if(typeof p == "object"){
9260 p = Roo.urlEncode(Roo.applyIf(p, bp));
9261 }else if(typeof p == 'string' && bp){
9262 p += '&' + Roo.urlEncode(bp);
9265 p = Roo.urlEncode(bp);
9270 createCallback : function(){
9272 success: this.success,
9273 failure: this.failure,
9275 timeout: (this.form.timeout*1000),
9276 upload: this.form.fileUpload ? this.success : undefined
9281 Roo.form.Action.Submit = function(form, options){
9282 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
9285 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
9288 haveProgress : false,
9289 uploadComplete : false,
9291 // uploadProgress indicator.
9292 uploadProgress : function()
9294 if (!this.form.progressUrl) {
9298 if (!this.haveProgress) {
9299 Roo.MessageBox.progress("Uploading", "Uploading");
9301 if (this.uploadComplete) {
9302 Roo.MessageBox.hide();
9306 this.haveProgress = true;
9308 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
9310 var c = new Roo.data.Connection();
9312 url : this.form.progressUrl,
9317 success : function(req){
9318 //console.log(data);
9322 rdata = Roo.decode(req.responseText)
9324 Roo.log("Invalid data from server..");
9328 if (!rdata || !rdata.success) {
9330 Roo.MessageBox.alert(Roo.encode(rdata));
9333 var data = rdata.data;
9335 if (this.uploadComplete) {
9336 Roo.MessageBox.hide();
9341 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
9342 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
9345 this.uploadProgress.defer(2000,this);
9348 failure: function(data) {
9349 Roo.log('progress url failed ');
9360 // run get Values on the form, so it syncs any secondary forms.
9361 this.form.getValues();
9363 var o = this.options;
9364 var method = this.getMethod();
9365 var isPost = method == 'POST';
9366 if(o.clientValidation === false || this.form.isValid()){
9368 if (this.form.progressUrl) {
9369 this.form.findField('UPLOAD_IDENTIFIER').setValue(
9370 (new Date() * 1) + '' + Math.random());
9375 Roo.Ajax.request(Roo.apply(this.createCallback(), {
9376 form:this.form.el.dom,
9377 url:this.getUrl(!isPost),
9379 params:isPost ? this.getParams() : null,
9380 isUpload: this.form.fileUpload,
9381 formData : this.form.formData
9384 this.uploadProgress();
9386 }else if (o.clientValidation !== false){ // client validation failed
9387 this.failureType = Roo.form.Action.CLIENT_INVALID;
9388 this.form.afterAction(this, false);
9392 success : function(response)
9394 this.uploadComplete= true;
9395 if (this.haveProgress) {
9396 Roo.MessageBox.hide();
9400 var result = this.processResponse(response);
9401 if(result === true || result.success){
9402 this.form.afterAction(this, true);
9406 this.form.markInvalid(result.errors);
9407 this.failureType = Roo.form.Action.SERVER_INVALID;
9409 this.form.afterAction(this, false);
9411 failure : function(response)
9413 this.uploadComplete= true;
9414 if (this.haveProgress) {
9415 Roo.MessageBox.hide();
9418 this.response = response;
9419 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9420 this.form.afterAction(this, false);
9423 handleResponse : function(response){
9424 if(this.form.errorReader){
9425 var rs = this.form.errorReader.read(response);
9428 for(var i = 0, len = rs.records.length; i < len; i++) {
9429 var r = rs.records[i];
9433 if(errors.length < 1){
9437 success : rs.success,
9443 ret = Roo.decode(response.responseText);
9447 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
9457 Roo.form.Action.Load = function(form, options){
9458 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
9459 this.reader = this.form.reader;
9462 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9467 Roo.Ajax.request(Roo.apply(
9468 this.createCallback(), {
9469 method:this.getMethod(),
9470 url:this.getUrl(false),
9471 params:this.getParams()
9475 success : function(response){
9477 var result = this.processResponse(response);
9478 if(result === true || !result.success || !result.data){
9479 this.failureType = Roo.form.Action.LOAD_FAILURE;
9480 this.form.afterAction(this, false);
9483 this.form.clearInvalid();
9484 this.form.setValues(result.data);
9485 this.form.afterAction(this, true);
9488 handleResponse : function(response){
9489 if(this.form.reader){
9490 var rs = this.form.reader.read(response);
9491 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9493 success : rs.success,
9497 return Roo.decode(response.responseText);
9501 Roo.form.Action.ACTION_TYPES = {
9502 'load' : Roo.form.Action.Load,
9503 'submit' : Roo.form.Action.Submit
9512 * @class Roo.bootstrap.Form
9513 * @extends Roo.bootstrap.Component
9514 * Bootstrap Form class
9515 * @cfg {String} method GET | POST (default POST)
9516 * @cfg {String} labelAlign top | left (default top)
9517 * @cfg {String} align left | right - for navbars
9518 * @cfg {Boolean} loadMask load mask when submit (default true)
9523 * @param {Object} config The config object
9527 Roo.bootstrap.Form = function(config){
9529 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9531 Roo.bootstrap.Form.popover.apply();
9535 * @event clientvalidation
9536 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9537 * @param {Form} this
9538 * @param {Boolean} valid true if the form has passed client-side validation
9540 clientvalidation: true,
9542 * @event beforeaction
9543 * Fires before any action is performed. Return false to cancel the action.
9544 * @param {Form} this
9545 * @param {Action} action The action to be performed
9549 * @event actionfailed
9550 * Fires when an action fails.
9551 * @param {Form} this
9552 * @param {Action} action The action that failed
9554 actionfailed : true,
9556 * @event actioncomplete
9557 * Fires when an action is completed.
9558 * @param {Form} this
9559 * @param {Action} action The action that completed
9561 actioncomplete : true
9565 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9568 * @cfg {String} method
9569 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9574 * The URL to use for form actions if one isn't supplied in the action options.
9577 * @cfg {Boolean} fileUpload
9578 * Set to true if this form is a file upload.
9582 * @cfg {Object} baseParams
9583 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9587 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9591 * @cfg {Sting} align (left|right) for navbar forms
9596 activeAction : null,
9599 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9600 * element by passing it or its id or mask the form itself by passing in true.
9603 waitMsgTarget : false,
9608 * @cfg {Boolean} errorMask (true|false) default false
9613 * @cfg {Number} maskOffset Default 100
9618 * @cfg {Boolean} maskBody
9622 getAutoCreate : function(){
9626 method : this.method || 'POST',
9627 id : this.id || Roo.id(),
9630 if (this.parent().xtype.match(/^Nav/)) {
9631 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9635 if (this.labelAlign == 'left' ) {
9636 cfg.cls += ' form-horizontal';
9642 initEvents : function()
9644 this.el.on('submit', this.onSubmit, this);
9645 // this was added as random key presses on the form where triggering form submit.
9646 this.el.on('keypress', function(e) {
9647 if (e.getCharCode() != 13) {
9650 // we might need to allow it for textareas.. and some other items.
9651 // check e.getTarget().
9653 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9657 Roo.log("keypress blocked");
9665 onSubmit : function(e){
9670 * Returns true if client-side validation on the form is successful.
9673 isValid : function(){
9674 var items = this.getItems();
9678 items.each(function(f){
9684 Roo.log('invalid field: ' + f.name);
9688 if(!target && f.el.isVisible(true)){
9694 if(this.errorMask && !valid){
9695 Roo.bootstrap.Form.popover.mask(this, target);
9702 * Returns true if any fields in this form have changed since their original load.
9705 isDirty : function(){
9707 var items = this.getItems();
9708 items.each(function(f){
9718 * Performs a predefined action (submit or load) or custom actions you define on this form.
9719 * @param {String} actionName The name of the action type
9720 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9721 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9722 * accept other config options):
9724 Property Type Description
9725 ---------------- --------------- ----------------------------------------------------------------------------------
9726 url String The url for the action (defaults to the form's url)
9727 method String The form method to use (defaults to the form's method, or POST if not defined)
9728 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9729 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9730 validate the form on the client (defaults to false)
9732 * @return {BasicForm} this
9734 doAction : function(action, options){
9735 if(typeof action == 'string'){
9736 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9738 if(this.fireEvent('beforeaction', this, action) !== false){
9739 this.beforeAction(action);
9740 action.run.defer(100, action);
9746 beforeAction : function(action){
9747 var o = action.options;
9752 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9754 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9757 // not really supported yet.. ??
9759 //if(this.waitMsgTarget === true){
9760 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9761 //}else if(this.waitMsgTarget){
9762 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9763 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9765 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9771 afterAction : function(action, success){
9772 this.activeAction = null;
9773 var o = action.options;
9778 Roo.get(document.body).unmask();
9784 //if(this.waitMsgTarget === true){
9785 // this.el.unmask();
9786 //}else if(this.waitMsgTarget){
9787 // this.waitMsgTarget.unmask();
9789 // Roo.MessageBox.updateProgress(1);
9790 // Roo.MessageBox.hide();
9797 Roo.callback(o.success, o.scope, [this, action]);
9798 this.fireEvent('actioncomplete', this, action);
9802 // failure condition..
9803 // we have a scenario where updates need confirming.
9804 // eg. if a locking scenario exists..
9805 // we look for { errors : { needs_confirm : true }} in the response.
9807 (typeof(action.result) != 'undefined') &&
9808 (typeof(action.result.errors) != 'undefined') &&
9809 (typeof(action.result.errors.needs_confirm) != 'undefined')
9812 Roo.log("not supported yet");
9815 Roo.MessageBox.confirm(
9816 "Change requires confirmation",
9817 action.result.errorMsg,
9822 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9832 Roo.callback(o.failure, o.scope, [this, action]);
9833 // show an error message if no failed handler is set..
9834 if (!this.hasListener('actionfailed')) {
9835 Roo.log("need to add dialog support");
9837 Roo.MessageBox.alert("Error",
9838 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9839 action.result.errorMsg :
9840 "Saving Failed, please check your entries or try again"
9845 this.fireEvent('actionfailed', this, action);
9850 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9851 * @param {String} id The value to search for
9854 findField : function(id){
9855 var items = this.getItems();
9856 var field = items.get(id);
9858 items.each(function(f){
9859 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9866 return field || null;
9869 * Mark fields in this form invalid in bulk.
9870 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9871 * @return {BasicForm} this
9873 markInvalid : function(errors){
9874 if(errors instanceof Array){
9875 for(var i = 0, len = errors.length; i < len; i++){
9876 var fieldError = errors[i];
9877 var f = this.findField(fieldError.id);
9879 f.markInvalid(fieldError.msg);
9885 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9886 field.markInvalid(errors[id]);
9890 //Roo.each(this.childForms || [], function (f) {
9891 // f.markInvalid(errors);
9898 * Set values for fields in this form in bulk.
9899 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9900 * @return {BasicForm} this
9902 setValues : function(values){
9903 if(values instanceof Array){ // array of objects
9904 for(var i = 0, len = values.length; i < len; i++){
9906 var f = this.findField(v.id);
9908 f.setValue(v.value);
9909 if(this.trackResetOnLoad){
9910 f.originalValue = f.getValue();
9914 }else{ // object hash
9917 if(typeof values[id] != 'function' && (field = this.findField(id))){
9919 if (field.setFromData &&
9921 field.displayField &&
9922 // combos' with local stores can
9923 // be queried via setValue()
9924 // to set their value..
9925 (field.store && !field.store.isLocal)
9929 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9930 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9931 field.setFromData(sd);
9933 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9935 field.setFromData(values);
9938 field.setValue(values[id]);
9942 if(this.trackResetOnLoad){
9943 field.originalValue = field.getValue();
9949 //Roo.each(this.childForms || [], function (f) {
9950 // f.setValues(values);
9957 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9958 * they are returned as an array.
9959 * @param {Boolean} asString
9962 getValues : function(asString){
9963 //if (this.childForms) {
9964 // copy values from the child forms
9965 // Roo.each(this.childForms, function (f) {
9966 // this.setValues(f.getValues());
9972 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9973 if(asString === true){
9976 return Roo.urlDecode(fs);
9980 * Returns the fields in this form as an object with key/value pairs.
9981 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9984 getFieldValues : function(with_hidden)
9986 var items = this.getItems();
9988 items.each(function(f){
9994 var v = f.getValue();
9996 if (f.inputType =='radio') {
9997 if (typeof(ret[f.getName()]) == 'undefined') {
9998 ret[f.getName()] = ''; // empty..
10001 if (!f.el.dom.checked) {
10005 v = f.el.dom.value;
10009 if(f.xtype == 'MoneyField'){
10010 ret[f.currencyName] = f.getCurrency();
10013 // not sure if this supported any more..
10014 if ((typeof(v) == 'object') && f.getRawValue) {
10015 v = f.getRawValue() ; // dates..
10017 // combo boxes where name != hiddenName...
10018 if (f.name !== false && f.name != '' && f.name != f.getName()) {
10019 ret[f.name] = f.getRawValue();
10021 ret[f.getName()] = v;
10028 * Clears all invalid messages in this form.
10029 * @return {BasicForm} this
10031 clearInvalid : function(){
10032 var items = this.getItems();
10034 items.each(function(f){
10042 * Resets this form.
10043 * @return {BasicForm} this
10045 reset : function(){
10046 var items = this.getItems();
10047 items.each(function(f){
10051 Roo.each(this.childForms || [], function (f) {
10059 getItems : function()
10061 var r=new Roo.util.MixedCollection(false, function(o){
10062 return o.id || (o.id = Roo.id());
10064 var iter = function(el) {
10071 Roo.each(el.items,function(e) {
10080 hideFields : function(items)
10082 Roo.each(items, function(i){
10084 var f = this.findField(i);
10095 showFields : function(items)
10097 Roo.each(items, function(i){
10099 var f = this.findField(i);
10112 Roo.apply(Roo.bootstrap.Form, {
10128 intervalID : false,
10134 if(this.isApplied){
10139 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
10140 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
10141 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
10142 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
10145 this.maskEl.top.enableDisplayMode("block");
10146 this.maskEl.left.enableDisplayMode("block");
10147 this.maskEl.bottom.enableDisplayMode("block");
10148 this.maskEl.right.enableDisplayMode("block");
10150 this.toolTip = new Roo.bootstrap.Tooltip({
10151 cls : 'roo-form-error-popover',
10153 'left' : ['r-l', [-2,0], 'right'],
10154 'right' : ['l-r', [2,0], 'left'],
10155 'bottom' : ['tl-bl', [0,2], 'top'],
10156 'top' : [ 'bl-tl', [0,-2], 'bottom']
10160 this.toolTip.render(Roo.get(document.body));
10162 this.toolTip.el.enableDisplayMode("block");
10164 Roo.get(document.body).on('click', function(){
10168 Roo.get(document.body).on('touchstart', function(){
10172 this.isApplied = true
10175 mask : function(form, target)
10179 this.target = target;
10181 if(!this.form.errorMask || !target.el){
10185 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
10187 Roo.log(scrollable);
10189 var ot = this.target.el.calcOffsetsTo(scrollable);
10191 var scrollTo = ot[1] - this.form.maskOffset;
10193 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
10195 scrollable.scrollTo('top', scrollTo);
10197 var box = this.target.el.getBox();
10199 var zIndex = Roo.bootstrap.Modal.zIndex++;
10202 this.maskEl.top.setStyle('position', 'absolute');
10203 this.maskEl.top.setStyle('z-index', zIndex);
10204 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
10205 this.maskEl.top.setLeft(0);
10206 this.maskEl.top.setTop(0);
10207 this.maskEl.top.show();
10209 this.maskEl.left.setStyle('position', 'absolute');
10210 this.maskEl.left.setStyle('z-index', zIndex);
10211 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
10212 this.maskEl.left.setLeft(0);
10213 this.maskEl.left.setTop(box.y - this.padding);
10214 this.maskEl.left.show();
10216 this.maskEl.bottom.setStyle('position', 'absolute');
10217 this.maskEl.bottom.setStyle('z-index', zIndex);
10218 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
10219 this.maskEl.bottom.setLeft(0);
10220 this.maskEl.bottom.setTop(box.bottom + this.padding);
10221 this.maskEl.bottom.show();
10223 this.maskEl.right.setStyle('position', 'absolute');
10224 this.maskEl.right.setStyle('z-index', zIndex);
10225 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
10226 this.maskEl.right.setLeft(box.right + this.padding);
10227 this.maskEl.right.setTop(box.y - this.padding);
10228 this.maskEl.right.show();
10230 this.toolTip.bindEl = this.target.el;
10232 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
10234 var tip = this.target.blankText;
10236 if(this.target.getValue() !== '' ) {
10238 if (this.target.invalidText.length) {
10239 tip = this.target.invalidText;
10240 } else if (this.target.regexText.length){
10241 tip = this.target.regexText;
10245 this.toolTip.show(tip);
10247 this.intervalID = window.setInterval(function() {
10248 Roo.bootstrap.Form.popover.unmask();
10251 window.onwheel = function(){ return false;};
10253 (function(){ this.isMasked = true; }).defer(500, this);
10257 unmask : function()
10259 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
10263 this.maskEl.top.setStyle('position', 'absolute');
10264 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
10265 this.maskEl.top.hide();
10267 this.maskEl.left.setStyle('position', 'absolute');
10268 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
10269 this.maskEl.left.hide();
10271 this.maskEl.bottom.setStyle('position', 'absolute');
10272 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
10273 this.maskEl.bottom.hide();
10275 this.maskEl.right.setStyle('position', 'absolute');
10276 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
10277 this.maskEl.right.hide();
10279 this.toolTip.hide();
10281 this.toolTip.el.hide();
10283 window.onwheel = function(){ return true;};
10285 if(this.intervalID){
10286 window.clearInterval(this.intervalID);
10287 this.intervalID = false;
10290 this.isMasked = false;
10300 * Ext JS Library 1.1.1
10301 * Copyright(c) 2006-2007, Ext JS, LLC.
10303 * Originally Released Under LGPL - original licence link has changed is not relivant.
10306 * <script type="text/javascript">
10309 * @class Roo.form.VTypes
10310 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
10313 Roo.form.VTypes = function(){
10314 // closure these in so they are only created once.
10315 var alpha = /^[a-zA-Z_]+$/;
10316 var alphanum = /^[a-zA-Z0-9_]+$/;
10317 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
10318 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
10320 // All these messages and functions are configurable
10323 * The function used to validate email addresses
10324 * @param {String} value The email address
10326 'email' : function(v){
10327 return email.test(v);
10330 * The error text to display when the email validation function returns false
10333 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
10335 * The keystroke filter mask to be applied on email input
10338 'emailMask' : /[a-z0-9_\.\-@]/i,
10341 * The function used to validate URLs
10342 * @param {String} value The URL
10344 'url' : function(v){
10345 return url.test(v);
10348 * The error text to display when the url validation function returns false
10351 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
10354 * The function used to validate alpha values
10355 * @param {String} value The value
10357 'alpha' : function(v){
10358 return alpha.test(v);
10361 * The error text to display when the alpha validation function returns false
10364 'alphaText' : 'This field should only contain letters and _',
10366 * The keystroke filter mask to be applied on alpha input
10369 'alphaMask' : /[a-z_]/i,
10372 * The function used to validate alphanumeric values
10373 * @param {String} value The value
10375 'alphanum' : function(v){
10376 return alphanum.test(v);
10379 * The error text to display when the alphanumeric validation function returns false
10382 'alphanumText' : 'This field should only contain letters, numbers and _',
10384 * The keystroke filter mask to be applied on alphanumeric input
10387 'alphanumMask' : /[a-z0-9_]/i
10397 * @class Roo.bootstrap.Input
10398 * @extends Roo.bootstrap.Component
10399 * Bootstrap Input class
10400 * @cfg {Boolean} disabled is it disabled
10401 * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType
10402 * @cfg {String} name name of the input
10403 * @cfg {string} fieldLabel - the label associated
10404 * @cfg {string} placeholder - placeholder to put in text.
10405 * @cfg {string} before - input group add on before
10406 * @cfg {string} after - input group add on after
10407 * @cfg {string} size - (lg|sm) or leave empty..
10408 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
10409 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
10410 * @cfg {Number} md colspan out of 12 for computer-sized screens
10411 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
10412 * @cfg {string} value default value of the input
10413 * @cfg {Number} labelWidth set the width of label
10414 * @cfg {Number} labellg set the width of label (1-12)
10415 * @cfg {Number} labelmd set the width of label (1-12)
10416 * @cfg {Number} labelsm set the width of label (1-12)
10417 * @cfg {Number} labelxs set the width of label (1-12)
10418 * @cfg {String} labelAlign (top|left)
10419 * @cfg {Boolean} readOnly Specifies that the field should be read-only
10420 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
10421 * @cfg {String} indicatorpos (left|right) default left
10422 * @cfg {String} capture (user|camera) use for file input only. (default empty)
10423 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
10424 * @cfg {Boolean} preventMark Do not show tick or cross if error/success
10426 * @cfg {String} align (left|center|right) Default left
10427 * @cfg {Boolean} forceFeedback (true|false) Default false
10430 * Create a new Input
10431 * @param {Object} config The config object
10434 Roo.bootstrap.Input = function(config){
10436 Roo.bootstrap.Input.superclass.constructor.call(this, config);
10441 * Fires when this field receives input focus.
10442 * @param {Roo.form.Field} this
10447 * Fires when this field loses input focus.
10448 * @param {Roo.form.Field} this
10452 * @event specialkey
10453 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
10454 * {@link Roo.EventObject#getKey} to determine which key was pressed.
10455 * @param {Roo.form.Field} this
10456 * @param {Roo.EventObject} e The event object
10461 * Fires just before the field blurs if the field value has changed.
10462 * @param {Roo.form.Field} this
10463 * @param {Mixed} newValue The new value
10464 * @param {Mixed} oldValue The original value
10469 * Fires after the field has been marked as invalid.
10470 * @param {Roo.form.Field} this
10471 * @param {String} msg The validation message
10476 * Fires after the field has been validated with no errors.
10477 * @param {Roo.form.Field} this
10482 * Fires after the key up
10483 * @param {Roo.form.Field} this
10484 * @param {Roo.EventObject} e The event Object
10490 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10492 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10493 automatic validation (defaults to "keyup").
10495 validationEvent : "keyup",
10497 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10499 validateOnBlur : true,
10501 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10503 validationDelay : 250,
10505 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10507 focusClass : "x-form-focus", // not needed???
10511 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10513 invalidClass : "has-warning",
10516 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10518 validClass : "has-success",
10521 * @cfg {Boolean} hasFeedback (true|false) default true
10523 hasFeedback : true,
10526 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10528 invalidFeedbackClass : "glyphicon-warning-sign",
10531 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10533 validFeedbackClass : "glyphicon-ok",
10536 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10538 selectOnFocus : false,
10541 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10545 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10550 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10552 disableKeyFilter : false,
10555 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10559 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10563 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10565 blankText : "Please complete this mandatory field",
10568 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10572 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10574 maxLength : Number.MAX_VALUE,
10576 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10578 minLengthText : "The minimum length for this field is {0}",
10580 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10582 maxLengthText : "The maximum length for this field is {0}",
10586 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10587 * If available, this function will be called only after the basic validators all return true, and will be passed the
10588 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10592 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10593 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10594 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10598 * @cfg {String} regexText -- Depricated - use Invalid Text
10603 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10609 autocomplete: false,
10613 inputType : 'text',
10616 placeholder: false,
10621 preventMark: false,
10622 isFormField : true,
10625 labelAlign : false,
10628 formatedValue : false,
10629 forceFeedback : false,
10631 indicatorpos : 'left',
10641 parentLabelAlign : function()
10644 while (parent.parent()) {
10645 parent = parent.parent();
10646 if (typeof(parent.labelAlign) !='undefined') {
10647 return parent.labelAlign;
10654 getAutoCreate : function()
10656 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10662 if(this.inputType != 'hidden'){
10663 cfg.cls = 'form-group' //input-group
10669 type : this.inputType,
10670 value : this.value,
10671 cls : 'form-control',
10672 placeholder : this.placeholder || '',
10673 autocomplete : this.autocomplete || 'new-password'
10675 if (this.inputType == 'file') {
10676 input.style = 'overflow:hidden'; // why not in CSS?
10679 if(this.capture.length){
10680 input.capture = this.capture;
10683 if(this.accept.length){
10684 input.accept = this.accept + "/*";
10688 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10691 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10692 input.maxLength = this.maxLength;
10695 if (this.disabled) {
10696 input.disabled=true;
10699 if (this.readOnly) {
10700 input.readonly=true;
10704 input.name = this.name;
10708 input.cls += ' input-' + this.size;
10712 ['xs','sm','md','lg'].map(function(size){
10713 if (settings[size]) {
10714 cfg.cls += ' col-' + size + '-' + settings[size];
10718 var inputblock = input;
10722 cls: 'glyphicon form-control-feedback'
10725 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10728 cls : 'has-feedback',
10736 if (this.before || this.after) {
10739 cls : 'input-group',
10743 if (this.before && typeof(this.before) == 'string') {
10745 inputblock.cn.push({
10747 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10751 if (this.before && typeof(this.before) == 'object') {
10752 this.before = Roo.factory(this.before);
10754 inputblock.cn.push({
10756 cls : 'roo-input-before input-group-prepend input-group-' +
10757 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10761 inputblock.cn.push(input);
10763 if (this.after && typeof(this.after) == 'string') {
10764 inputblock.cn.push({
10766 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10770 if (this.after && typeof(this.after) == 'object') {
10771 this.after = Roo.factory(this.after);
10773 inputblock.cn.push({
10775 cls : 'roo-input-after input-group-append input-group-' +
10776 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10780 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10781 inputblock.cls += ' has-feedback';
10782 inputblock.cn.push(feedback);
10787 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10788 tooltip : 'This field is required'
10790 if (this.allowBlank ) {
10791 indicator.style = this.allowBlank ? ' display:none' : '';
10793 if (align ==='left' && this.fieldLabel.length) {
10795 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10802 cls : 'control-label col-form-label',
10803 html : this.fieldLabel
10814 var labelCfg = cfg.cn[1];
10815 var contentCfg = cfg.cn[2];
10817 if(this.indicatorpos == 'right'){
10822 cls : 'control-label col-form-label',
10826 html : this.fieldLabel
10840 labelCfg = cfg.cn[0];
10841 contentCfg = cfg.cn[1];
10845 if(this.labelWidth > 12){
10846 labelCfg.style = "width: " + this.labelWidth + 'px';
10849 if(this.labelWidth < 13 && this.labelmd == 0){
10850 this.labelmd = this.labelWidth;
10853 if(this.labellg > 0){
10854 labelCfg.cls += ' col-lg-' + this.labellg;
10855 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10858 if(this.labelmd > 0){
10859 labelCfg.cls += ' col-md-' + this.labelmd;
10860 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10863 if(this.labelsm > 0){
10864 labelCfg.cls += ' col-sm-' + this.labelsm;
10865 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10868 if(this.labelxs > 0){
10869 labelCfg.cls += ' col-xs-' + this.labelxs;
10870 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10874 } else if ( this.fieldLabel.length) {
10881 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10882 tooltip : 'This field is required',
10883 style : this.allowBlank ? ' display:none' : ''
10887 //cls : 'input-group-addon',
10888 html : this.fieldLabel
10896 if(this.indicatorpos == 'right'){
10901 //cls : 'input-group-addon',
10902 html : this.fieldLabel
10907 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10908 tooltip : 'This field is required',
10909 style : this.allowBlank ? ' display:none' : ''
10929 if (this.parentType === 'Navbar' && this.parent().bar) {
10930 cfg.cls += ' navbar-form';
10933 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10934 // on BS4 we do this only if not form
10935 cfg.cls += ' navbar-form';
10943 * return the real input element.
10945 inputEl: function ()
10947 return this.el.select('input.form-control',true).first();
10950 tooltipEl : function()
10952 return this.inputEl();
10955 indicatorEl : function()
10957 if (Roo.bootstrap.version == 4) {
10958 return false; // not enabled in v4 yet.
10961 var indicator = this.el.select('i.roo-required-indicator',true).first();
10971 setDisabled : function(v)
10973 var i = this.inputEl().dom;
10975 i.removeAttribute('disabled');
10979 i.setAttribute('disabled','true');
10981 initEvents : function()
10984 this.inputEl().on("keydown" , this.fireKey, this);
10985 this.inputEl().on("focus", this.onFocus, this);
10986 this.inputEl().on("blur", this.onBlur, this);
10988 this.inputEl().relayEvent('keyup', this);
10990 this.indicator = this.indicatorEl();
10992 if(this.indicator){
10993 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10996 // reference to original value for reset
10997 this.originalValue = this.getValue();
10998 //Roo.form.TextField.superclass.initEvents.call(this);
10999 if(this.validationEvent == 'keyup'){
11000 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
11001 this.inputEl().on('keyup', this.filterValidation, this);
11003 else if(this.validationEvent !== false){
11004 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
11007 if(this.selectOnFocus){
11008 this.on("focus", this.preFocus, this);
11011 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
11012 this.inputEl().on("keypress", this.filterKeys, this);
11014 this.inputEl().relayEvent('keypress', this);
11017 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
11018 this.el.on("click", this.autoSize, this);
11021 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
11022 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
11025 if (typeof(this.before) == 'object') {
11026 this.before.render(this.el.select('.roo-input-before',true).first());
11028 if (typeof(this.after) == 'object') {
11029 this.after.render(this.el.select('.roo-input-after',true).first());
11032 this.inputEl().on('change', this.onChange, this);
11035 filterValidation : function(e){
11036 if(!e.isNavKeyPress()){
11037 this.validationTask.delay(this.validationDelay);
11041 * Validates the field value
11042 * @return {Boolean} True if the value is valid, else false
11044 validate : function(){
11045 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
11046 if(this.disabled || this.validateValue(this.getRawValue())){
11051 this.markInvalid();
11057 * Validates a value according to the field's validation rules and marks the field as invalid
11058 * if the validation fails
11059 * @param {Mixed} value The value to validate
11060 * @return {Boolean} True if the value is valid, else false
11062 validateValue : function(value)
11064 if(this.getVisibilityEl().hasClass('hidden')){
11068 if(value.length < 1) { // if it's blank
11069 if(this.allowBlank){
11075 if(value.length < this.minLength){
11078 if(value.length > this.maxLength){
11082 var vt = Roo.form.VTypes;
11083 if(!vt[this.vtype](value, this)){
11087 if(typeof this.validator == "function"){
11088 var msg = this.validator(value);
11092 if (typeof(msg) == 'string') {
11093 this.invalidText = msg;
11097 if(this.regex && !this.regex.test(value)){
11105 fireKey : function(e){
11106 //Roo.log('field ' + e.getKey());
11107 if(e.isNavKeyPress()){
11108 this.fireEvent("specialkey", this, e);
11111 focus : function (selectText){
11113 this.inputEl().focus();
11114 if(selectText === true){
11115 this.inputEl().dom.select();
11121 onFocus : function(){
11122 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11123 // this.el.addClass(this.focusClass);
11125 if(!this.hasFocus){
11126 this.hasFocus = true;
11127 this.startValue = this.getValue();
11128 this.fireEvent("focus", this);
11132 beforeBlur : Roo.emptyFn,
11136 onBlur : function(){
11138 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11139 //this.el.removeClass(this.focusClass);
11141 this.hasFocus = false;
11142 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
11145 var v = this.getValue();
11146 if(String(v) !== String(this.startValue)){
11147 this.fireEvent('change', this, v, this.startValue);
11149 this.fireEvent("blur", this);
11152 onChange : function(e)
11154 var v = this.getValue();
11155 if(String(v) !== String(this.startValue)){
11156 this.fireEvent('change', this, v, this.startValue);
11162 * Resets the current field value to the originally loaded value and clears any validation messages
11164 reset : function(){
11165 this.setValue(this.originalValue);
11169 * Returns the name of the field
11170 * @return {Mixed} name The name field
11172 getName: function(){
11176 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11177 * @return {Mixed} value The field value
11179 getValue : function(){
11181 var v = this.inputEl().getValue();
11186 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
11187 * @return {Mixed} value The field value
11189 getRawValue : function(){
11190 var v = this.inputEl().getValue();
11196 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
11197 * @param {Mixed} value The value to set
11199 setRawValue : function(v){
11200 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11203 selectText : function(start, end){
11204 var v = this.getRawValue();
11206 start = start === undefined ? 0 : start;
11207 end = end === undefined ? v.length : end;
11208 var d = this.inputEl().dom;
11209 if(d.setSelectionRange){
11210 d.setSelectionRange(start, end);
11211 }else if(d.createTextRange){
11212 var range = d.createTextRange();
11213 range.moveStart("character", start);
11214 range.moveEnd("character", v.length-end);
11221 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
11222 * @param {Mixed} value The value to set
11224 setValue : function(v){
11227 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11233 processValue : function(value){
11234 if(this.stripCharsRe){
11235 var newValue = value.replace(this.stripCharsRe, '');
11236 if(newValue !== value){
11237 this.setRawValue(newValue);
11244 preFocus : function(){
11246 if(this.selectOnFocus){
11247 this.inputEl().dom.select();
11250 filterKeys : function(e){
11251 var k = e.getKey();
11252 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
11255 var c = e.getCharCode(), cc = String.fromCharCode(c);
11256 if(Roo.isIE && (e.isSpecialKey() || !cc)){
11259 if(!this.maskRe.test(cc)){
11264 * Clear any invalid styles/messages for this field
11266 clearInvalid : function(){
11268 if(!this.el || this.preventMark){ // not rendered
11273 this.el.removeClass([this.invalidClass, 'is-invalid']);
11275 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11277 var feedback = this.el.select('.form-control-feedback', true).first();
11280 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11285 if(this.indicator){
11286 this.indicator.removeClass('visible');
11287 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11290 this.fireEvent('valid', this);
11294 * Mark this field as valid
11296 markValid : function()
11298 if(!this.el || this.preventMark){ // not rendered...
11302 this.el.removeClass([this.invalidClass, this.validClass]);
11303 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11305 var feedback = this.el.select('.form-control-feedback', true).first();
11308 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11311 if(this.indicator){
11312 this.indicator.removeClass('visible');
11313 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11321 if(this.allowBlank && !this.getRawValue().length){
11324 if (Roo.bootstrap.version == 3) {
11325 this.el.addClass(this.validClass);
11327 this.inputEl().addClass('is-valid');
11330 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11332 var feedback = this.el.select('.form-control-feedback', true).first();
11335 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11336 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11341 this.fireEvent('valid', this);
11345 * Mark this field as invalid
11346 * @param {String} msg The validation message
11348 markInvalid : function(msg)
11350 if(!this.el || this.preventMark){ // not rendered
11354 this.el.removeClass([this.invalidClass, this.validClass]);
11355 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11357 var feedback = this.el.select('.form-control-feedback', true).first();
11360 this.el.select('.form-control-feedback', true).first().removeClass(
11361 [this.invalidFeedbackClass, this.validFeedbackClass]);
11368 if(this.allowBlank && !this.getRawValue().length){
11372 if(this.indicator){
11373 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11374 this.indicator.addClass('visible');
11376 if (Roo.bootstrap.version == 3) {
11377 this.el.addClass(this.invalidClass);
11379 this.inputEl().addClass('is-invalid');
11384 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11386 var feedback = this.el.select('.form-control-feedback', true).first();
11389 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11391 if(this.getValue().length || this.forceFeedback){
11392 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11399 this.fireEvent('invalid', this, msg);
11402 SafariOnKeyDown : function(event)
11404 // this is a workaround for a password hang bug on chrome/ webkit.
11405 if (this.inputEl().dom.type != 'password') {
11409 var isSelectAll = false;
11411 if(this.inputEl().dom.selectionEnd > 0){
11412 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
11414 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
11415 event.preventDefault();
11420 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
11422 event.preventDefault();
11423 // this is very hacky as keydown always get's upper case.
11425 var cc = String.fromCharCode(event.getCharCode());
11426 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
11430 adjustWidth : function(tag, w){
11431 tag = tag.toLowerCase();
11432 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
11433 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
11434 if(tag == 'input'){
11437 if(tag == 'textarea'){
11440 }else if(Roo.isOpera){
11441 if(tag == 'input'){
11444 if(tag == 'textarea'){
11452 setFieldLabel : function(v)
11454 if(!this.rendered){
11458 if(this.indicatorEl()){
11459 var ar = this.el.select('label > span',true);
11461 if (ar.elements.length) {
11462 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11463 this.fieldLabel = v;
11467 var br = this.el.select('label',true);
11469 if(br.elements.length) {
11470 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11471 this.fieldLabel = v;
11475 Roo.log('Cannot Found any of label > span || label in input');
11479 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11480 this.fieldLabel = v;
11495 * @class Roo.bootstrap.TextArea
11496 * @extends Roo.bootstrap.Input
11497 * Bootstrap TextArea class
11498 * @cfg {Number} cols Specifies the visible width of a text area
11499 * @cfg {Number} rows Specifies the visible number of lines in a text area
11500 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11501 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11502 * @cfg {string} html text
11505 * Create a new TextArea
11506 * @param {Object} config The config object
11509 Roo.bootstrap.TextArea = function(config){
11510 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11514 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11524 getAutoCreate : function(){
11526 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11532 if(this.inputType != 'hidden'){
11533 cfg.cls = 'form-group' //input-group
11541 value : this.value || '',
11542 html: this.html || '',
11543 cls : 'form-control',
11544 placeholder : this.placeholder || ''
11548 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11549 input.maxLength = this.maxLength;
11553 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11557 input.cols = this.cols;
11560 if (this.readOnly) {
11561 input.readonly = true;
11565 input.name = this.name;
11569 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11573 ['xs','sm','md','lg'].map(function(size){
11574 if (settings[size]) {
11575 cfg.cls += ' col-' + size + '-' + settings[size];
11579 var inputblock = input;
11581 if(this.hasFeedback && !this.allowBlank){
11585 cls: 'glyphicon form-control-feedback'
11589 cls : 'has-feedback',
11598 if (this.before || this.after) {
11601 cls : 'input-group',
11605 inputblock.cn.push({
11607 cls : 'input-group-addon',
11612 inputblock.cn.push(input);
11614 if(this.hasFeedback && !this.allowBlank){
11615 inputblock.cls += ' has-feedback';
11616 inputblock.cn.push(feedback);
11620 inputblock.cn.push({
11622 cls : 'input-group-addon',
11629 if (align ==='left' && this.fieldLabel.length) {
11634 cls : 'control-label',
11635 html : this.fieldLabel
11646 if(this.labelWidth > 12){
11647 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11650 if(this.labelWidth < 13 && this.labelmd == 0){
11651 this.labelmd = this.labelWidth;
11654 if(this.labellg > 0){
11655 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11656 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11659 if(this.labelmd > 0){
11660 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11661 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11664 if(this.labelsm > 0){
11665 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11666 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11669 if(this.labelxs > 0){
11670 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11671 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11674 } else if ( this.fieldLabel.length) {
11679 //cls : 'input-group-addon',
11680 html : this.fieldLabel
11698 if (this.disabled) {
11699 input.disabled=true;
11706 * return the real textarea element.
11708 inputEl: function ()
11710 return this.el.select('textarea.form-control',true).first();
11714 * Clear any invalid styles/messages for this field
11716 clearInvalid : function()
11719 if(!this.el || this.preventMark){ // not rendered
11723 var label = this.el.select('label', true).first();
11724 var icon = this.el.select('i.fa-star', true).first();
11729 this.el.removeClass( this.validClass);
11730 this.inputEl().removeClass('is-invalid');
11732 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11734 var feedback = this.el.select('.form-control-feedback', true).first();
11737 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11742 this.fireEvent('valid', this);
11746 * Mark this field as valid
11748 markValid : function()
11750 if(!this.el || this.preventMark){ // not rendered
11754 this.el.removeClass([this.invalidClass, this.validClass]);
11755 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11757 var feedback = this.el.select('.form-control-feedback', true).first();
11760 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11763 if(this.disabled || this.allowBlank){
11767 var label = this.el.select('label', true).first();
11768 var icon = this.el.select('i.fa-star', true).first();
11773 if (Roo.bootstrap.version == 3) {
11774 this.el.addClass(this.validClass);
11776 this.inputEl().addClass('is-valid');
11780 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11782 var feedback = this.el.select('.form-control-feedback', true).first();
11785 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11786 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11791 this.fireEvent('valid', this);
11795 * Mark this field as invalid
11796 * @param {String} msg The validation message
11798 markInvalid : function(msg)
11800 if(!this.el || this.preventMark){ // not rendered
11804 this.el.removeClass([this.invalidClass, this.validClass]);
11805 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11807 var feedback = this.el.select('.form-control-feedback', true).first();
11810 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11813 if(this.disabled || this.allowBlank){
11817 var label = this.el.select('label', true).first();
11818 var icon = this.el.select('i.fa-star', true).first();
11820 if(!this.getValue().length && label && !icon){
11821 this.el.createChild({
11823 cls : 'text-danger fa fa-lg fa-star',
11824 tooltip : 'This field is required',
11825 style : 'margin-right:5px;'
11829 if (Roo.bootstrap.version == 3) {
11830 this.el.addClass(this.invalidClass);
11832 this.inputEl().addClass('is-invalid');
11835 // fixme ... this may be depricated need to test..
11836 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11838 var feedback = this.el.select('.form-control-feedback', true).first();
11841 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11843 if(this.getValue().length || this.forceFeedback){
11844 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11851 this.fireEvent('invalid', this, msg);
11859 * trigger field - base class for combo..
11864 * @class Roo.bootstrap.TriggerField
11865 * @extends Roo.bootstrap.Input
11866 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11867 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11868 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11869 * for which you can provide a custom implementation. For example:
11871 var trigger = new Roo.bootstrap.TriggerField();
11872 trigger.onTriggerClick = myTriggerFn;
11873 trigger.applyTo('my-field');
11876 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11877 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11878 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11879 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11880 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11883 * Create a new TriggerField.
11884 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11885 * to the base TextField)
11887 Roo.bootstrap.TriggerField = function(config){
11888 this.mimicing = false;
11889 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11892 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11894 * @cfg {String} triggerClass A CSS class to apply to the trigger
11897 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11902 * @cfg {Boolean} removable (true|false) special filter default false
11906 /** @cfg {Boolean} grow @hide */
11907 /** @cfg {Number} growMin @hide */
11908 /** @cfg {Number} growMax @hide */
11914 autoSize: Roo.emptyFn,
11918 deferHeight : true,
11921 actionMode : 'wrap',
11926 getAutoCreate : function(){
11928 var align = this.labelAlign || this.parentLabelAlign();
11933 cls: 'form-group' //input-group
11940 type : this.inputType,
11941 cls : 'form-control',
11942 autocomplete: 'new-password',
11943 placeholder : this.placeholder || ''
11947 input.name = this.name;
11950 input.cls += ' input-' + this.size;
11953 if (this.disabled) {
11954 input.disabled=true;
11957 var inputblock = input;
11959 if(this.hasFeedback && !this.allowBlank){
11963 cls: 'glyphicon form-control-feedback'
11966 if(this.removable && !this.editable ){
11968 cls : 'has-feedback',
11974 cls : 'roo-combo-removable-btn close'
11981 cls : 'has-feedback',
11990 if(this.removable && !this.editable ){
11992 cls : 'roo-removable',
11998 cls : 'roo-combo-removable-btn close'
12005 if (this.before || this.after) {
12008 cls : 'input-group',
12012 inputblock.cn.push({
12014 cls : 'input-group-addon input-group-prepend input-group-text',
12019 inputblock.cn.push(input);
12021 if(this.hasFeedback && !this.allowBlank){
12022 inputblock.cls += ' has-feedback';
12023 inputblock.cn.push(feedback);
12027 inputblock.cn.push({
12029 cls : 'input-group-addon input-group-append input-group-text',
12038 var ibwrap = inputblock;
12043 cls: 'roo-select2-choices',
12047 cls: 'roo-select2-search-field',
12059 cls: 'roo-select2-container input-group',
12064 cls: 'form-hidden-field'
12070 if(!this.multiple && this.showToggleBtn){
12076 if (this.caret != false) {
12079 cls: 'fa fa-' + this.caret
12086 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
12088 Roo.bootstrap.version == 3 ? caret : '',
12091 cls: 'combobox-clear',
12105 combobox.cls += ' roo-select2-container-multi';
12109 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
12110 tooltip : 'This field is required'
12112 if (Roo.bootstrap.version == 4) {
12115 style : 'display:none'
12120 if (align ==='left' && this.fieldLabel.length) {
12122 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
12129 cls : 'control-label',
12130 html : this.fieldLabel
12142 var labelCfg = cfg.cn[1];
12143 var contentCfg = cfg.cn[2];
12145 if(this.indicatorpos == 'right'){
12150 cls : 'control-label',
12154 html : this.fieldLabel
12168 labelCfg = cfg.cn[0];
12169 contentCfg = cfg.cn[1];
12172 if(this.labelWidth > 12){
12173 labelCfg.style = "width: " + this.labelWidth + 'px';
12176 if(this.labelWidth < 13 && this.labelmd == 0){
12177 this.labelmd = this.labelWidth;
12180 if(this.labellg > 0){
12181 labelCfg.cls += ' col-lg-' + this.labellg;
12182 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12185 if(this.labelmd > 0){
12186 labelCfg.cls += ' col-md-' + this.labelmd;
12187 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12190 if(this.labelsm > 0){
12191 labelCfg.cls += ' col-sm-' + this.labelsm;
12192 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12195 if(this.labelxs > 0){
12196 labelCfg.cls += ' col-xs-' + this.labelxs;
12197 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12200 } else if ( this.fieldLabel.length) {
12201 // Roo.log(" label");
12206 //cls : 'input-group-addon',
12207 html : this.fieldLabel
12215 if(this.indicatorpos == 'right'){
12223 html : this.fieldLabel
12237 // Roo.log(" no label && no align");
12244 ['xs','sm','md','lg'].map(function(size){
12245 if (settings[size]) {
12246 cfg.cls += ' col-' + size + '-' + settings[size];
12257 onResize : function(w, h){
12258 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
12259 // if(typeof w == 'number'){
12260 // var x = w - this.trigger.getWidth();
12261 // this.inputEl().setWidth(this.adjustWidth('input', x));
12262 // this.trigger.setStyle('left', x+'px');
12267 adjustSize : Roo.BoxComponent.prototype.adjustSize,
12270 getResizeEl : function(){
12271 return this.inputEl();
12275 getPositionEl : function(){
12276 return this.inputEl();
12280 alignErrorIcon : function(){
12281 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
12285 initEvents : function(){
12289 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
12290 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
12291 if(!this.multiple && this.showToggleBtn){
12292 this.trigger = this.el.select('span.dropdown-toggle',true).first();
12293 if(this.hideTrigger){
12294 this.trigger.setDisplayed(false);
12296 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
12300 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
12303 if(this.removable && !this.editable && !this.tickable){
12304 var close = this.closeTriggerEl();
12307 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
12308 close.on('click', this.removeBtnClick, this, close);
12312 //this.trigger.addClassOnOver('x-form-trigger-over');
12313 //this.trigger.addClassOnClick('x-form-trigger-click');
12316 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
12320 closeTriggerEl : function()
12322 var close = this.el.select('.roo-combo-removable-btn', true).first();
12323 return close ? close : false;
12326 removeBtnClick : function(e, h, el)
12328 e.preventDefault();
12330 if(this.fireEvent("remove", this) !== false){
12332 this.fireEvent("afterremove", this)
12336 createList : function()
12338 this.list = Roo.get(document.body).createChild({
12339 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
12340 cls: 'typeahead typeahead-long dropdown-menu',
12341 style: 'display:none'
12344 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
12349 initTrigger : function(){
12354 onDestroy : function(){
12356 this.trigger.removeAllListeners();
12357 // this.trigger.remove();
12360 // this.wrap.remove();
12362 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
12366 onFocus : function(){
12367 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
12369 if(!this.mimicing){
12370 this.wrap.addClass('x-trigger-wrap-focus');
12371 this.mimicing = true;
12372 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
12373 if(this.monitorTab){
12374 this.el.on("keydown", this.checkTab, this);
12381 checkTab : function(e){
12382 if(e.getKey() == e.TAB){
12383 this.triggerBlur();
12388 onBlur : function(){
12393 mimicBlur : function(e, t){
12395 if(!this.wrap.contains(t) && this.validateBlur()){
12396 this.triggerBlur();
12402 triggerBlur : function(){
12403 this.mimicing = false;
12404 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
12405 if(this.monitorTab){
12406 this.el.un("keydown", this.checkTab, this);
12408 //this.wrap.removeClass('x-trigger-wrap-focus');
12409 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
12413 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
12414 validateBlur : function(e, t){
12419 onDisable : function(){
12420 this.inputEl().dom.disabled = true;
12421 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
12423 // this.wrap.addClass('x-item-disabled');
12428 onEnable : function(){
12429 this.inputEl().dom.disabled = false;
12430 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
12432 // this.el.removeClass('x-item-disabled');
12437 onShow : function(){
12438 var ae = this.getActionEl();
12441 ae.dom.style.display = '';
12442 ae.dom.style.visibility = 'visible';
12448 onHide : function(){
12449 var ae = this.getActionEl();
12450 ae.dom.style.display = 'none';
12454 * The function that should handle the trigger's click event. This method does nothing by default until overridden
12455 * by an implementing function.
12457 * @param {EventObject} e
12459 onTriggerClick : Roo.emptyFn
12467 * @class Roo.bootstrap.CardUploader
12468 * @extends Roo.bootstrap.Button
12469 * Bootstrap Card Uploader class - it's a button which when you add files to it, adds cards below with preview and the name...
12470 * @cfg {Number} errorTimeout default 3000
12471 * @cfg {Array} images an array of ?? Img objects ??? when loading existing files..
12472 * @cfg {Array} html The button text.
12476 * Create a new CardUploader
12477 * @param {Object} config The config object
12480 Roo.bootstrap.CardUploader = function(config){
12484 Roo.bootstrap.CardUploader.superclass.constructor.call(this, config);
12487 this.fileCollection = new Roo.util.MixedCollection(false,function(r) {
12494 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input, {
12497 errorTimeout : 3000,
12501 fileCollection : false,
12504 getAutoCreate : function()
12508 cls :'form-group' ,
12513 //cls : 'input-group-addon',
12514 html : this.fieldLabel
12521 value : this.value,
12522 cls : 'd-none form-control'
12527 multiple : 'multiple',
12529 cls : 'd-none roo-card-upload-selector'
12533 cls : 'roo-card-uploader-button-container w-100 mb-2'
12536 cls : 'card-columns roo-card-uploader-container'
12546 getChildContainer : function() /// what children are added to.
12548 return this.containerEl;
12551 getButtonContainer : function() /// what children are added to.
12553 return this.el.select(".roo-card-uploader-button-container").first();
12556 initEvents : function()
12559 Roo.bootstrap.Input.prototype.initEvents.call(this);
12563 xns: Roo.bootstrap,
12566 container_method : 'getButtonContainer' ,
12567 html : this.html, // fix changable?
12570 'click' : function(btn, e) {
12579 this.urlAPI = (window.createObjectURL && window) ||
12580 (window.URL && URL.revokeObjectURL && URL) ||
12581 (window.webkitURL && webkitURL);
12586 this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
12588 this.selectorEl.on('change', this.onFileSelected, this);
12591 this.images.forEach(function(img) {
12594 this.images = false;
12596 this.containerEl = this.el.select('.roo-card-uploader-container', true).first();
12602 onClick : function(e)
12604 e.preventDefault();
12606 this.selectorEl.dom.click();
12610 onFileSelected : function(e)
12612 e.preventDefault();
12614 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
12618 Roo.each(this.selectorEl.dom.files, function(file){
12619 this.addFile(file);
12628 addFile : function(file)
12631 if(typeof(file) === 'string'){
12632 throw "Add file by name?"; // should not happen
12636 if(!file || !this.urlAPI){
12646 var url = _this.urlAPI.createObjectURL( file);
12649 id : Roo.bootstrap.CardUploader.ID--,
12650 is_uploaded : false,
12653 mimetype : file.type,
12660 addCard : function (data)
12662 // hidden input element?
12663 // if the file is not an image...
12664 //then we need to use something other that and header_image
12669 xns : Roo.bootstrap,
12670 xtype : 'CardFooter',
12673 xns : Roo.bootstrap,
12679 xns : Roo.bootstrap,
12681 html : String.format("<small>{0}</small>", data.title),
12682 cls : 'col-11 text-left',
12687 click : function() {
12688 this.downloadCard(data.id)
12694 xns : Roo.bootstrap,
12702 click : function() {
12703 t.removeCard(data.id)
12715 var cn = this.addxtype(
12718 xns : Roo.bootstrap,
12721 header : !data.mimetype.match(/image/) && !data.preview ? "Document": false,
12722 header_image : data.mimetype.match(/image/) ? data.src : data.preview,
12723 header_image_fit_square: true, // fixme - we probably need to use the 'Img' element to do stuff like this.
12728 initEvents : function() {
12729 Roo.bootstrap.Card.prototype.initEvents.call(this);
12730 this.imgEl = this.el.select('.card-img-top').first();
12732 this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
12733 this.imgEl.set({ 'pointer' : 'cursor' });
12742 // dont' really need ot update items.
12743 // this.items.push(cn);
12744 this.fileCollection.add(cn);
12745 this.updateInput();
12748 removeCard : function(id)
12751 var card = this.fileCollection.get(id);
12752 card.data.is_deleted = 1;
12753 card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
12754 this.fileCollection.remove(card);
12755 //this.items = this.items.filter(function(e) { return e != card });
12756 // dont' really need ot update items.
12757 card.el.dom.parentNode.removeChild(card.el.dom);
12762 this.fileCollection.each(function(card) {
12763 card.el.dom.parentNode.removeChild(card.el.dom);
12765 this.fileCollection.clear();
12766 this.updateInput();
12769 updateInput : function()
12772 this.fileCollection.each(function(e) {
12776 this.inputEl().dom.value = JSON.stringify(data);
12783 Roo.bootstrap.CardUploader.ID = -1;/*
12785 * Ext JS Library 1.1.1
12786 * Copyright(c) 2006-2007, Ext JS, LLC.
12788 * Originally Released Under LGPL - original licence link has changed is not relivant.
12791 * <script type="text/javascript">
12796 * @class Roo.data.SortTypes
12798 * Defines the default sorting (casting?) comparison functions used when sorting data.
12800 Roo.data.SortTypes = {
12802 * Default sort that does nothing
12803 * @param {Mixed} s The value being converted
12804 * @return {Mixed} The comparison value
12806 none : function(s){
12811 * The regular expression used to strip tags
12815 stripTagsRE : /<\/?[^>]+>/gi,
12818 * Strips all HTML tags to sort on text only
12819 * @param {Mixed} s The value being converted
12820 * @return {String} The comparison value
12822 asText : function(s){
12823 return String(s).replace(this.stripTagsRE, "");
12827 * Strips all HTML tags to sort on text only - Case insensitive
12828 * @param {Mixed} s The value being converted
12829 * @return {String} The comparison value
12831 asUCText : function(s){
12832 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12836 * Case insensitive string
12837 * @param {Mixed} s The value being converted
12838 * @return {String} The comparison value
12840 asUCString : function(s) {
12841 return String(s).toUpperCase();
12846 * @param {Mixed} s The value being converted
12847 * @return {Number} The comparison value
12849 asDate : function(s) {
12853 if(s instanceof Date){
12854 return s.getTime();
12856 return Date.parse(String(s));
12861 * @param {Mixed} s The value being converted
12862 * @return {Float} The comparison value
12864 asFloat : function(s) {
12865 var val = parseFloat(String(s).replace(/,/g, ""));
12874 * @param {Mixed} s The value being converted
12875 * @return {Number} The comparison value
12877 asInt : function(s) {
12878 var val = parseInt(String(s).replace(/,/g, ""));
12886 * Ext JS Library 1.1.1
12887 * Copyright(c) 2006-2007, Ext JS, LLC.
12889 * Originally Released Under LGPL - original licence link has changed is not relivant.
12892 * <script type="text/javascript">
12896 * @class Roo.data.Record
12897 * Instances of this class encapsulate both record <em>definition</em> information, and record
12898 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12899 * to access Records cached in an {@link Roo.data.Store} object.<br>
12901 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12902 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12905 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12907 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12908 * {@link #create}. The parameters are the same.
12909 * @param {Array} data An associative Array of data values keyed by the field name.
12910 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12911 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12912 * not specified an integer id is generated.
12914 Roo.data.Record = function(data, id){
12915 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12920 * Generate a constructor for a specific record layout.
12921 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12922 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12923 * Each field definition object may contain the following properties: <ul>
12924 * <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,
12925 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12926 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12927 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12928 * is being used, then this is a string containing the javascript expression to reference the data relative to
12929 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12930 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12931 * this may be omitted.</p></li>
12932 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12933 * <ul><li>auto (Default, implies no conversion)</li>
12938 * <li>date</li></ul></p></li>
12939 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12940 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12941 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12942 * by the Reader into an object that will be stored in the Record. It is passed the
12943 * following parameters:<ul>
12944 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12946 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12948 * <br>usage:<br><pre><code>
12949 var TopicRecord = Roo.data.Record.create(
12950 {name: 'title', mapping: 'topic_title'},
12951 {name: 'author', mapping: 'username'},
12952 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12953 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12954 {name: 'lastPoster', mapping: 'user2'},
12955 {name: 'excerpt', mapping: 'post_text'}
12958 var myNewRecord = new TopicRecord({
12959 title: 'Do my job please',
12962 lastPost: new Date(),
12963 lastPoster: 'Animal',
12964 excerpt: 'No way dude!'
12966 myStore.add(myNewRecord);
12971 Roo.data.Record.create = function(o){
12972 var f = function(){
12973 f.superclass.constructor.apply(this, arguments);
12975 Roo.extend(f, Roo.data.Record);
12976 var p = f.prototype;
12977 p.fields = new Roo.util.MixedCollection(false, function(field){
12980 for(var i = 0, len = o.length; i < len; i++){
12981 p.fields.add(new Roo.data.Field(o[i]));
12983 f.getField = function(name){
12984 return p.fields.get(name);
12989 Roo.data.Record.AUTO_ID = 1000;
12990 Roo.data.Record.EDIT = 'edit';
12991 Roo.data.Record.REJECT = 'reject';
12992 Roo.data.Record.COMMIT = 'commit';
12994 Roo.data.Record.prototype = {
12996 * Readonly flag - true if this record has been modified.
13005 join : function(store){
13006 this.store = store;
13010 * Set the named field to the specified value.
13011 * @param {String} name The name of the field to set.
13012 * @param {Object} value The value to set the field to.
13014 set : function(name, value){
13015 if(this.data[name] == value){
13019 if(!this.modified){
13020 this.modified = {};
13022 if(typeof this.modified[name] == 'undefined'){
13023 this.modified[name] = this.data[name];
13025 this.data[name] = value;
13026 if(!this.editing && this.store){
13027 this.store.afterEdit(this);
13032 * Get the value of the named field.
13033 * @param {String} name The name of the field to get the value of.
13034 * @return {Object} The value of the field.
13036 get : function(name){
13037 return this.data[name];
13041 beginEdit : function(){
13042 this.editing = true;
13043 this.modified = {};
13047 cancelEdit : function(){
13048 this.editing = false;
13049 delete this.modified;
13053 endEdit : function(){
13054 this.editing = false;
13055 if(this.dirty && this.store){
13056 this.store.afterEdit(this);
13061 * Usually called by the {@link Roo.data.Store} which owns the Record.
13062 * Rejects all changes made to the Record since either creation, or the last commit operation.
13063 * Modified fields are reverted to their original values.
13065 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
13066 * of reject operations.
13068 reject : function(){
13069 var m = this.modified;
13071 if(typeof m[n] != "function"){
13072 this.data[n] = m[n];
13075 this.dirty = false;
13076 delete this.modified;
13077 this.editing = false;
13079 this.store.afterReject(this);
13084 * Usually called by the {@link Roo.data.Store} which owns the Record.
13085 * Commits all changes made to the Record since either creation, or the last commit operation.
13087 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
13088 * of commit operations.
13090 commit : function(){
13091 this.dirty = false;
13092 delete this.modified;
13093 this.editing = false;
13095 this.store.afterCommit(this);
13100 hasError : function(){
13101 return this.error != null;
13105 clearError : function(){
13110 * Creates a copy of this record.
13111 * @param {String} id (optional) A new record id if you don't want to use this record's id
13114 copy : function(newId) {
13115 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
13119 * Ext JS Library 1.1.1
13120 * Copyright(c) 2006-2007, Ext JS, LLC.
13122 * Originally Released Under LGPL - original licence link has changed is not relivant.
13125 * <script type="text/javascript">
13131 * @class Roo.data.Store
13132 * @extends Roo.util.Observable
13133 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
13134 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
13136 * 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
13137 * has no knowledge of the format of the data returned by the Proxy.<br>
13139 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
13140 * instances from the data object. These records are cached and made available through accessor functions.
13142 * Creates a new Store.
13143 * @param {Object} config A config object containing the objects needed for the Store to access data,
13144 * and read the data into Records.
13146 Roo.data.Store = function(config){
13147 this.data = new Roo.util.MixedCollection(false);
13148 this.data.getKey = function(o){
13151 this.baseParams = {};
13153 this.paramNames = {
13158 "multisort" : "_multisort"
13161 if(config && config.data){
13162 this.inlineData = config.data;
13163 delete config.data;
13166 Roo.apply(this, config);
13168 if(this.reader){ // reader passed
13169 this.reader = Roo.factory(this.reader, Roo.data);
13170 this.reader.xmodule = this.xmodule || false;
13171 if(!this.recordType){
13172 this.recordType = this.reader.recordType;
13174 if(this.reader.onMetaChange){
13175 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
13179 if(this.recordType){
13180 this.fields = this.recordType.prototype.fields;
13182 this.modified = [];
13186 * @event datachanged
13187 * Fires when the data cache has changed, and a widget which is using this Store
13188 * as a Record cache should refresh its view.
13189 * @param {Store} this
13191 datachanged : true,
13193 * @event metachange
13194 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
13195 * @param {Store} this
13196 * @param {Object} meta The JSON metadata
13201 * Fires when Records have been added to the Store
13202 * @param {Store} this
13203 * @param {Roo.data.Record[]} records The array of Records added
13204 * @param {Number} index The index at which the record(s) were added
13209 * Fires when a Record has been removed from the Store
13210 * @param {Store} this
13211 * @param {Roo.data.Record} record The Record that was removed
13212 * @param {Number} index The index at which the record was removed
13217 * Fires when a Record has been updated
13218 * @param {Store} this
13219 * @param {Roo.data.Record} record The Record that was updated
13220 * @param {String} operation The update operation being performed. Value may be one of:
13222 Roo.data.Record.EDIT
13223 Roo.data.Record.REJECT
13224 Roo.data.Record.COMMIT
13230 * Fires when the data cache has been cleared.
13231 * @param {Store} this
13235 * @event beforeload
13236 * Fires before a request is made for a new data object. If the beforeload handler returns false
13237 * the load action will be canceled.
13238 * @param {Store} this
13239 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13243 * @event beforeloadadd
13244 * Fires after a new set of Records has been loaded.
13245 * @param {Store} this
13246 * @param {Roo.data.Record[]} records The Records that were loaded
13247 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13249 beforeloadadd : true,
13252 * Fires after a new set of Records has been loaded, before they are added to the store.
13253 * @param {Store} this
13254 * @param {Roo.data.Record[]} records The Records that were loaded
13255 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13256 * @params {Object} return from reader
13260 * @event loadexception
13261 * Fires if an exception occurs in the Proxy during loading.
13262 * Called with the signature of the Proxy's "loadexception" event.
13263 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
13266 * @param {Object} return from JsonData.reader() - success, totalRecords, records
13267 * @param {Object} load options
13268 * @param {Object} jsonData from your request (normally this contains the Exception)
13270 loadexception : true
13274 this.proxy = Roo.factory(this.proxy, Roo.data);
13275 this.proxy.xmodule = this.xmodule || false;
13276 this.relayEvents(this.proxy, ["loadexception"]);
13278 this.sortToggle = {};
13279 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
13281 Roo.data.Store.superclass.constructor.call(this);
13283 if(this.inlineData){
13284 this.loadData(this.inlineData);
13285 delete this.inlineData;
13289 Roo.extend(Roo.data.Store, Roo.util.Observable, {
13291 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
13292 * without a remote query - used by combo/forms at present.
13296 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
13299 * @cfg {Array} data Inline data to be loaded when the store is initialized.
13302 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
13303 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
13306 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
13307 * on any HTTP request
13310 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
13313 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
13317 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
13318 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
13320 remoteSort : false,
13323 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
13324 * loaded or when a record is removed. (defaults to false).
13326 pruneModifiedRecords : false,
13329 lastOptions : null,
13332 * Add Records to the Store and fires the add event.
13333 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13335 add : function(records){
13336 records = [].concat(records);
13337 for(var i = 0, len = records.length; i < len; i++){
13338 records[i].join(this);
13340 var index = this.data.length;
13341 this.data.addAll(records);
13342 this.fireEvent("add", this, records, index);
13346 * Remove a Record from the Store and fires the remove event.
13347 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
13349 remove : function(record){
13350 var index = this.data.indexOf(record);
13351 this.data.removeAt(index);
13353 if(this.pruneModifiedRecords){
13354 this.modified.remove(record);
13356 this.fireEvent("remove", this, record, index);
13360 * Remove all Records from the Store and fires the clear event.
13362 removeAll : function(){
13364 if(this.pruneModifiedRecords){
13365 this.modified = [];
13367 this.fireEvent("clear", this);
13371 * Inserts Records to the Store at the given index and fires the add event.
13372 * @param {Number} index The start index at which to insert the passed Records.
13373 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13375 insert : function(index, records){
13376 records = [].concat(records);
13377 for(var i = 0, len = records.length; i < len; i++){
13378 this.data.insert(index, records[i]);
13379 records[i].join(this);
13381 this.fireEvent("add", this, records, index);
13385 * Get the index within the cache of the passed Record.
13386 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
13387 * @return {Number} The index of the passed Record. Returns -1 if not found.
13389 indexOf : function(record){
13390 return this.data.indexOf(record);
13394 * Get the index within the cache of the Record with the passed id.
13395 * @param {String} id The id of the Record to find.
13396 * @return {Number} The index of the Record. Returns -1 if not found.
13398 indexOfId : function(id){
13399 return this.data.indexOfKey(id);
13403 * Get the Record with the specified id.
13404 * @param {String} id The id of the Record to find.
13405 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
13407 getById : function(id){
13408 return this.data.key(id);
13412 * Get the Record at the specified index.
13413 * @param {Number} index The index of the Record to find.
13414 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
13416 getAt : function(index){
13417 return this.data.itemAt(index);
13421 * Returns a range of Records between specified indices.
13422 * @param {Number} startIndex (optional) The starting index (defaults to 0)
13423 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
13424 * @return {Roo.data.Record[]} An array of Records
13426 getRange : function(start, end){
13427 return this.data.getRange(start, end);
13431 storeOptions : function(o){
13432 o = Roo.apply({}, o);
13435 this.lastOptions = o;
13439 * Loads the Record cache from the configured Proxy using the configured Reader.
13441 * If using remote paging, then the first load call must specify the <em>start</em>
13442 * and <em>limit</em> properties in the options.params property to establish the initial
13443 * position within the dataset, and the number of Records to cache on each read from the Proxy.
13445 * <strong>It is important to note that for remote data sources, loading is asynchronous,
13446 * and this call will return before the new data has been loaded. Perform any post-processing
13447 * in a callback function, or in a "load" event handler.</strong>
13449 * @param {Object} options An object containing properties which control loading options:<ul>
13450 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
13451 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
13452 * passed the following arguments:<ul>
13453 * <li>r : Roo.data.Record[]</li>
13454 * <li>options: Options object from the load call</li>
13455 * <li>success: Boolean success indicator</li></ul></li>
13456 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
13457 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
13460 load : function(options){
13461 options = options || {};
13462 if(this.fireEvent("beforeload", this, options) !== false){
13463 this.storeOptions(options);
13464 var p = Roo.apply(options.params || {}, this.baseParams);
13465 // if meta was not loaded from remote source.. try requesting it.
13466 if (!this.reader.metaFromRemote) {
13467 p._requestMeta = 1;
13469 if(this.sortInfo && this.remoteSort){
13470 var pn = this.paramNames;
13471 p[pn["sort"]] = this.sortInfo.field;
13472 p[pn["dir"]] = this.sortInfo.direction;
13474 if (this.multiSort) {
13475 var pn = this.paramNames;
13476 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
13479 this.proxy.load(p, this.reader, this.loadRecords, this, options);
13484 * Reloads the Record cache from the configured Proxy using the configured Reader and
13485 * the options from the last load operation performed.
13486 * @param {Object} options (optional) An object containing properties which may override the options
13487 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
13488 * the most recently used options are reused).
13490 reload : function(options){
13491 this.load(Roo.applyIf(options||{}, this.lastOptions));
13495 // Called as a callback by the Reader during a load operation.
13496 loadRecords : function(o, options, success){
13497 if(!o || success === false){
13498 if(success !== false){
13499 this.fireEvent("load", this, [], options, o);
13501 if(options.callback){
13502 options.callback.call(options.scope || this, [], options, false);
13506 // if data returned failure - throw an exception.
13507 if (o.success === false) {
13508 // show a message if no listener is registered.
13509 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
13510 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
13512 // loadmask wil be hooked into this..
13513 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
13516 var r = o.records, t = o.totalRecords || r.length;
13518 this.fireEvent("beforeloadadd", this, r, options, o);
13520 if(!options || options.add !== true){
13521 if(this.pruneModifiedRecords){
13522 this.modified = [];
13524 for(var i = 0, len = r.length; i < len; i++){
13528 this.data = this.snapshot;
13529 delete this.snapshot;
13532 this.data.addAll(r);
13533 this.totalLength = t;
13535 this.fireEvent("datachanged", this);
13537 this.totalLength = Math.max(t, this.data.length+r.length);
13541 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
13543 var e = new Roo.data.Record({});
13545 e.set(this.parent.displayField, this.parent.emptyTitle);
13546 e.set(this.parent.valueField, '');
13551 this.fireEvent("load", this, r, options, o);
13552 if(options.callback){
13553 options.callback.call(options.scope || this, r, options, true);
13559 * Loads data from a passed data block. A Reader which understands the format of the data
13560 * must have been configured in the constructor.
13561 * @param {Object} data The data block from which to read the Records. The format of the data expected
13562 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
13563 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
13565 loadData : function(o, append){
13566 var r = this.reader.readRecords(o);
13567 this.loadRecords(r, {add: append}, true);
13571 * using 'cn' the nested child reader read the child array into it's child stores.
13572 * @param {Object} rec The record with a 'children array
13574 loadDataFromChildren : function(rec)
13576 this.loadData(this.reader.toLoadData(rec));
13581 * Gets the number of cached records.
13583 * <em>If using paging, this may not be the total size of the dataset. If the data object
13584 * used by the Reader contains the dataset size, then the getTotalCount() function returns
13585 * the data set size</em>
13587 getCount : function(){
13588 return this.data.length || 0;
13592 * Gets the total number of records in the dataset as returned by the server.
13594 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
13595 * the dataset size</em>
13597 getTotalCount : function(){
13598 return this.totalLength || 0;
13602 * Returns the sort state of the Store as an object with two properties:
13604 field {String} The name of the field by which the Records are sorted
13605 direction {String} The sort order, "ASC" or "DESC"
13608 getSortState : function(){
13609 return this.sortInfo;
13613 applySort : function(){
13614 if(this.sortInfo && !this.remoteSort){
13615 var s = this.sortInfo, f = s.field;
13616 var st = this.fields.get(f).sortType;
13617 var fn = function(r1, r2){
13618 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
13619 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
13621 this.data.sort(s.direction, fn);
13622 if(this.snapshot && this.snapshot != this.data){
13623 this.snapshot.sort(s.direction, fn);
13629 * Sets the default sort column and order to be used by the next load operation.
13630 * @param {String} fieldName The name of the field to sort by.
13631 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13633 setDefaultSort : function(field, dir){
13634 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
13638 * Sort the Records.
13639 * If remote sorting is used, the sort is performed on the server, and the cache is
13640 * reloaded. If local sorting is used, the cache is sorted internally.
13641 * @param {String} fieldName The name of the field to sort by.
13642 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13644 sort : function(fieldName, dir){
13645 var f = this.fields.get(fieldName);
13647 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
13649 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
13650 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
13655 this.sortToggle[f.name] = dir;
13656 this.sortInfo = {field: f.name, direction: dir};
13657 if(!this.remoteSort){
13659 this.fireEvent("datachanged", this);
13661 this.load(this.lastOptions);
13666 * Calls the specified function for each of the Records in the cache.
13667 * @param {Function} fn The function to call. The Record is passed as the first parameter.
13668 * Returning <em>false</em> aborts and exits the iteration.
13669 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
13671 each : function(fn, scope){
13672 this.data.each(fn, scope);
13676 * Gets all records modified since the last commit. Modified records are persisted across load operations
13677 * (e.g., during paging).
13678 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
13680 getModifiedRecords : function(){
13681 return this.modified;
13685 createFilterFn : function(property, value, anyMatch){
13686 if(!value.exec){ // not a regex
13687 value = String(value);
13688 if(value.length == 0){
13691 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
13693 return function(r){
13694 return value.test(r.data[property]);
13699 * Sums the value of <i>property</i> for each record between start and end and returns the result.
13700 * @param {String} property A field on your records
13701 * @param {Number} start The record index to start at (defaults to 0)
13702 * @param {Number} end The last record index to include (defaults to length - 1)
13703 * @return {Number} The sum
13705 sum : function(property, start, end){
13706 var rs = this.data.items, v = 0;
13707 start = start || 0;
13708 end = (end || end === 0) ? end : rs.length-1;
13710 for(var i = start; i <= end; i++){
13711 v += (rs[i].data[property] || 0);
13717 * Filter the records by a specified property.
13718 * @param {String} field A field on your records
13719 * @param {String/RegExp} value Either a string that the field
13720 * should start with or a RegExp to test against the field
13721 * @param {Boolean} anyMatch True to match any part not just the beginning
13723 filter : function(property, value, anyMatch){
13724 var fn = this.createFilterFn(property, value, anyMatch);
13725 return fn ? this.filterBy(fn) : this.clearFilter();
13729 * Filter by a function. The specified function will be called with each
13730 * record in this data source. If the function returns true the record is included,
13731 * otherwise it is filtered.
13732 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13733 * @param {Object} scope (optional) The scope of the function (defaults to this)
13735 filterBy : function(fn, scope){
13736 this.snapshot = this.snapshot || this.data;
13737 this.data = this.queryBy(fn, scope||this);
13738 this.fireEvent("datachanged", this);
13742 * Query the records by a specified property.
13743 * @param {String} field A field on your records
13744 * @param {String/RegExp} value Either a string that the field
13745 * should start with or a RegExp to test against the field
13746 * @param {Boolean} anyMatch True to match any part not just the beginning
13747 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13749 query : function(property, value, anyMatch){
13750 var fn = this.createFilterFn(property, value, anyMatch);
13751 return fn ? this.queryBy(fn) : this.data.clone();
13755 * Query by a function. The specified function will be called with each
13756 * record in this data source. If the function returns true the record is included
13758 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13759 * @param {Object} scope (optional) The scope of the function (defaults to this)
13760 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13762 queryBy : function(fn, scope){
13763 var data = this.snapshot || this.data;
13764 return data.filterBy(fn, scope||this);
13768 * Collects unique values for a particular dataIndex from this store.
13769 * @param {String} dataIndex The property to collect
13770 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
13771 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
13772 * @return {Array} An array of the unique values
13774 collect : function(dataIndex, allowNull, bypassFilter){
13775 var d = (bypassFilter === true && this.snapshot) ?
13776 this.snapshot.items : this.data.items;
13777 var v, sv, r = [], l = {};
13778 for(var i = 0, len = d.length; i < len; i++){
13779 v = d[i].data[dataIndex];
13781 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
13790 * Revert to a view of the Record cache with no filtering applied.
13791 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13793 clearFilter : function(suppressEvent){
13794 if(this.snapshot && this.snapshot != this.data){
13795 this.data = this.snapshot;
13796 delete this.snapshot;
13797 if(suppressEvent !== true){
13798 this.fireEvent("datachanged", this);
13804 afterEdit : function(record){
13805 if(this.modified.indexOf(record) == -1){
13806 this.modified.push(record);
13808 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13812 afterReject : function(record){
13813 this.modified.remove(record);
13814 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13818 afterCommit : function(record){
13819 this.modified.remove(record);
13820 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13824 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13825 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13827 commitChanges : function(){
13828 var m = this.modified.slice(0);
13829 this.modified = [];
13830 for(var i = 0, len = m.length; i < len; i++){
13836 * Cancel outstanding changes on all changed records.
13838 rejectChanges : function(){
13839 var m = this.modified.slice(0);
13840 this.modified = [];
13841 for(var i = 0, len = m.length; i < len; i++){
13846 onMetaChange : function(meta, rtype, o){
13847 this.recordType = rtype;
13848 this.fields = rtype.prototype.fields;
13849 delete this.snapshot;
13850 this.sortInfo = meta.sortInfo || this.sortInfo;
13851 this.modified = [];
13852 this.fireEvent('metachange', this, this.reader.meta);
13855 moveIndex : function(data, type)
13857 var index = this.indexOf(data);
13859 var newIndex = index + type;
13863 this.insert(newIndex, data);
13868 * Ext JS Library 1.1.1
13869 * Copyright(c) 2006-2007, Ext JS, LLC.
13871 * Originally Released Under LGPL - original licence link has changed is not relivant.
13874 * <script type="text/javascript">
13878 * @class Roo.data.SimpleStore
13879 * @extends Roo.data.Store
13880 * Small helper class to make creating Stores from Array data easier.
13881 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13882 * @cfg {Array} fields An array of field definition objects, or field name strings.
13883 * @cfg {Object} an existing reader (eg. copied from another store)
13884 * @cfg {Array} data The multi-dimensional array of data
13886 * @param {Object} config
13888 Roo.data.SimpleStore = function(config)
13890 Roo.data.SimpleStore.superclass.constructor.call(this, {
13892 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13895 Roo.data.Record.create(config.fields)
13897 proxy : new Roo.data.MemoryProxy(config.data)
13901 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13903 * Ext JS Library 1.1.1
13904 * Copyright(c) 2006-2007, Ext JS, LLC.
13906 * Originally Released Under LGPL - original licence link has changed is not relivant.
13909 * <script type="text/javascript">
13914 * @extends Roo.data.Store
13915 * @class Roo.data.JsonStore
13916 * Small helper class to make creating Stores for JSON data easier. <br/>
13918 var store = new Roo.data.JsonStore({
13919 url: 'get-images.php',
13921 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13924 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13925 * JsonReader and HttpProxy (unless inline data is provided).</b>
13926 * @cfg {Array} fields An array of field definition objects, or field name strings.
13928 * @param {Object} config
13930 Roo.data.JsonStore = function(c){
13931 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13932 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13933 reader: new Roo.data.JsonReader(c, c.fields)
13936 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13938 * Ext JS Library 1.1.1
13939 * Copyright(c) 2006-2007, Ext JS, LLC.
13941 * Originally Released Under LGPL - original licence link has changed is not relivant.
13944 * <script type="text/javascript">
13948 Roo.data.Field = function(config){
13949 if(typeof config == "string"){
13950 config = {name: config};
13952 Roo.apply(this, config);
13955 this.type = "auto";
13958 var st = Roo.data.SortTypes;
13959 // named sortTypes are supported, here we look them up
13960 if(typeof this.sortType == "string"){
13961 this.sortType = st[this.sortType];
13964 // set default sortType for strings and dates
13965 if(!this.sortType){
13968 this.sortType = st.asUCString;
13971 this.sortType = st.asDate;
13974 this.sortType = st.none;
13979 var stripRe = /[\$,%]/g;
13981 // prebuilt conversion function for this field, instead of
13982 // switching every time we're reading a value
13984 var cv, dateFormat = this.dateFormat;
13989 cv = function(v){ return v; };
13992 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13996 return v !== undefined && v !== null && v !== '' ?
13997 parseInt(String(v).replace(stripRe, ""), 10) : '';
14002 return v !== undefined && v !== null && v !== '' ?
14003 parseFloat(String(v).replace(stripRe, ""), 10) : '';
14008 cv = function(v){ return v === true || v === "true" || v == 1; };
14015 if(v instanceof Date){
14019 if(dateFormat == "timestamp"){
14020 return new Date(v*1000);
14022 return Date.parseDate(v, dateFormat);
14024 var parsed = Date.parse(v);
14025 return parsed ? new Date(parsed) : null;
14034 Roo.data.Field.prototype = {
14042 * Ext JS Library 1.1.1
14043 * Copyright(c) 2006-2007, Ext JS, LLC.
14045 * Originally Released Under LGPL - original licence link has changed is not relivant.
14048 * <script type="text/javascript">
14051 // Base class for reading structured data from a data source. This class is intended to be
14052 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
14055 * @class Roo.data.DataReader
14056 * Base class for reading structured data from a data source. This class is intended to be
14057 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
14060 Roo.data.DataReader = function(meta, recordType){
14064 this.recordType = recordType instanceof Array ?
14065 Roo.data.Record.create(recordType) : recordType;
14068 Roo.data.DataReader.prototype = {
14071 readerType : 'Data',
14073 * Create an empty record
14074 * @param {Object} data (optional) - overlay some values
14075 * @return {Roo.data.Record} record created.
14077 newRow : function(d) {
14079 this.recordType.prototype.fields.each(function(c) {
14081 case 'int' : da[c.name] = 0; break;
14082 case 'date' : da[c.name] = new Date(); break;
14083 case 'float' : da[c.name] = 0.0; break;
14084 case 'boolean' : da[c.name] = false; break;
14085 default : da[c.name] = ""; break;
14089 return new this.recordType(Roo.apply(da, d));
14095 * Ext JS Library 1.1.1
14096 * Copyright(c) 2006-2007, Ext JS, LLC.
14098 * Originally Released Under LGPL - original licence link has changed is not relivant.
14101 * <script type="text/javascript">
14105 * @class Roo.data.DataProxy
14106 * @extends Roo.data.Observable
14107 * This class is an abstract base class for implementations which provide retrieval of
14108 * unformatted data objects.<br>
14110 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
14111 * (of the appropriate type which knows how to parse the data object) to provide a block of
14112 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
14114 * Custom implementations must implement the load method as described in
14115 * {@link Roo.data.HttpProxy#load}.
14117 Roo.data.DataProxy = function(){
14120 * @event beforeload
14121 * Fires before a network request is made to retrieve a data object.
14122 * @param {Object} This DataProxy object.
14123 * @param {Object} params The params parameter to the load function.
14128 * Fires before the load method's callback is called.
14129 * @param {Object} This DataProxy object.
14130 * @param {Object} o The data object.
14131 * @param {Object} arg The callback argument object passed to the load function.
14135 * @event loadexception
14136 * Fires if an Exception occurs during data retrieval.
14137 * @param {Object} This DataProxy object.
14138 * @param {Object} o The data object.
14139 * @param {Object} arg The callback argument object passed to the load function.
14140 * @param {Object} e The Exception.
14142 loadexception : true
14144 Roo.data.DataProxy.superclass.constructor.call(this);
14147 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
14150 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
14154 * Ext JS Library 1.1.1
14155 * Copyright(c) 2006-2007, Ext JS, LLC.
14157 * Originally Released Under LGPL - original licence link has changed is not relivant.
14160 * <script type="text/javascript">
14163 * @class Roo.data.MemoryProxy
14164 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
14165 * to the Reader when its load method is called.
14167 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
14169 Roo.data.MemoryProxy = function(data){
14173 Roo.data.MemoryProxy.superclass.constructor.call(this);
14177 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
14180 * Load data from the requested source (in this case an in-memory
14181 * data object passed to the constructor), read the data object into
14182 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14183 * process that block using the passed callback.
14184 * @param {Object} params This parameter is not used by the MemoryProxy class.
14185 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14186 * object into a block of Roo.data.Records.
14187 * @param {Function} callback The function into which to pass the block of Roo.data.records.
14188 * The function must be passed <ul>
14189 * <li>The Record block object</li>
14190 * <li>The "arg" argument from the load function</li>
14191 * <li>A boolean success indicator</li>
14193 * @param {Object} scope The scope in which to call the callback
14194 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14196 load : function(params, reader, callback, scope, arg){
14197 params = params || {};
14200 result = reader.readRecords(params.data ? params.data :this.data);
14202 this.fireEvent("loadexception", this, arg, null, e);
14203 callback.call(scope, null, arg, false);
14206 callback.call(scope, result, arg, true);
14210 update : function(params, records){
14215 * Ext JS Library 1.1.1
14216 * Copyright(c) 2006-2007, Ext JS, LLC.
14218 * Originally Released Under LGPL - original licence link has changed is not relivant.
14221 * <script type="text/javascript">
14224 * @class Roo.data.HttpProxy
14225 * @extends Roo.data.DataProxy
14226 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
14227 * configured to reference a certain URL.<br><br>
14229 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
14230 * from which the running page was served.<br><br>
14232 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
14234 * Be aware that to enable the browser to parse an XML document, the server must set
14235 * the Content-Type header in the HTTP response to "text/xml".
14237 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
14238 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
14239 * will be used to make the request.
14241 Roo.data.HttpProxy = function(conn){
14242 Roo.data.HttpProxy.superclass.constructor.call(this);
14243 // is conn a conn config or a real conn?
14245 this.useAjax = !conn || !conn.events;
14249 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
14250 // thse are take from connection...
14253 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
14256 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
14257 * extra parameters to each request made by this object. (defaults to undefined)
14260 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
14261 * to each request made by this object. (defaults to undefined)
14264 * @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)
14267 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
14270 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
14276 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
14280 * Return the {@link Roo.data.Connection} object being used by this Proxy.
14281 * @return {Connection} The Connection object. This object may be used to subscribe to events on
14282 * a finer-grained basis than the DataProxy events.
14284 getConnection : function(){
14285 return this.useAjax ? Roo.Ajax : this.conn;
14289 * Load data from the configured {@link Roo.data.Connection}, read the data object into
14290 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
14291 * process that block using the passed callback.
14292 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14293 * for the request to the remote server.
14294 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14295 * object into a block of Roo.data.Records.
14296 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14297 * The function must be passed <ul>
14298 * <li>The Record block object</li>
14299 * <li>The "arg" argument from the load function</li>
14300 * <li>A boolean success indicator</li>
14302 * @param {Object} scope The scope in which to call the callback
14303 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14305 load : function(params, reader, callback, scope, arg){
14306 if(this.fireEvent("beforeload", this, params) !== false){
14308 params : params || {},
14310 callback : callback,
14315 callback : this.loadResponse,
14319 Roo.applyIf(o, this.conn);
14320 if(this.activeRequest){
14321 Roo.Ajax.abort(this.activeRequest);
14323 this.activeRequest = Roo.Ajax.request(o);
14325 this.conn.request(o);
14328 callback.call(scope||this, null, arg, false);
14333 loadResponse : function(o, success, response){
14334 delete this.activeRequest;
14336 this.fireEvent("loadexception", this, o, response);
14337 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14342 result = o.reader.read(response);
14344 this.fireEvent("loadexception", this, o, response, e);
14345 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14349 this.fireEvent("load", this, o, o.request.arg);
14350 o.request.callback.call(o.request.scope, result, o.request.arg, true);
14354 update : function(dataSet){
14359 updateResponse : function(dataSet){
14364 * Ext JS Library 1.1.1
14365 * Copyright(c) 2006-2007, Ext JS, LLC.
14367 * Originally Released Under LGPL - original licence link has changed is not relivant.
14370 * <script type="text/javascript">
14374 * @class Roo.data.ScriptTagProxy
14375 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
14376 * other than the originating domain of the running page.<br><br>
14378 * <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
14379 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
14381 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
14382 * source code that is used as the source inside a <script> tag.<br><br>
14384 * In order for the browser to process the returned data, the server must wrap the data object
14385 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
14386 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
14387 * depending on whether the callback name was passed:
14390 boolean scriptTag = false;
14391 String cb = request.getParameter("callback");
14394 response.setContentType("text/javascript");
14396 response.setContentType("application/x-json");
14398 Writer out = response.getWriter();
14400 out.write(cb + "(");
14402 out.print(dataBlock.toJsonString());
14409 * @param {Object} config A configuration object.
14411 Roo.data.ScriptTagProxy = function(config){
14412 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
14413 Roo.apply(this, config);
14414 this.head = document.getElementsByTagName("head")[0];
14417 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
14419 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
14421 * @cfg {String} url The URL from which to request the data object.
14424 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
14428 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
14429 * the server the name of the callback function set up by the load call to process the returned data object.
14430 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
14431 * javascript output which calls this named function passing the data object as its only parameter.
14433 callbackParam : "callback",
14435 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
14436 * name to the request.
14441 * Load data from the configured URL, read the data object into
14442 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14443 * process that block using the passed callback.
14444 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14445 * for the request to the remote server.
14446 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14447 * object into a block of Roo.data.Records.
14448 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14449 * The function must be passed <ul>
14450 * <li>The Record block object</li>
14451 * <li>The "arg" argument from the load function</li>
14452 * <li>A boolean success indicator</li>
14454 * @param {Object} scope The scope in which to call the callback
14455 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14457 load : function(params, reader, callback, scope, arg){
14458 if(this.fireEvent("beforeload", this, params) !== false){
14460 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
14462 var url = this.url;
14463 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
14465 url += "&_dc=" + (new Date().getTime());
14467 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
14470 cb : "stcCallback"+transId,
14471 scriptId : "stcScript"+transId,
14475 callback : callback,
14481 window[trans.cb] = function(o){
14482 conn.handleResponse(o, trans);
14485 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
14487 if(this.autoAbort !== false){
14491 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
14493 var script = document.createElement("script");
14494 script.setAttribute("src", url);
14495 script.setAttribute("type", "text/javascript");
14496 script.setAttribute("id", trans.scriptId);
14497 this.head.appendChild(script);
14499 this.trans = trans;
14501 callback.call(scope||this, null, arg, false);
14506 isLoading : function(){
14507 return this.trans ? true : false;
14511 * Abort the current server request.
14513 abort : function(){
14514 if(this.isLoading()){
14515 this.destroyTrans(this.trans);
14520 destroyTrans : function(trans, isLoaded){
14521 this.head.removeChild(document.getElementById(trans.scriptId));
14522 clearTimeout(trans.timeoutId);
14524 window[trans.cb] = undefined;
14526 delete window[trans.cb];
14529 // if hasn't been loaded, wait for load to remove it to prevent script error
14530 window[trans.cb] = function(){
14531 window[trans.cb] = undefined;
14533 delete window[trans.cb];
14540 handleResponse : function(o, trans){
14541 this.trans = false;
14542 this.destroyTrans(trans, true);
14545 result = trans.reader.readRecords(o);
14547 this.fireEvent("loadexception", this, o, trans.arg, e);
14548 trans.callback.call(trans.scope||window, null, trans.arg, false);
14551 this.fireEvent("load", this, o, trans.arg);
14552 trans.callback.call(trans.scope||window, result, trans.arg, true);
14556 handleFailure : function(trans){
14557 this.trans = false;
14558 this.destroyTrans(trans, false);
14559 this.fireEvent("loadexception", this, null, trans.arg);
14560 trans.callback.call(trans.scope||window, null, trans.arg, false);
14564 * Ext JS Library 1.1.1
14565 * Copyright(c) 2006-2007, Ext JS, LLC.
14567 * Originally Released Under LGPL - original licence link has changed is not relivant.
14570 * <script type="text/javascript">
14574 * @class Roo.data.JsonReader
14575 * @extends Roo.data.DataReader
14576 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
14577 * based on mappings in a provided Roo.data.Record constructor.
14579 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
14580 * in the reply previously.
14585 var RecordDef = Roo.data.Record.create([
14586 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
14587 {name: 'occupation'} // This field will use "occupation" as the mapping.
14589 var myReader = new Roo.data.JsonReader({
14590 totalProperty: "results", // The property which contains the total dataset size (optional)
14591 root: "rows", // The property which contains an Array of row objects
14592 id: "id" // The property within each row object that provides an ID for the record (optional)
14596 * This would consume a JSON file like this:
14598 { 'results': 2, 'rows': [
14599 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
14600 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
14603 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
14604 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
14605 * paged from the remote server.
14606 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
14607 * @cfg {String} root name of the property which contains the Array of row objects.
14608 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14609 * @cfg {Array} fields Array of field definition objects
14611 * Create a new JsonReader
14612 * @param {Object} meta Metadata configuration options
14613 * @param {Object} recordType Either an Array of field definition objects,
14614 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
14616 Roo.data.JsonReader = function(meta, recordType){
14619 // set some defaults:
14620 Roo.applyIf(meta, {
14621 totalProperty: 'total',
14622 successProperty : 'success',
14627 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14629 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
14631 readerType : 'Json',
14634 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
14635 * Used by Store query builder to append _requestMeta to params.
14638 metaFromRemote : false,
14640 * This method is only used by a DataProxy which has retrieved data from a remote server.
14641 * @param {Object} response The XHR object which contains the JSON data in its responseText.
14642 * @return {Object} data A data block which is used by an Roo.data.Store object as
14643 * a cache of Roo.data.Records.
14645 read : function(response){
14646 var json = response.responseText;
14648 var o = /* eval:var:o */ eval("("+json+")");
14650 throw {message: "JsonReader.read: Json object not found"};
14656 this.metaFromRemote = true;
14657 this.meta = o.metaData;
14658 this.recordType = Roo.data.Record.create(o.metaData.fields);
14659 this.onMetaChange(this.meta, this.recordType, o);
14661 return this.readRecords(o);
14664 // private function a store will implement
14665 onMetaChange : function(meta, recordType, o){
14672 simpleAccess: function(obj, subsc) {
14679 getJsonAccessor: function(){
14681 return function(expr) {
14683 return(re.test(expr))
14684 ? new Function("obj", "return obj." + expr)
14689 return Roo.emptyFn;
14694 * Create a data block containing Roo.data.Records from an XML document.
14695 * @param {Object} o An object which contains an Array of row objects in the property specified
14696 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
14697 * which contains the total size of the dataset.
14698 * @return {Object} data A data block which is used by an Roo.data.Store object as
14699 * a cache of Roo.data.Records.
14701 readRecords : function(o){
14703 * After any data loads, the raw JSON data is available for further custom processing.
14707 var s = this.meta, Record = this.recordType,
14708 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
14710 // Generate extraction functions for the totalProperty, the root, the id, and for each field
14712 if(s.totalProperty) {
14713 this.getTotal = this.getJsonAccessor(s.totalProperty);
14715 if(s.successProperty) {
14716 this.getSuccess = this.getJsonAccessor(s.successProperty);
14718 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
14720 var g = this.getJsonAccessor(s.id);
14721 this.getId = function(rec) {
14723 return (r === undefined || r === "") ? null : r;
14726 this.getId = function(){return null;};
14729 for(var jj = 0; jj < fl; jj++){
14731 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
14732 this.ef[jj] = this.getJsonAccessor(map);
14736 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
14737 if(s.totalProperty){
14738 var vt = parseInt(this.getTotal(o), 10);
14743 if(s.successProperty){
14744 var vs = this.getSuccess(o);
14745 if(vs === false || vs === 'false'){
14750 for(var i = 0; i < c; i++){
14753 var id = this.getId(n);
14754 for(var j = 0; j < fl; j++){
14756 var v = this.ef[j](n);
14758 Roo.log('missing convert for ' + f.name);
14762 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
14764 var record = new Record(values, id);
14766 records[i] = record;
14772 totalRecords : totalRecords
14775 // used when loading children.. @see loadDataFromChildren
14776 toLoadData: function(rec)
14778 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14779 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14780 return { data : data, total : data.length };
14785 * Ext JS Library 1.1.1
14786 * Copyright(c) 2006-2007, Ext JS, LLC.
14788 * Originally Released Under LGPL - original licence link has changed is not relivant.
14791 * <script type="text/javascript">
14795 * @class Roo.data.ArrayReader
14796 * @extends Roo.data.DataReader
14797 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14798 * Each element of that Array represents a row of data fields. The
14799 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14800 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14804 var RecordDef = Roo.data.Record.create([
14805 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14806 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14808 var myReader = new Roo.data.ArrayReader({
14809 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14813 * This would consume an Array like this:
14815 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14819 * Create a new JsonReader
14820 * @param {Object} meta Metadata configuration options.
14821 * @param {Object|Array} recordType Either an Array of field definition objects
14823 * @cfg {Array} fields Array of field definition objects
14824 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14825 * as specified to {@link Roo.data.Record#create},
14826 * or an {@link Roo.data.Record} object
14829 * created using {@link Roo.data.Record#create}.
14831 Roo.data.ArrayReader = function(meta, recordType)
14833 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14836 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14839 * Create a data block containing Roo.data.Records from an XML document.
14840 * @param {Object} o An Array of row objects which represents the dataset.
14841 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14842 * a cache of Roo.data.Records.
14844 readRecords : function(o)
14846 var sid = this.meta ? this.meta.id : null;
14847 var recordType = this.recordType, fields = recordType.prototype.fields;
14850 for(var i = 0; i < root.length; i++){
14853 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14854 for(var j = 0, jlen = fields.length; j < jlen; j++){
14855 var f = fields.items[j];
14856 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14857 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14859 values[f.name] = v;
14861 var record = new recordType(values, id);
14863 records[records.length] = record;
14867 totalRecords : records.length
14870 // used when loading children.. @see loadDataFromChildren
14871 toLoadData: function(rec)
14873 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14874 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14885 * @class Roo.bootstrap.ComboBox
14886 * @extends Roo.bootstrap.TriggerField
14887 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14888 * @cfg {Boolean} append (true|false) default false
14889 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14890 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14891 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14892 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14893 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14894 * @cfg {Boolean} animate default true
14895 * @cfg {Boolean} emptyResultText only for touch device
14896 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14897 * @cfg {String} emptyTitle default ''
14898 * @cfg {Number} width fixed with? experimental
14900 * Create a new ComboBox.
14901 * @param {Object} config Configuration options
14903 Roo.bootstrap.ComboBox = function(config){
14904 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14908 * Fires when the dropdown list is expanded
14909 * @param {Roo.bootstrap.ComboBox} combo This combo box
14914 * Fires when the dropdown list is collapsed
14915 * @param {Roo.bootstrap.ComboBox} combo This combo box
14919 * @event beforeselect
14920 * Fires before a list item is selected. Return false to cancel the selection.
14921 * @param {Roo.bootstrap.ComboBox} combo This combo box
14922 * @param {Roo.data.Record} record The data record returned from the underlying store
14923 * @param {Number} index The index of the selected item in the dropdown list
14925 'beforeselect' : true,
14928 * Fires when a list item is selected
14929 * @param {Roo.bootstrap.ComboBox} combo This combo box
14930 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14931 * @param {Number} index The index of the selected item in the dropdown list
14935 * @event beforequery
14936 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14937 * The event object passed has these properties:
14938 * @param {Roo.bootstrap.ComboBox} combo This combo box
14939 * @param {String} query The query
14940 * @param {Boolean} forceAll true to force "all" query
14941 * @param {Boolean} cancel true to cancel the query
14942 * @param {Object} e The query event object
14944 'beforequery': true,
14947 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14948 * @param {Roo.bootstrap.ComboBox} combo This combo box
14953 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14954 * @param {Roo.bootstrap.ComboBox} combo This combo box
14955 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14960 * Fires when the remove value from the combobox array
14961 * @param {Roo.bootstrap.ComboBox} combo This combo box
14965 * @event afterremove
14966 * Fires when the remove value from the combobox array
14967 * @param {Roo.bootstrap.ComboBox} combo This combo box
14969 'afterremove' : true,
14971 * @event specialfilter
14972 * Fires when specialfilter
14973 * @param {Roo.bootstrap.ComboBox} combo This combo box
14975 'specialfilter' : true,
14978 * Fires when tick the element
14979 * @param {Roo.bootstrap.ComboBox} combo This combo box
14983 * @event touchviewdisplay
14984 * Fires when touch view require special display (default is using displayField)
14985 * @param {Roo.bootstrap.ComboBox} combo This combo box
14986 * @param {Object} cfg set html .
14988 'touchviewdisplay' : true
14993 this.tickItems = [];
14995 this.selectedIndex = -1;
14996 if(this.mode == 'local'){
14997 if(config.queryDelay === undefined){
14998 this.queryDelay = 10;
15000 if(config.minChars === undefined){
15006 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
15009 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
15010 * rendering into an Roo.Editor, defaults to false)
15013 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
15014 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
15017 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
15020 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
15021 * the dropdown list (defaults to undefined, with no header element)
15025 * @cfg {String/Roo.Template} tpl The template to use to render the output default is '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>'
15029 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
15031 listWidth: undefined,
15033 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
15034 * mode = 'remote' or 'text' if mode = 'local')
15036 displayField: undefined,
15039 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
15040 * mode = 'remote' or 'value' if mode = 'local').
15041 * Note: use of a valueField requires the user make a selection
15042 * in order for a value to be mapped.
15044 valueField: undefined,
15046 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
15051 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
15052 * field's data value (defaults to the underlying DOM element's name)
15054 hiddenName: undefined,
15056 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
15060 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
15062 selectedClass: 'active',
15065 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
15069 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
15070 * anchor positions (defaults to 'tl-bl')
15072 listAlign: 'tl-bl?',
15074 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
15078 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
15079 * query specified by the allQuery config option (defaults to 'query')
15081 triggerAction: 'query',
15083 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
15084 * (defaults to 4, does not apply if editable = false)
15088 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
15089 * delay (typeAheadDelay) if it matches a known value (defaults to false)
15093 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
15094 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
15098 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
15099 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
15103 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
15104 * when editable = true (defaults to false)
15106 selectOnFocus:false,
15108 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
15110 queryParam: 'query',
15112 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
15113 * when mode = 'remote' (defaults to 'Loading...')
15115 loadingText: 'Loading...',
15117 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
15121 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
15125 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
15126 * traditional select (defaults to true)
15130 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
15134 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
15138 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
15139 * listWidth has a higher value)
15143 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
15144 * allow the user to set arbitrary text into the field (defaults to false)
15146 forceSelection:false,
15148 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
15149 * if typeAhead = true (defaults to 250)
15151 typeAheadDelay : 250,
15153 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
15154 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
15156 valueNotFoundText : undefined,
15158 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
15160 blockFocus : false,
15163 * @cfg {Boolean} disableClear Disable showing of clear button.
15165 disableClear : false,
15167 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
15169 alwaysQuery : false,
15172 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
15177 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
15179 invalidClass : "has-warning",
15182 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
15184 validClass : "has-success",
15187 * @cfg {Boolean} specialFilter (true|false) special filter default false
15189 specialFilter : false,
15192 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
15194 mobileTouchView : true,
15197 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
15199 useNativeIOS : false,
15202 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
15204 mobile_restrict_height : false,
15206 ios_options : false,
15218 btnPosition : 'right',
15219 triggerList : true,
15220 showToggleBtn : true,
15222 emptyResultText: 'Empty',
15223 triggerText : 'Select',
15227 // element that contains real text value.. (when hidden is used..)
15229 getAutoCreate : function()
15234 * Render classic select for iso
15237 if(Roo.isIOS && this.useNativeIOS){
15238 cfg = this.getAutoCreateNativeIOS();
15246 if(Roo.isTouch && this.mobileTouchView){
15247 cfg = this.getAutoCreateTouchView();
15254 if(!this.tickable){
15255 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
15260 * ComboBox with tickable selections
15263 var align = this.labelAlign || this.parentLabelAlign();
15266 cls : 'form-group roo-combobox-tickable' //input-group
15269 var btn_text_select = '';
15270 var btn_text_done = '';
15271 var btn_text_cancel = '';
15273 if (this.btn_text_show) {
15274 btn_text_select = 'Select';
15275 btn_text_done = 'Done';
15276 btn_text_cancel = 'Cancel';
15281 cls : 'tickable-buttons',
15286 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
15287 //html : this.triggerText
15288 html: btn_text_select
15294 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
15296 html: btn_text_done
15302 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
15304 html: btn_text_cancel
15310 buttons.cn.unshift({
15312 cls: 'roo-select2-search-field-input'
15318 Roo.each(buttons.cn, function(c){
15320 c.cls += ' btn-' + _this.size;
15323 if (_this.disabled) {
15330 style : 'display: contents',
15335 cls: 'form-hidden-field'
15339 cls: 'roo-select2-choices',
15343 cls: 'roo-select2-search-field',
15354 cls: 'roo-select2-container input-group roo-select2-container-multi',
15360 // cls: 'typeahead typeahead-long dropdown-menu',
15361 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
15366 if(this.hasFeedback && !this.allowBlank){
15370 cls: 'glyphicon form-control-feedback'
15373 combobox.cn.push(feedback);
15380 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
15381 tooltip : 'This field is required'
15383 if (Roo.bootstrap.version == 4) {
15386 style : 'display:none'
15389 if (align ==='left' && this.fieldLabel.length) {
15391 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
15398 cls : 'control-label col-form-label',
15399 html : this.fieldLabel
15411 var labelCfg = cfg.cn[1];
15412 var contentCfg = cfg.cn[2];
15415 if(this.indicatorpos == 'right'){
15421 cls : 'control-label col-form-label',
15425 html : this.fieldLabel
15441 labelCfg = cfg.cn[0];
15442 contentCfg = cfg.cn[1];
15446 if(this.labelWidth > 12){
15447 labelCfg.style = "width: " + this.labelWidth + 'px';
15449 if(this.width * 1 > 0){
15450 contentCfg.style = "width: " + this.width + 'px';
15452 if(this.labelWidth < 13 && this.labelmd == 0){
15453 this.labelmd = this.labelWidth;
15456 if(this.labellg > 0){
15457 labelCfg.cls += ' col-lg-' + this.labellg;
15458 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15461 if(this.labelmd > 0){
15462 labelCfg.cls += ' col-md-' + this.labelmd;
15463 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15466 if(this.labelsm > 0){
15467 labelCfg.cls += ' col-sm-' + this.labelsm;
15468 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15471 if(this.labelxs > 0){
15472 labelCfg.cls += ' col-xs-' + this.labelxs;
15473 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15477 } else if ( this.fieldLabel.length) {
15478 // Roo.log(" label");
15483 //cls : 'input-group-addon',
15484 html : this.fieldLabel
15489 if(this.indicatorpos == 'right'){
15493 //cls : 'input-group-addon',
15494 html : this.fieldLabel
15504 // Roo.log(" no label && no align");
15511 ['xs','sm','md','lg'].map(function(size){
15512 if (settings[size]) {
15513 cfg.cls += ' col-' + size + '-' + settings[size];
15521 _initEventsCalled : false,
15524 initEvents: function()
15526 if (this._initEventsCalled) { // as we call render... prevent looping...
15529 this._initEventsCalled = true;
15532 throw "can not find store for combo";
15535 this.indicator = this.indicatorEl();
15537 this.store = Roo.factory(this.store, Roo.data);
15538 this.store.parent = this;
15540 // if we are building from html. then this element is so complex, that we can not really
15541 // use the rendered HTML.
15542 // so we have to trash and replace the previous code.
15543 if (Roo.XComponent.build_from_html) {
15544 // remove this element....
15545 var e = this.el.dom, k=0;
15546 while (e ) { e = e.previousSibling; ++k;}
15551 this.rendered = false;
15553 this.render(this.parent().getChildContainer(true), k);
15556 if(Roo.isIOS && this.useNativeIOS){
15557 this.initIOSView();
15565 if(Roo.isTouch && this.mobileTouchView){
15566 this.initTouchView();
15571 this.initTickableEvents();
15575 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
15577 if(this.hiddenName){
15579 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15581 this.hiddenField.dom.value =
15582 this.hiddenValue !== undefined ? this.hiddenValue :
15583 this.value !== undefined ? this.value : '';
15585 // prevent input submission
15586 this.el.dom.removeAttribute('name');
15587 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15592 // this.el.dom.setAttribute('autocomplete', 'off');
15595 var cls = 'x-combo-list';
15597 //this.list = new Roo.Layer({
15598 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
15604 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15605 _this.list.setWidth(lw);
15608 this.list.on('mouseover', this.onViewOver, this);
15609 this.list.on('mousemove', this.onViewMove, this);
15610 this.list.on('scroll', this.onViewScroll, this);
15613 this.list.swallowEvent('mousewheel');
15614 this.assetHeight = 0;
15617 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
15618 this.assetHeight += this.header.getHeight();
15621 this.innerList = this.list.createChild({cls:cls+'-inner'});
15622 this.innerList.on('mouseover', this.onViewOver, this);
15623 this.innerList.on('mousemove', this.onViewMove, this);
15624 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15626 if(this.allowBlank && !this.pageSize && !this.disableClear){
15627 this.footer = this.list.createChild({cls:cls+'-ft'});
15628 this.pageTb = new Roo.Toolbar(this.footer);
15632 this.footer = this.list.createChild({cls:cls+'-ft'});
15633 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
15634 {pageSize: this.pageSize});
15638 if (this.pageTb && this.allowBlank && !this.disableClear) {
15640 this.pageTb.add(new Roo.Toolbar.Fill(), {
15641 cls: 'x-btn-icon x-btn-clear',
15643 handler: function()
15646 _this.clearValue();
15647 _this.onSelect(false, -1);
15652 this.assetHeight += this.footer.getHeight();
15657 this.tpl = Roo.bootstrap.version == 4 ?
15658 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
15659 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
15662 this.view = new Roo.View(this.list, this.tpl, {
15663 singleSelect:true, store: this.store, selectedClass: this.selectedClass
15665 //this.view.wrapEl.setDisplayed(false);
15666 this.view.on('click', this.onViewClick, this);
15669 this.store.on('beforeload', this.onBeforeLoad, this);
15670 this.store.on('load', this.onLoad, this);
15671 this.store.on('loadexception', this.onLoadException, this);
15673 if(this.resizable){
15674 this.resizer = new Roo.Resizable(this.list, {
15675 pinned:true, handles:'se'
15677 this.resizer.on('resize', function(r, w, h){
15678 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
15679 this.listWidth = w;
15680 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
15681 this.restrictHeight();
15683 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
15686 if(!this.editable){
15687 this.editable = true;
15688 this.setEditable(false);
15693 if (typeof(this.events.add.listeners) != 'undefined') {
15695 this.addicon = this.wrap.createChild(
15696 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
15698 this.addicon.on('click', function(e) {
15699 this.fireEvent('add', this);
15702 if (typeof(this.events.edit.listeners) != 'undefined') {
15704 this.editicon = this.wrap.createChild(
15705 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
15706 if (this.addicon) {
15707 this.editicon.setStyle('margin-left', '40px');
15709 this.editicon.on('click', function(e) {
15711 // we fire even if inothing is selected..
15712 this.fireEvent('edit', this, this.lastData );
15718 this.keyNav = new Roo.KeyNav(this.inputEl(), {
15719 "up" : function(e){
15720 this.inKeyMode = true;
15724 "down" : function(e){
15725 if(!this.isExpanded()){
15726 this.onTriggerClick();
15728 this.inKeyMode = true;
15733 "enter" : function(e){
15734 // this.onViewClick();
15738 if(this.fireEvent("specialkey", this, e)){
15739 this.onViewClick(false);
15745 "esc" : function(e){
15749 "tab" : function(e){
15752 if(this.fireEvent("specialkey", this, e)){
15753 this.onViewClick(false);
15761 doRelay : function(foo, bar, hname){
15762 if(hname == 'down' || this.scope.isExpanded()){
15763 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15772 this.queryDelay = Math.max(this.queryDelay || 10,
15773 this.mode == 'local' ? 10 : 250);
15776 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15778 if(this.typeAhead){
15779 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15781 if(this.editable !== false){
15782 this.inputEl().on("keyup", this.onKeyUp, this);
15784 if(this.forceSelection){
15785 this.inputEl().on('blur', this.doForce, this);
15789 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15790 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15794 initTickableEvents: function()
15798 if(this.hiddenName){
15800 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15802 this.hiddenField.dom.value =
15803 this.hiddenValue !== undefined ? this.hiddenValue :
15804 this.value !== undefined ? this.value : '';
15806 // prevent input submission
15807 this.el.dom.removeAttribute('name');
15808 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15813 // this.list = this.el.select('ul.dropdown-menu',true).first();
15815 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15816 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15817 if(this.triggerList){
15818 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15821 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15822 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15824 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15825 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15827 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15828 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15830 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15831 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15832 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15835 this.cancelBtn.hide();
15840 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15841 _this.list.setWidth(lw);
15844 this.list.on('mouseover', this.onViewOver, this);
15845 this.list.on('mousemove', this.onViewMove, this);
15847 this.list.on('scroll', this.onViewScroll, this);
15850 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15851 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15854 this.view = new Roo.View(this.list, this.tpl, {
15859 selectedClass: this.selectedClass
15862 //this.view.wrapEl.setDisplayed(false);
15863 this.view.on('click', this.onViewClick, this);
15867 this.store.on('beforeload', this.onBeforeLoad, this);
15868 this.store.on('load', this.onLoad, this);
15869 this.store.on('loadexception', this.onLoadException, this);
15872 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15873 "up" : function(e){
15874 this.inKeyMode = true;
15878 "down" : function(e){
15879 this.inKeyMode = true;
15883 "enter" : function(e){
15884 if(this.fireEvent("specialkey", this, e)){
15885 this.onViewClick(false);
15891 "esc" : function(e){
15892 this.onTickableFooterButtonClick(e, false, false);
15895 "tab" : function(e){
15896 this.fireEvent("specialkey", this, e);
15898 this.onTickableFooterButtonClick(e, false, false);
15905 doRelay : function(e, fn, key){
15906 if(this.scope.isExpanded()){
15907 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15916 this.queryDelay = Math.max(this.queryDelay || 10,
15917 this.mode == 'local' ? 10 : 250);
15920 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15922 if(this.typeAhead){
15923 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15926 if(this.editable !== false){
15927 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15930 this.indicator = this.indicatorEl();
15932 if(this.indicator){
15933 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15934 this.indicator.hide();
15939 onDestroy : function(){
15941 this.view.setStore(null);
15942 this.view.el.removeAllListeners();
15943 this.view.el.remove();
15944 this.view.purgeListeners();
15947 this.list.dom.innerHTML = '';
15951 this.store.un('beforeload', this.onBeforeLoad, this);
15952 this.store.un('load', this.onLoad, this);
15953 this.store.un('loadexception', this.onLoadException, this);
15955 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15959 fireKey : function(e){
15960 if(e.isNavKeyPress() && !this.list.isVisible()){
15961 this.fireEvent("specialkey", this, e);
15966 onResize: function(w, h)
15970 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15972 // if(typeof w != 'number'){
15973 // // we do not handle it!?!?
15976 // var tw = this.trigger.getWidth();
15977 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15978 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15980 // this.inputEl().setWidth( this.adjustWidth('input', x));
15982 // //this.trigger.setStyle('left', x+'px');
15984 // if(this.list && this.listWidth === undefined){
15985 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15986 // this.list.setWidth(lw);
15987 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15995 * Allow or prevent the user from directly editing the field text. If false is passed,
15996 * the user will only be able to select from the items defined in the dropdown list. This method
15997 * is the runtime equivalent of setting the 'editable' config option at config time.
15998 * @param {Boolean} value True to allow the user to directly edit the field text
16000 setEditable : function(value){
16001 if(value == this.editable){
16004 this.editable = value;
16006 this.inputEl().dom.setAttribute('readOnly', true);
16007 this.inputEl().on('mousedown', this.onTriggerClick, this);
16008 this.inputEl().addClass('x-combo-noedit');
16010 this.inputEl().dom.setAttribute('readOnly', false);
16011 this.inputEl().un('mousedown', this.onTriggerClick, this);
16012 this.inputEl().removeClass('x-combo-noedit');
16018 onBeforeLoad : function(combo,opts){
16019 if(!this.hasFocus){
16023 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
16025 this.restrictHeight();
16026 this.selectedIndex = -1;
16030 onLoad : function(){
16032 this.hasQuery = false;
16034 if(!this.hasFocus){
16038 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
16039 this.loading.hide();
16042 if(this.store.getCount() > 0){
16045 this.restrictHeight();
16046 if(this.lastQuery == this.allQuery){
16047 if(this.editable && !this.tickable){
16048 this.inputEl().dom.select();
16052 !this.selectByValue(this.value, true) &&
16055 !this.store.lastOptions ||
16056 typeof(this.store.lastOptions.add) == 'undefined' ||
16057 this.store.lastOptions.add != true
16060 this.select(0, true);
16063 if(this.autoFocus){
16066 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
16067 this.taTask.delay(this.typeAheadDelay);
16071 this.onEmptyResults();
16077 onLoadException : function()
16079 this.hasQuery = false;
16081 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
16082 this.loading.hide();
16085 if(this.tickable && this.editable){
16090 // only causes errors at present
16091 //Roo.log(this.store.reader.jsonData);
16092 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
16094 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
16100 onTypeAhead : function(){
16101 if(this.store.getCount() > 0){
16102 var r = this.store.getAt(0);
16103 var newValue = r.data[this.displayField];
16104 var len = newValue.length;
16105 var selStart = this.getRawValue().length;
16107 if(selStart != len){
16108 this.setRawValue(newValue);
16109 this.selectText(selStart, newValue.length);
16115 onSelect : function(record, index){
16117 if(this.fireEvent('beforeselect', this, record, index) !== false){
16119 this.setFromData(index > -1 ? record.data : false);
16122 this.fireEvent('select', this, record, index);
16127 * Returns the currently selected field value or empty string if no value is set.
16128 * @return {String} value The selected value
16130 getValue : function()
16132 if(Roo.isIOS && this.useNativeIOS){
16133 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
16137 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
16140 if(this.valueField){
16141 return typeof this.value != 'undefined' ? this.value : '';
16143 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
16147 getRawValue : function()
16149 if(Roo.isIOS && this.useNativeIOS){
16150 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
16153 var v = this.inputEl().getValue();
16159 * Clears any text/value currently set in the field
16161 clearValue : function(){
16163 if(this.hiddenField){
16164 this.hiddenField.dom.value = '';
16167 this.setRawValue('');
16168 this.lastSelectionText = '';
16169 this.lastData = false;
16171 var close = this.closeTriggerEl();
16182 * Sets the specified value into the field. If the value finds a match, the corresponding record text
16183 * will be displayed in the field. If the value does not match the data value of an existing item,
16184 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
16185 * Otherwise the field will be blank (although the value will still be set).
16186 * @param {String} value The value to match
16188 setValue : function(v)
16190 if(Roo.isIOS && this.useNativeIOS){
16191 this.setIOSValue(v);
16201 if(this.valueField){
16202 var r = this.findRecord(this.valueField, v);
16204 text = r.data[this.displayField];
16205 }else if(this.valueNotFoundText !== undefined){
16206 text = this.valueNotFoundText;
16209 this.lastSelectionText = text;
16210 if(this.hiddenField){
16211 this.hiddenField.dom.value = v;
16213 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
16216 var close = this.closeTriggerEl();
16219 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
16225 * @property {Object} the last set data for the element
16230 * Sets the value of the field based on a object which is related to the record format for the store.
16231 * @param {Object} value the value to set as. or false on reset?
16233 setFromData : function(o){
16240 var dv = ''; // display value
16241 var vv = ''; // value value..
16243 if (this.displayField) {
16244 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16246 // this is an error condition!!!
16247 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16250 if(this.valueField){
16251 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
16254 var close = this.closeTriggerEl();
16257 if(dv.length || vv * 1 > 0){
16259 this.blockFocus=true;
16265 if(this.hiddenField){
16266 this.hiddenField.dom.value = vv;
16268 this.lastSelectionText = dv;
16269 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16273 // no hidden field.. - we store the value in 'value', but still display
16274 // display field!!!!
16275 this.lastSelectionText = dv;
16276 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16283 reset : function(){
16284 // overridden so that last data is reset..
16291 this.setValue(this.originalValue);
16292 //this.clearInvalid();
16293 this.lastData = false;
16295 this.view.clearSelections();
16301 findRecord : function(prop, value){
16303 if(this.store.getCount() > 0){
16304 this.store.each(function(r){
16305 if(r.data[prop] == value){
16315 getName: function()
16317 // returns hidden if it's set..
16318 if (!this.rendered) {return ''};
16319 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
16323 onViewMove : function(e, t){
16324 this.inKeyMode = false;
16328 onViewOver : function(e, t){
16329 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
16332 var item = this.view.findItemFromChild(t);
16335 var index = this.view.indexOf(item);
16336 this.select(index, false);
16341 onViewClick : function(view, doFocus, el, e)
16343 var index = this.view.getSelectedIndexes()[0];
16345 var r = this.store.getAt(index);
16349 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
16356 Roo.each(this.tickItems, function(v,k){
16358 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
16360 _this.tickItems.splice(k, 1);
16362 if(typeof(e) == 'undefined' && view == false){
16363 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
16375 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
16376 this.tickItems.push(r.data);
16379 if(typeof(e) == 'undefined' && view == false){
16380 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
16387 this.onSelect(r, index);
16389 if(doFocus !== false && !this.blockFocus){
16390 this.inputEl().focus();
16395 restrictHeight : function(){
16396 //this.innerList.dom.style.height = '';
16397 //var inner = this.innerList.dom;
16398 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
16399 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
16400 //this.list.beginUpdate();
16401 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
16402 this.list.alignTo(this.inputEl(), this.listAlign);
16403 this.list.alignTo(this.inputEl(), this.listAlign);
16404 //this.list.endUpdate();
16408 onEmptyResults : function(){
16410 if(this.tickable && this.editable){
16411 this.hasFocus = false;
16412 this.restrictHeight();
16420 * Returns true if the dropdown list is expanded, else false.
16422 isExpanded : function(){
16423 return this.list.isVisible();
16427 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
16428 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16429 * @param {String} value The data value of the item to select
16430 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16431 * selected item if it is not currently in view (defaults to true)
16432 * @return {Boolean} True if the value matched an item in the list, else false
16434 selectByValue : function(v, scrollIntoView){
16435 if(v !== undefined && v !== null){
16436 var r = this.findRecord(this.valueField || this.displayField, v);
16438 this.select(this.store.indexOf(r), scrollIntoView);
16446 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
16447 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16448 * @param {Number} index The zero-based index of the list item to select
16449 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16450 * selected item if it is not currently in view (defaults to true)
16452 select : function(index, scrollIntoView){
16453 this.selectedIndex = index;
16454 this.view.select(index);
16455 if(scrollIntoView !== false){
16456 var el = this.view.getNode(index);
16458 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
16461 this.list.scrollChildIntoView(el, false);
16467 selectNext : function(){
16468 var ct = this.store.getCount();
16470 if(this.selectedIndex == -1){
16472 }else if(this.selectedIndex < ct-1){
16473 this.select(this.selectedIndex+1);
16479 selectPrev : function(){
16480 var ct = this.store.getCount();
16482 if(this.selectedIndex == -1){
16484 }else if(this.selectedIndex != 0){
16485 this.select(this.selectedIndex-1);
16491 onKeyUp : function(e){
16492 if(this.editable !== false && !e.isSpecialKey()){
16493 this.lastKey = e.getKey();
16494 this.dqTask.delay(this.queryDelay);
16499 validateBlur : function(){
16500 return !this.list || !this.list.isVisible();
16504 initQuery : function(){
16506 var v = this.getRawValue();
16508 if(this.tickable && this.editable){
16509 v = this.tickableInputEl().getValue();
16516 doForce : function(){
16517 if(this.inputEl().dom.value.length > 0){
16518 this.inputEl().dom.value =
16519 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
16525 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
16526 * query allowing the query action to be canceled if needed.
16527 * @param {String} query The SQL query to execute
16528 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
16529 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
16530 * saved in the current store (defaults to false)
16532 doQuery : function(q, forceAll){
16534 if(q === undefined || q === null){
16539 forceAll: forceAll,
16543 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
16548 forceAll = qe.forceAll;
16549 if(forceAll === true || (q.length >= this.minChars)){
16551 this.hasQuery = true;
16553 if(this.lastQuery != q || this.alwaysQuery){
16554 this.lastQuery = q;
16555 if(this.mode == 'local'){
16556 this.selectedIndex = -1;
16558 this.store.clearFilter();
16561 if(this.specialFilter){
16562 this.fireEvent('specialfilter', this);
16567 this.store.filter(this.displayField, q);
16570 this.store.fireEvent("datachanged", this.store);
16577 this.store.baseParams[this.queryParam] = q;
16579 var options = {params : this.getParams(q)};
16582 options.add = true;
16583 options.params.start = this.page * this.pageSize;
16586 this.store.load(options);
16589 * this code will make the page width larger, at the beginning, the list not align correctly,
16590 * we should expand the list on onLoad
16591 * so command out it
16596 this.selectedIndex = -1;
16601 this.loadNext = false;
16605 getParams : function(q){
16607 //p[this.queryParam] = q;
16611 p.limit = this.pageSize;
16617 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
16619 collapse : function(){
16620 if(!this.isExpanded()){
16626 this.hasFocus = false;
16630 this.cancelBtn.hide();
16631 this.trigger.show();
16634 this.tickableInputEl().dom.value = '';
16635 this.tickableInputEl().blur();
16640 Roo.get(document).un('mousedown', this.collapseIf, this);
16641 Roo.get(document).un('mousewheel', this.collapseIf, this);
16642 if (!this.editable) {
16643 Roo.get(document).un('keydown', this.listKeyPress, this);
16645 this.fireEvent('collapse', this);
16651 collapseIf : function(e){
16652 var in_combo = e.within(this.el);
16653 var in_list = e.within(this.list);
16654 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
16656 if (in_combo || in_list || is_list) {
16657 //e.stopPropagation();
16662 this.onTickableFooterButtonClick(e, false, false);
16670 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
16672 expand : function(){
16674 if(this.isExpanded() || !this.hasFocus){
16678 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
16679 this.list.setWidth(lw);
16685 this.restrictHeight();
16689 this.tickItems = Roo.apply([], this.item);
16692 this.cancelBtn.show();
16693 this.trigger.hide();
16696 this.tickableInputEl().focus();
16701 Roo.get(document).on('mousedown', this.collapseIf, this);
16702 Roo.get(document).on('mousewheel', this.collapseIf, this);
16703 if (!this.editable) {
16704 Roo.get(document).on('keydown', this.listKeyPress, this);
16707 this.fireEvent('expand', this);
16711 // Implements the default empty TriggerField.onTriggerClick function
16712 onTriggerClick : function(e)
16714 Roo.log('trigger click');
16716 if(this.disabled || !this.triggerList){
16721 this.loadNext = false;
16723 if(this.isExpanded()){
16725 if (!this.blockFocus) {
16726 this.inputEl().focus();
16730 this.hasFocus = true;
16731 if(this.triggerAction == 'all') {
16732 this.doQuery(this.allQuery, true);
16734 this.doQuery(this.getRawValue());
16736 if (!this.blockFocus) {
16737 this.inputEl().focus();
16742 onTickableTriggerClick : function(e)
16749 this.loadNext = false;
16750 this.hasFocus = true;
16752 if(this.triggerAction == 'all') {
16753 this.doQuery(this.allQuery, true);
16755 this.doQuery(this.getRawValue());
16759 onSearchFieldClick : function(e)
16761 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
16762 this.onTickableFooterButtonClick(e, false, false);
16766 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
16771 this.loadNext = false;
16772 this.hasFocus = true;
16774 if(this.triggerAction == 'all') {
16775 this.doQuery(this.allQuery, true);
16777 this.doQuery(this.getRawValue());
16781 listKeyPress : function(e)
16783 //Roo.log('listkeypress');
16784 // scroll to first matching element based on key pres..
16785 if (e.isSpecialKey()) {
16788 var k = String.fromCharCode(e.getKey()).toUpperCase();
16791 var csel = this.view.getSelectedNodes();
16792 var cselitem = false;
16794 var ix = this.view.indexOf(csel[0]);
16795 cselitem = this.store.getAt(ix);
16796 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16802 this.store.each(function(v) {
16804 // start at existing selection.
16805 if (cselitem.id == v.id) {
16811 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16812 match = this.store.indexOf(v);
16818 if (match === false) {
16819 return true; // no more action?
16822 this.view.select(match);
16823 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16824 sn.scrollIntoView(sn.dom.parentNode, false);
16827 onViewScroll : function(e, t){
16829 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){
16833 this.hasQuery = true;
16835 this.loading = this.list.select('.loading', true).first();
16837 if(this.loading === null){
16838 this.list.createChild({
16840 cls: 'loading roo-select2-more-results roo-select2-active',
16841 html: 'Loading more results...'
16844 this.loading = this.list.select('.loading', true).first();
16846 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16848 this.loading.hide();
16851 this.loading.show();
16856 this.loadNext = true;
16858 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16863 addItem : function(o)
16865 var dv = ''; // display value
16867 if (this.displayField) {
16868 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16870 // this is an error condition!!!
16871 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16878 var choice = this.choices.createChild({
16880 cls: 'roo-select2-search-choice',
16889 cls: 'roo-select2-search-choice-close fa fa-times',
16894 }, this.searchField);
16896 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16898 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16906 this.inputEl().dom.value = '';
16911 onRemoveItem : function(e, _self, o)
16913 e.preventDefault();
16915 this.lastItem = Roo.apply([], this.item);
16917 var index = this.item.indexOf(o.data) * 1;
16920 Roo.log('not this item?!');
16924 this.item.splice(index, 1);
16929 this.fireEvent('remove', this, e);
16935 syncValue : function()
16937 if(!this.item.length){
16944 Roo.each(this.item, function(i){
16945 if(_this.valueField){
16946 value.push(i[_this.valueField]);
16953 this.value = value.join(',');
16955 if(this.hiddenField){
16956 this.hiddenField.dom.value = this.value;
16959 this.store.fireEvent("datachanged", this.store);
16964 clearItem : function()
16966 if(!this.multiple){
16972 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16980 if(this.tickable && !Roo.isTouch){
16981 this.view.refresh();
16985 inputEl: function ()
16987 if(Roo.isIOS && this.useNativeIOS){
16988 return this.el.select('select.roo-ios-select', true).first();
16991 if(Roo.isTouch && this.mobileTouchView){
16992 return this.el.select('input.form-control',true).first();
16996 return this.searchField;
16999 return this.el.select('input.form-control',true).first();
17002 onTickableFooterButtonClick : function(e, btn, el)
17004 e.preventDefault();
17006 this.lastItem = Roo.apply([], this.item);
17008 if(btn && btn.name == 'cancel'){
17009 this.tickItems = Roo.apply([], this.item);
17018 Roo.each(this.tickItems, function(o){
17026 validate : function()
17028 if(this.getVisibilityEl().hasClass('hidden')){
17032 var v = this.getRawValue();
17035 v = this.getValue();
17038 if(this.disabled || this.allowBlank || v.length){
17043 this.markInvalid();
17047 tickableInputEl : function()
17049 if(!this.tickable || !this.editable){
17050 return this.inputEl();
17053 return this.inputEl().select('.roo-select2-search-field-input', true).first();
17057 getAutoCreateTouchView : function()
17062 cls: 'form-group' //input-group
17068 type : this.inputType,
17069 cls : 'form-control x-combo-noedit',
17070 autocomplete: 'new-password',
17071 placeholder : this.placeholder || '',
17076 input.name = this.name;
17080 input.cls += ' input-' + this.size;
17083 if (this.disabled) {
17084 input.disabled = true;
17088 cls : 'roo-combobox-wrap',
17095 inputblock.cls += ' input-group';
17097 inputblock.cn.unshift({
17099 cls : 'input-group-addon input-group-prepend input-group-text',
17104 if(this.removable && !this.multiple){
17105 inputblock.cls += ' roo-removable';
17107 inputblock.cn.push({
17110 cls : 'roo-combo-removable-btn close'
17114 if(this.hasFeedback && !this.allowBlank){
17116 inputblock.cls += ' has-feedback';
17118 inputblock.cn.push({
17120 cls: 'glyphicon form-control-feedback'
17127 inputblock.cls += (this.before) ? '' : ' input-group';
17129 inputblock.cn.push({
17131 cls : 'input-group-addon input-group-append input-group-text',
17137 var ibwrap = inputblock;
17142 cls: 'roo-select2-choices',
17146 cls: 'roo-select2-search-field',
17159 cls: 'roo-select2-container input-group roo-touchview-combobox ',
17164 cls: 'form-hidden-field'
17170 if(!this.multiple && this.showToggleBtn){
17176 if (this.caret != false) {
17179 cls: 'fa fa-' + this.caret
17186 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
17188 Roo.bootstrap.version == 3 ? caret : '',
17191 cls: 'combobox-clear',
17205 combobox.cls += ' roo-select2-container-multi';
17208 var align = this.labelAlign || this.parentLabelAlign();
17210 if (align ==='left' && this.fieldLabel.length) {
17215 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17216 tooltip : 'This field is required'
17220 cls : 'control-label col-form-label',
17221 html : this.fieldLabel
17225 cls : 'roo-combobox-wrap ',
17232 var labelCfg = cfg.cn[1];
17233 var contentCfg = cfg.cn[2];
17236 if(this.indicatorpos == 'right'){
17241 cls : 'control-label col-form-label',
17245 html : this.fieldLabel
17249 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17250 tooltip : 'This field is required'
17255 cls : "roo-combobox-wrap ",
17263 labelCfg = cfg.cn[0];
17264 contentCfg = cfg.cn[1];
17269 if(this.labelWidth > 12){
17270 labelCfg.style = "width: " + this.labelWidth + 'px';
17273 if(this.labelWidth < 13 && this.labelmd == 0){
17274 this.labelmd = this.labelWidth;
17277 if(this.labellg > 0){
17278 labelCfg.cls += ' col-lg-' + this.labellg;
17279 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
17282 if(this.labelmd > 0){
17283 labelCfg.cls += ' col-md-' + this.labelmd;
17284 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
17287 if(this.labelsm > 0){
17288 labelCfg.cls += ' col-sm-' + this.labelsm;
17289 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
17292 if(this.labelxs > 0){
17293 labelCfg.cls += ' col-xs-' + this.labelxs;
17294 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
17298 } else if ( this.fieldLabel.length) {
17302 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17303 tooltip : 'This field is required'
17307 cls : 'control-label',
17308 html : this.fieldLabel
17319 if(this.indicatorpos == 'right'){
17323 cls : 'control-label',
17324 html : this.fieldLabel,
17328 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17329 tooltip : 'This field is required'
17346 var settings = this;
17348 ['xs','sm','md','lg'].map(function(size){
17349 if (settings[size]) {
17350 cfg.cls += ' col-' + size + '-' + settings[size];
17357 initTouchView : function()
17359 this.renderTouchView();
17361 this.touchViewEl.on('scroll', function(){
17362 this.el.dom.scrollTop = 0;
17365 this.originalValue = this.getValue();
17367 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
17369 this.inputEl().on("click", this.showTouchView, this);
17370 if (this.triggerEl) {
17371 this.triggerEl.on("click", this.showTouchView, this);
17375 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
17376 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
17378 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
17380 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
17381 this.store.on('load', this.onTouchViewLoad, this);
17382 this.store.on('loadexception', this.onTouchViewLoadException, this);
17384 if(this.hiddenName){
17386 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
17388 this.hiddenField.dom.value =
17389 this.hiddenValue !== undefined ? this.hiddenValue :
17390 this.value !== undefined ? this.value : '';
17392 this.el.dom.removeAttribute('name');
17393 this.hiddenField.dom.setAttribute('name', this.hiddenName);
17397 this.choices = this.el.select('ul.roo-select2-choices', true).first();
17398 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
17401 if(this.removable && !this.multiple){
17402 var close = this.closeTriggerEl();
17404 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
17405 close.on('click', this.removeBtnClick, this, close);
17409 * fix the bug in Safari iOS8
17411 this.inputEl().on("focus", function(e){
17412 document.activeElement.blur();
17415 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
17422 renderTouchView : function()
17424 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
17425 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17427 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
17428 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17430 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
17431 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17432 this.touchViewBodyEl.setStyle('overflow', 'auto');
17434 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
17435 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17437 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
17438 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17442 showTouchView : function()
17448 this.touchViewHeaderEl.hide();
17450 if(this.modalTitle.length){
17451 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
17452 this.touchViewHeaderEl.show();
17455 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
17456 this.touchViewEl.show();
17458 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
17460 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
17461 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17463 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17465 if(this.modalTitle.length){
17466 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17469 this.touchViewBodyEl.setHeight(bodyHeight);
17473 (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
17475 this.touchViewEl.addClass(['in','show']);
17478 if(this._touchViewMask){
17479 Roo.get(document.body).addClass("x-body-masked");
17480 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17481 this._touchViewMask.setStyle('z-index', 10000);
17482 this._touchViewMask.addClass('show');
17485 this.doTouchViewQuery();
17489 hideTouchView : function()
17491 this.touchViewEl.removeClass(['in','show']);
17495 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
17497 this.touchViewEl.setStyle('display', 'none');
17500 if(this._touchViewMask){
17501 this._touchViewMask.removeClass('show');
17502 Roo.get(document.body).removeClass("x-body-masked");
17506 setTouchViewValue : function()
17513 Roo.each(this.tickItems, function(o){
17518 this.hideTouchView();
17521 doTouchViewQuery : function()
17530 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
17534 if(!this.alwaysQuery || this.mode == 'local'){
17535 this.onTouchViewLoad();
17542 onTouchViewBeforeLoad : function(combo,opts)
17548 onTouchViewLoad : function()
17550 if(this.store.getCount() < 1){
17551 this.onTouchViewEmptyResults();
17555 this.clearTouchView();
17557 var rawValue = this.getRawValue();
17559 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
17561 this.tickItems = [];
17563 this.store.data.each(function(d, rowIndex){
17564 var row = this.touchViewListGroup.createChild(template);
17566 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
17567 row.addClass(d.data.cls);
17570 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17573 html : d.data[this.displayField]
17576 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
17577 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
17580 row.removeClass('selected');
17581 if(!this.multiple && this.valueField &&
17582 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
17585 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17586 row.addClass('selected');
17589 if(this.multiple && this.valueField &&
17590 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
17594 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17595 this.tickItems.push(d.data);
17598 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
17602 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
17604 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17606 if(this.modalTitle.length){
17607 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17610 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
17612 if(this.mobile_restrict_height && listHeight < bodyHeight){
17613 this.touchViewBodyEl.setHeight(listHeight);
17618 if(firstChecked && listHeight > bodyHeight){
17619 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
17624 onTouchViewLoadException : function()
17626 this.hideTouchView();
17629 onTouchViewEmptyResults : function()
17631 this.clearTouchView();
17633 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
17635 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
17639 clearTouchView : function()
17641 this.touchViewListGroup.dom.innerHTML = '';
17644 onTouchViewClick : function(e, el, o)
17646 e.preventDefault();
17649 var rowIndex = o.rowIndex;
17651 var r = this.store.getAt(rowIndex);
17653 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
17655 if(!this.multiple){
17656 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
17657 c.dom.removeAttribute('checked');
17660 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17662 this.setFromData(r.data);
17664 var close = this.closeTriggerEl();
17670 this.hideTouchView();
17672 this.fireEvent('select', this, r, rowIndex);
17677 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
17678 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
17679 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
17683 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17684 this.addItem(r.data);
17685 this.tickItems.push(r.data);
17689 getAutoCreateNativeIOS : function()
17692 cls: 'form-group' //input-group,
17697 cls : 'roo-ios-select'
17701 combobox.name = this.name;
17704 if (this.disabled) {
17705 combobox.disabled = true;
17708 var settings = this;
17710 ['xs','sm','md','lg'].map(function(size){
17711 if (settings[size]) {
17712 cfg.cls += ' col-' + size + '-' + settings[size];
17722 initIOSView : function()
17724 this.store.on('load', this.onIOSViewLoad, this);
17729 onIOSViewLoad : function()
17731 if(this.store.getCount() < 1){
17735 this.clearIOSView();
17737 if(this.allowBlank) {
17739 var default_text = '-- SELECT --';
17741 if(this.placeholder.length){
17742 default_text = this.placeholder;
17745 if(this.emptyTitle.length){
17746 default_text += ' - ' + this.emptyTitle + ' -';
17749 var opt = this.inputEl().createChild({
17752 html : default_text
17756 o[this.valueField] = 0;
17757 o[this.displayField] = default_text;
17759 this.ios_options.push({
17766 this.store.data.each(function(d, rowIndex){
17770 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17771 html = d.data[this.displayField];
17776 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
17777 value = d.data[this.valueField];
17786 if(this.value == d.data[this.valueField]){
17787 option['selected'] = true;
17790 var opt = this.inputEl().createChild(option);
17792 this.ios_options.push({
17799 this.inputEl().on('change', function(){
17800 this.fireEvent('select', this);
17805 clearIOSView: function()
17807 this.inputEl().dom.innerHTML = '';
17809 this.ios_options = [];
17812 setIOSValue: function(v)
17816 if(!this.ios_options){
17820 Roo.each(this.ios_options, function(opts){
17822 opts.el.dom.removeAttribute('selected');
17824 if(opts.data[this.valueField] != v){
17828 opts.el.dom.setAttribute('selected', true);
17834 * @cfg {Boolean} grow
17838 * @cfg {Number} growMin
17842 * @cfg {Number} growMax
17851 Roo.apply(Roo.bootstrap.ComboBox, {
17855 cls: 'modal-header',
17877 cls: 'list-group-item',
17881 cls: 'roo-combobox-list-group-item-value'
17885 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17899 listItemCheckbox : {
17901 cls: 'list-group-item',
17905 cls: 'roo-combobox-list-group-item-value'
17909 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17925 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17930 cls: 'modal-footer',
17938 cls: 'col-xs-6 text-left',
17941 cls: 'btn btn-danger roo-touch-view-cancel',
17947 cls: 'col-xs-6 text-right',
17950 cls: 'btn btn-success roo-touch-view-ok',
17961 Roo.apply(Roo.bootstrap.ComboBox, {
17963 touchViewTemplate : {
17965 cls: 'modal fade roo-combobox-touch-view',
17969 cls: 'modal-dialog',
17970 style : 'position:fixed', // we have to fix position....
17974 cls: 'modal-content',
17976 Roo.bootstrap.ComboBox.header,
17977 Roo.bootstrap.ComboBox.body,
17978 Roo.bootstrap.ComboBox.footer
17987 * Ext JS Library 1.1.1
17988 * Copyright(c) 2006-2007, Ext JS, LLC.
17990 * Originally Released Under LGPL - original licence link has changed is not relivant.
17993 * <script type="text/javascript">
17998 * @extends Roo.util.Observable
17999 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
18000 * This class also supports single and multi selection modes. <br>
18001 * Create a data model bound view:
18003 var store = new Roo.data.Store(...);
18005 var view = new Roo.View({
18007 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
18009 singleSelect: true,
18010 selectedClass: "ydataview-selected",
18014 // listen for node click?
18015 view.on("click", function(vw, index, node, e){
18016 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
18020 dataModel.load("foobar.xml");
18022 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
18024 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
18025 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
18027 * Note: old style constructor is still suported (container, template, config)
18030 * Create a new View
18031 * @param {Object} config The config object
18034 Roo.View = function(config, depreciated_tpl, depreciated_config){
18036 this.parent = false;
18038 if (typeof(depreciated_tpl) == 'undefined') {
18039 // new way.. - universal constructor.
18040 Roo.apply(this, config);
18041 this.el = Roo.get(this.el);
18044 this.el = Roo.get(config);
18045 this.tpl = depreciated_tpl;
18046 Roo.apply(this, depreciated_config);
18048 this.wrapEl = this.el.wrap().wrap();
18049 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
18052 if(typeof(this.tpl) == "string"){
18053 this.tpl = new Roo.Template(this.tpl);
18055 // support xtype ctors..
18056 this.tpl = new Roo.factory(this.tpl, Roo);
18060 this.tpl.compile();
18065 * @event beforeclick
18066 * Fires before a click is processed. Returns false to cancel the default action.
18067 * @param {Roo.View} this
18068 * @param {Number} index The index of the target node
18069 * @param {HTMLElement} node The target node
18070 * @param {Roo.EventObject} e The raw event object
18072 "beforeclick" : true,
18075 * Fires when a template node is clicked.
18076 * @param {Roo.View} this
18077 * @param {Number} index The index of the target node
18078 * @param {HTMLElement} node The target node
18079 * @param {Roo.EventObject} e The raw event object
18084 * Fires when a template node is double clicked.
18085 * @param {Roo.View} this
18086 * @param {Number} index The index of the target node
18087 * @param {HTMLElement} node The target node
18088 * @param {Roo.EventObject} e The raw event object
18092 * @event contextmenu
18093 * Fires when a template node is right clicked.
18094 * @param {Roo.View} this
18095 * @param {Number} index The index of the target node
18096 * @param {HTMLElement} node The target node
18097 * @param {Roo.EventObject} e The raw event object
18099 "contextmenu" : true,
18101 * @event selectionchange
18102 * Fires when the selected nodes change.
18103 * @param {Roo.View} this
18104 * @param {Array} selections Array of the selected nodes
18106 "selectionchange" : true,
18109 * @event beforeselect
18110 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
18111 * @param {Roo.View} this
18112 * @param {HTMLElement} node The node to be selected
18113 * @param {Array} selections Array of currently selected nodes
18115 "beforeselect" : true,
18117 * @event preparedata
18118 * Fires on every row to render, to allow you to change the data.
18119 * @param {Roo.View} this
18120 * @param {Object} data to be rendered (change this)
18122 "preparedata" : true
18130 "click": this.onClick,
18131 "dblclick": this.onDblClick,
18132 "contextmenu": this.onContextMenu,
18136 this.selections = [];
18138 this.cmp = new Roo.CompositeElementLite([]);
18140 this.store = Roo.factory(this.store, Roo.data);
18141 this.setStore(this.store, true);
18144 if ( this.footer && this.footer.xtype) {
18146 var fctr = this.wrapEl.appendChild(document.createElement("div"));
18148 this.footer.dataSource = this.store;
18149 this.footer.container = fctr;
18150 this.footer = Roo.factory(this.footer, Roo);
18151 fctr.insertFirst(this.el);
18153 // this is a bit insane - as the paging toolbar seems to detach the el..
18154 // dom.parentNode.parentNode.parentNode
18155 // they get detached?
18159 Roo.View.superclass.constructor.call(this);
18164 Roo.extend(Roo.View, Roo.util.Observable, {
18167 * @cfg {Roo.data.Store} store Data store to load data from.
18172 * @cfg {String|Roo.Element} el The container element.
18177 * @cfg {String|Roo.Template} tpl The template used by this View
18181 * @cfg {String} dataName the named area of the template to use as the data area
18182 * Works with domtemplates roo-name="name"
18186 * @cfg {String} selectedClass The css class to add to selected nodes
18188 selectedClass : "x-view-selected",
18190 * @cfg {String} emptyText The empty text to show when nothing is loaded.
18195 * @cfg {String} text to display on mask (default Loading)
18199 * @cfg {Boolean} multiSelect Allow multiple selection
18201 multiSelect : false,
18203 * @cfg {Boolean} singleSelect Allow single selection
18205 singleSelect: false,
18208 * @cfg {Boolean} toggleSelect - selecting
18210 toggleSelect : false,
18213 * @cfg {Boolean} tickable - selecting
18218 * Returns the element this view is bound to.
18219 * @return {Roo.Element}
18221 getEl : function(){
18222 return this.wrapEl;
18228 * Refreshes the view. - called by datachanged on the store. - do not call directly.
18230 refresh : function(){
18231 //Roo.log('refresh');
18234 // if we are using something like 'domtemplate', then
18235 // the what gets used is:
18236 // t.applySubtemplate(NAME, data, wrapping data..)
18237 // the outer template then get' applied with
18238 // the store 'extra data'
18239 // and the body get's added to the
18240 // roo-name="data" node?
18241 // <span class='roo-tpl-{name}'></span> ?????
18245 this.clearSelections();
18246 this.el.update("");
18248 var records = this.store.getRange();
18249 if(records.length < 1) {
18251 // is this valid?? = should it render a template??
18253 this.el.update(this.emptyText);
18257 if (this.dataName) {
18258 this.el.update(t.apply(this.store.meta)); //????
18259 el = this.el.child('.roo-tpl-' + this.dataName);
18262 for(var i = 0, len = records.length; i < len; i++){
18263 var data = this.prepareData(records[i].data, i, records[i]);
18264 this.fireEvent("preparedata", this, data, i, records[i]);
18266 var d = Roo.apply({}, data);
18269 Roo.apply(d, {'roo-id' : Roo.id()});
18273 Roo.each(this.parent.item, function(item){
18274 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
18277 Roo.apply(d, {'roo-data-checked' : 'checked'});
18281 html[html.length] = Roo.util.Format.trim(
18283 t.applySubtemplate(this.dataName, d, this.store.meta) :
18290 el.update(html.join(""));
18291 this.nodes = el.dom.childNodes;
18292 this.updateIndexes(0);
18297 * Function to override to reformat the data that is sent to
18298 * the template for each node.
18299 * DEPRICATED - use the preparedata event handler.
18300 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
18301 * a JSON object for an UpdateManager bound view).
18303 prepareData : function(data, index, record)
18305 this.fireEvent("preparedata", this, data, index, record);
18309 onUpdate : function(ds, record){
18310 // Roo.log('on update');
18311 this.clearSelections();
18312 var index = this.store.indexOf(record);
18313 var n = this.nodes[index];
18314 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
18315 n.parentNode.removeChild(n);
18316 this.updateIndexes(index, index);
18322 onAdd : function(ds, records, index)
18324 //Roo.log(['on Add', ds, records, index] );
18325 this.clearSelections();
18326 if(this.nodes.length == 0){
18330 var n = this.nodes[index];
18331 for(var i = 0, len = records.length; i < len; i++){
18332 var d = this.prepareData(records[i].data, i, records[i]);
18334 this.tpl.insertBefore(n, d);
18337 this.tpl.append(this.el, d);
18340 this.updateIndexes(index);
18343 onRemove : function(ds, record, index){
18344 // Roo.log('onRemove');
18345 this.clearSelections();
18346 var el = this.dataName ?
18347 this.el.child('.roo-tpl-' + this.dataName) :
18350 el.dom.removeChild(this.nodes[index]);
18351 this.updateIndexes(index);
18355 * Refresh an individual node.
18356 * @param {Number} index
18358 refreshNode : function(index){
18359 this.onUpdate(this.store, this.store.getAt(index));
18362 updateIndexes : function(startIndex, endIndex){
18363 var ns = this.nodes;
18364 startIndex = startIndex || 0;
18365 endIndex = endIndex || ns.length - 1;
18366 for(var i = startIndex; i <= endIndex; i++){
18367 ns[i].nodeIndex = i;
18372 * Changes the data store this view uses and refresh the view.
18373 * @param {Store} store
18375 setStore : function(store, initial){
18376 if(!initial && this.store){
18377 this.store.un("datachanged", this.refresh);
18378 this.store.un("add", this.onAdd);
18379 this.store.un("remove", this.onRemove);
18380 this.store.un("update", this.onUpdate);
18381 this.store.un("clear", this.refresh);
18382 this.store.un("beforeload", this.onBeforeLoad);
18383 this.store.un("load", this.onLoad);
18384 this.store.un("loadexception", this.onLoad);
18388 store.on("datachanged", this.refresh, this);
18389 store.on("add", this.onAdd, this);
18390 store.on("remove", this.onRemove, this);
18391 store.on("update", this.onUpdate, this);
18392 store.on("clear", this.refresh, this);
18393 store.on("beforeload", this.onBeforeLoad, this);
18394 store.on("load", this.onLoad, this);
18395 store.on("loadexception", this.onLoad, this);
18403 * onbeforeLoad - masks the loading area.
18406 onBeforeLoad : function(store,opts)
18408 //Roo.log('onBeforeLoad');
18410 this.el.update("");
18412 this.el.mask(this.mask ? this.mask : "Loading" );
18414 onLoad : function ()
18421 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
18422 * @param {HTMLElement} node
18423 * @return {HTMLElement} The template node
18425 findItemFromChild : function(node){
18426 var el = this.dataName ?
18427 this.el.child('.roo-tpl-' + this.dataName,true) :
18430 if(!node || node.parentNode == el){
18433 var p = node.parentNode;
18434 while(p && p != el){
18435 if(p.parentNode == el){
18444 onClick : function(e){
18445 var item = this.findItemFromChild(e.getTarget());
18447 var index = this.indexOf(item);
18448 if(this.onItemClick(item, index, e) !== false){
18449 this.fireEvent("click", this, index, item, e);
18452 this.clearSelections();
18457 onContextMenu : function(e){
18458 var item = this.findItemFromChild(e.getTarget());
18460 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
18465 onDblClick : function(e){
18466 var item = this.findItemFromChild(e.getTarget());
18468 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
18472 onItemClick : function(item, index, e)
18474 if(this.fireEvent("beforeclick", this, index, item, e) === false){
18477 if (this.toggleSelect) {
18478 var m = this.isSelected(item) ? 'unselect' : 'select';
18481 _t[m](item, true, false);
18484 if(this.multiSelect || this.singleSelect){
18485 if(this.multiSelect && e.shiftKey && this.lastSelection){
18486 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
18488 this.select(item, this.multiSelect && e.ctrlKey);
18489 this.lastSelection = item;
18492 if(!this.tickable){
18493 e.preventDefault();
18501 * Get the number of selected nodes.
18504 getSelectionCount : function(){
18505 return this.selections.length;
18509 * Get the currently selected nodes.
18510 * @return {Array} An array of HTMLElements
18512 getSelectedNodes : function(){
18513 return this.selections;
18517 * Get the indexes of the selected nodes.
18520 getSelectedIndexes : function(){
18521 var indexes = [], s = this.selections;
18522 for(var i = 0, len = s.length; i < len; i++){
18523 indexes.push(s[i].nodeIndex);
18529 * Clear all selections
18530 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
18532 clearSelections : function(suppressEvent){
18533 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
18534 this.cmp.elements = this.selections;
18535 this.cmp.removeClass(this.selectedClass);
18536 this.selections = [];
18537 if(!suppressEvent){
18538 this.fireEvent("selectionchange", this, this.selections);
18544 * Returns true if the passed node is selected
18545 * @param {HTMLElement/Number} node The node or node index
18546 * @return {Boolean}
18548 isSelected : function(node){
18549 var s = this.selections;
18553 node = this.getNode(node);
18554 return s.indexOf(node) !== -1;
18559 * @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
18560 * @param {Boolean} keepExisting (optional) true to keep existing selections
18561 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18563 select : function(nodeInfo, keepExisting, suppressEvent){
18564 if(nodeInfo instanceof Array){
18566 this.clearSelections(true);
18568 for(var i = 0, len = nodeInfo.length; i < len; i++){
18569 this.select(nodeInfo[i], true, true);
18573 var node = this.getNode(nodeInfo);
18574 if(!node || this.isSelected(node)){
18575 return; // already selected.
18578 this.clearSelections(true);
18581 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
18582 Roo.fly(node).addClass(this.selectedClass);
18583 this.selections.push(node);
18584 if(!suppressEvent){
18585 this.fireEvent("selectionchange", this, this.selections);
18593 * @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
18594 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
18595 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18597 unselect : function(nodeInfo, keepExisting, suppressEvent)
18599 if(nodeInfo instanceof Array){
18600 Roo.each(this.selections, function(s) {
18601 this.unselect(s, nodeInfo);
18605 var node = this.getNode(nodeInfo);
18606 if(!node || !this.isSelected(node)){
18607 //Roo.log("not selected");
18608 return; // not selected.
18612 Roo.each(this.selections, function(s) {
18614 Roo.fly(node).removeClass(this.selectedClass);
18621 this.selections= ns;
18622 this.fireEvent("selectionchange", this, this.selections);
18626 * Gets a template node.
18627 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18628 * @return {HTMLElement} The node or null if it wasn't found
18630 getNode : function(nodeInfo){
18631 if(typeof nodeInfo == "string"){
18632 return document.getElementById(nodeInfo);
18633 }else if(typeof nodeInfo == "number"){
18634 return this.nodes[nodeInfo];
18640 * Gets a range template nodes.
18641 * @param {Number} startIndex
18642 * @param {Number} endIndex
18643 * @return {Array} An array of nodes
18645 getNodes : function(start, end){
18646 var ns = this.nodes;
18647 start = start || 0;
18648 end = typeof end == "undefined" ? ns.length - 1 : end;
18651 for(var i = start; i <= end; i++){
18655 for(var i = start; i >= end; i--){
18663 * Finds the index of the passed node
18664 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18665 * @return {Number} The index of the node or -1
18667 indexOf : function(node){
18668 node = this.getNode(node);
18669 if(typeof node.nodeIndex == "number"){
18670 return node.nodeIndex;
18672 var ns = this.nodes;
18673 for(var i = 0, len = ns.length; i < len; i++){
18684 * based on jquery fullcalendar
18688 Roo.bootstrap = Roo.bootstrap || {};
18690 * @class Roo.bootstrap.Calendar
18691 * @extends Roo.bootstrap.Component
18692 * Bootstrap Calendar class
18693 * @cfg {Boolean} loadMask (true|false) default false
18694 * @cfg {Object} header generate the user specific header of the calendar, default false
18697 * Create a new Container
18698 * @param {Object} config The config object
18703 Roo.bootstrap.Calendar = function(config){
18704 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
18708 * Fires when a date is selected
18709 * @param {DatePicker} this
18710 * @param {Date} date The selected date
18714 * @event monthchange
18715 * Fires when the displayed month changes
18716 * @param {DatePicker} this
18717 * @param {Date} date The selected month
18719 'monthchange': true,
18721 * @event evententer
18722 * Fires when mouse over an event
18723 * @param {Calendar} this
18724 * @param {event} Event
18726 'evententer': true,
18728 * @event eventleave
18729 * Fires when the mouse leaves an
18730 * @param {Calendar} this
18733 'eventleave': true,
18735 * @event eventclick
18736 * Fires when the mouse click an
18737 * @param {Calendar} this
18746 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
18749 * @cfg {Number} startDay
18750 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
18758 getAutoCreate : function(){
18761 var fc_button = function(name, corner, style, content ) {
18762 return Roo.apply({},{
18764 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
18766 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
18769 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
18780 style : 'width:100%',
18787 cls : 'fc-header-left',
18789 fc_button('prev', 'left', 'arrow', '‹' ),
18790 fc_button('next', 'right', 'arrow', '›' ),
18791 { tag: 'span', cls: 'fc-header-space' },
18792 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
18800 cls : 'fc-header-center',
18804 cls: 'fc-header-title',
18807 html : 'month / year'
18815 cls : 'fc-header-right',
18817 /* fc_button('month', 'left', '', 'month' ),
18818 fc_button('week', '', '', 'week' ),
18819 fc_button('day', 'right', '', 'day' )
18831 header = this.header;
18834 var cal_heads = function() {
18836 // fixme - handle this.
18838 for (var i =0; i < Date.dayNames.length; i++) {
18839 var d = Date.dayNames[i];
18842 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18843 html : d.substring(0,3)
18847 ret[0].cls += ' fc-first';
18848 ret[6].cls += ' fc-last';
18851 var cal_cell = function(n) {
18854 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18859 cls: 'fc-day-number',
18863 cls: 'fc-day-content',
18867 style: 'position: relative;' // height: 17px;
18879 var cal_rows = function() {
18882 for (var r = 0; r < 6; r++) {
18889 for (var i =0; i < Date.dayNames.length; i++) {
18890 var d = Date.dayNames[i];
18891 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18894 row.cn[0].cls+=' fc-first';
18895 row.cn[0].cn[0].style = 'min-height:90px';
18896 row.cn[6].cls+=' fc-last';
18900 ret[0].cls += ' fc-first';
18901 ret[4].cls += ' fc-prev-last';
18902 ret[5].cls += ' fc-last';
18909 cls: 'fc-border-separate',
18910 style : 'width:100%',
18918 cls : 'fc-first fc-last',
18936 cls : 'fc-content',
18937 style : "position: relative;",
18940 cls : 'fc-view fc-view-month fc-grid',
18941 style : 'position: relative',
18942 unselectable : 'on',
18945 cls : 'fc-event-container',
18946 style : 'position:absolute;z-index:8;top:0;left:0;'
18964 initEvents : function()
18967 throw "can not find store for calendar";
18973 style: "text-align:center",
18977 style: "background-color:white;width:50%;margin:250 auto",
18981 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18992 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18994 var size = this.el.select('.fc-content', true).first().getSize();
18995 this.maskEl.setSize(size.width, size.height);
18996 this.maskEl.enableDisplayMode("block");
18997 if(!this.loadMask){
18998 this.maskEl.hide();
19001 this.store = Roo.factory(this.store, Roo.data);
19002 this.store.on('load', this.onLoad, this);
19003 this.store.on('beforeload', this.onBeforeLoad, this);
19007 this.cells = this.el.select('.fc-day',true);
19008 //Roo.log(this.cells);
19009 this.textNodes = this.el.query('.fc-day-number');
19010 this.cells.addClassOnOver('fc-state-hover');
19012 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
19013 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
19014 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
19015 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
19017 this.on('monthchange', this.onMonthChange, this);
19019 this.update(new Date().clearTime());
19022 resize : function() {
19023 var sz = this.el.getSize();
19025 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
19026 this.el.select('.fc-day-content div',true).setHeight(34);
19031 showPrevMonth : function(e){
19032 this.update(this.activeDate.add("mo", -1));
19034 showToday : function(e){
19035 this.update(new Date().clearTime());
19038 showNextMonth : function(e){
19039 this.update(this.activeDate.add("mo", 1));
19043 showPrevYear : function(){
19044 this.update(this.activeDate.add("y", -1));
19048 showNextYear : function(){
19049 this.update(this.activeDate.add("y", 1));
19054 update : function(date)
19056 var vd = this.activeDate;
19057 this.activeDate = date;
19058 // if(vd && this.el){
19059 // var t = date.getTime();
19060 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
19061 // Roo.log('using add remove');
19063 // this.fireEvent('monthchange', this, date);
19065 // this.cells.removeClass("fc-state-highlight");
19066 // this.cells.each(function(c){
19067 // if(c.dateValue == t){
19068 // c.addClass("fc-state-highlight");
19069 // setTimeout(function(){
19070 // try{c.dom.firstChild.focus();}catch(e){}
19080 var days = date.getDaysInMonth();
19082 var firstOfMonth = date.getFirstDateOfMonth();
19083 var startingPos = firstOfMonth.getDay()-this.startDay;
19085 if(startingPos < this.startDay){
19089 var pm = date.add(Date.MONTH, -1);
19090 var prevStart = pm.getDaysInMonth()-startingPos;
19092 this.cells = this.el.select('.fc-day',true);
19093 this.textNodes = this.el.query('.fc-day-number');
19094 this.cells.addClassOnOver('fc-state-hover');
19096 var cells = this.cells.elements;
19097 var textEls = this.textNodes;
19099 Roo.each(cells, function(cell){
19100 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
19103 days += startingPos;
19105 // convert everything to numbers so it's fast
19106 var day = 86400000;
19107 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
19110 //Roo.log(prevStart);
19112 var today = new Date().clearTime().getTime();
19113 var sel = date.clearTime().getTime();
19114 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
19115 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
19116 var ddMatch = this.disabledDatesRE;
19117 var ddText = this.disabledDatesText;
19118 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
19119 var ddaysText = this.disabledDaysText;
19120 var format = this.format;
19122 var setCellClass = function(cal, cell){
19126 //Roo.log('set Cell Class');
19128 var t = d.getTime();
19132 cell.dateValue = t;
19134 cell.className += " fc-today";
19135 cell.className += " fc-state-highlight";
19136 cell.title = cal.todayText;
19139 // disable highlight in other month..
19140 //cell.className += " fc-state-highlight";
19145 cell.className = " fc-state-disabled";
19146 cell.title = cal.minText;
19150 cell.className = " fc-state-disabled";
19151 cell.title = cal.maxText;
19155 if(ddays.indexOf(d.getDay()) != -1){
19156 cell.title = ddaysText;
19157 cell.className = " fc-state-disabled";
19160 if(ddMatch && format){
19161 var fvalue = d.dateFormat(format);
19162 if(ddMatch.test(fvalue)){
19163 cell.title = ddText.replace("%0", fvalue);
19164 cell.className = " fc-state-disabled";
19168 if (!cell.initialClassName) {
19169 cell.initialClassName = cell.dom.className;
19172 cell.dom.className = cell.initialClassName + ' ' + cell.className;
19177 for(; i < startingPos; i++) {
19178 textEls[i].innerHTML = (++prevStart);
19179 d.setDate(d.getDate()+1);
19181 cells[i].className = "fc-past fc-other-month";
19182 setCellClass(this, cells[i]);
19187 for(; i < days; i++){
19188 intDay = i - startingPos + 1;
19189 textEls[i].innerHTML = (intDay);
19190 d.setDate(d.getDate()+1);
19192 cells[i].className = ''; // "x-date-active";
19193 setCellClass(this, cells[i]);
19197 for(; i < 42; i++) {
19198 textEls[i].innerHTML = (++extraDays);
19199 d.setDate(d.getDate()+1);
19201 cells[i].className = "fc-future fc-other-month";
19202 setCellClass(this, cells[i]);
19205 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
19207 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
19209 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
19210 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
19212 if(totalRows != 6){
19213 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
19214 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
19217 this.fireEvent('monthchange', this, date);
19221 if(!this.internalRender){
19222 var main = this.el.dom.firstChild;
19223 var w = main.offsetWidth;
19224 this.el.setWidth(w + this.el.getBorderWidth("lr"));
19225 Roo.fly(main).setWidth(w);
19226 this.internalRender = true;
19227 // opera does not respect the auto grow header center column
19228 // then, after it gets a width opera refuses to recalculate
19229 // without a second pass
19230 if(Roo.isOpera && !this.secondPass){
19231 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
19232 this.secondPass = true;
19233 this.update.defer(10, this, [date]);
19240 findCell : function(dt) {
19241 dt = dt.clearTime().getTime();
19243 this.cells.each(function(c){
19244 //Roo.log("check " +c.dateValue + '?=' + dt);
19245 if(c.dateValue == dt){
19255 findCells : function(ev) {
19256 var s = ev.start.clone().clearTime().getTime();
19258 var e= ev.end.clone().clearTime().getTime();
19261 this.cells.each(function(c){
19262 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
19264 if(c.dateValue > e){
19267 if(c.dateValue < s){
19276 // findBestRow: function(cells)
19280 // for (var i =0 ; i < cells.length;i++) {
19281 // ret = Math.max(cells[i].rows || 0,ret);
19288 addItem : function(ev)
19290 // look for vertical location slot in
19291 var cells = this.findCells(ev);
19293 // ev.row = this.findBestRow(cells);
19295 // work out the location.
19299 for(var i =0; i < cells.length; i++) {
19301 cells[i].row = cells[0].row;
19304 cells[i].row = cells[i].row + 1;
19314 if (crow.start.getY() == cells[i].getY()) {
19316 crow.end = cells[i];
19333 cells[0].events.push(ev);
19335 this.calevents.push(ev);
19338 clearEvents: function() {
19340 if(!this.calevents){
19344 Roo.each(this.cells.elements, function(c){
19350 Roo.each(this.calevents, function(e) {
19351 Roo.each(e.els, function(el) {
19352 el.un('mouseenter' ,this.onEventEnter, this);
19353 el.un('mouseleave' ,this.onEventLeave, this);
19358 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
19364 renderEvents: function()
19368 this.cells.each(function(c) {
19377 if(c.row != c.events.length){
19378 r = 4 - (4 - (c.row - c.events.length));
19381 c.events = ev.slice(0, r);
19382 c.more = ev.slice(r);
19384 if(c.more.length && c.more.length == 1){
19385 c.events.push(c.more.pop());
19388 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
19392 this.cells.each(function(c) {
19394 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
19397 for (var e = 0; e < c.events.length; e++){
19398 var ev = c.events[e];
19399 var rows = ev.rows;
19401 for(var i = 0; i < rows.length; i++) {
19403 // how many rows should it span..
19406 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
19407 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
19409 unselectable : "on",
19412 cls: 'fc-event-inner',
19416 // cls: 'fc-event-time',
19417 // html : cells.length > 1 ? '' : ev.time
19421 cls: 'fc-event-title',
19422 html : String.format('{0}', ev.title)
19429 cls: 'ui-resizable-handle ui-resizable-e',
19430 html : '  '
19437 cfg.cls += ' fc-event-start';
19439 if ((i+1) == rows.length) {
19440 cfg.cls += ' fc-event-end';
19443 var ctr = _this.el.select('.fc-event-container',true).first();
19444 var cg = ctr.createChild(cfg);
19446 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
19447 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
19449 var r = (c.more.length) ? 1 : 0;
19450 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
19451 cg.setWidth(ebox.right - sbox.x -2);
19453 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
19454 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
19455 cg.on('click', _this.onEventClick, _this, ev);
19466 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
19467 style : 'position: absolute',
19468 unselectable : "on",
19471 cls: 'fc-event-inner',
19475 cls: 'fc-event-title',
19483 cls: 'ui-resizable-handle ui-resizable-e',
19484 html : '  '
19490 var ctr = _this.el.select('.fc-event-container',true).first();
19491 var cg = ctr.createChild(cfg);
19493 var sbox = c.select('.fc-day-content',true).first().getBox();
19494 var ebox = c.select('.fc-day-content',true).first().getBox();
19496 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
19497 cg.setWidth(ebox.right - sbox.x -2);
19499 cg.on('click', _this.onMoreEventClick, _this, c.more);
19509 onEventEnter: function (e, el,event,d) {
19510 this.fireEvent('evententer', this, el, event);
19513 onEventLeave: function (e, el,event,d) {
19514 this.fireEvent('eventleave', this, el, event);
19517 onEventClick: function (e, el,event,d) {
19518 this.fireEvent('eventclick', this, el, event);
19521 onMonthChange: function () {
19525 onMoreEventClick: function(e, el, more)
19529 this.calpopover.placement = 'right';
19530 this.calpopover.setTitle('More');
19532 this.calpopover.setContent('');
19534 var ctr = this.calpopover.el.select('.popover-content', true).first();
19536 Roo.each(more, function(m){
19538 cls : 'fc-event-hori fc-event-draggable',
19541 var cg = ctr.createChild(cfg);
19543 cg.on('click', _this.onEventClick, _this, m);
19546 this.calpopover.show(el);
19551 onLoad: function ()
19553 this.calevents = [];
19556 if(this.store.getCount() > 0){
19557 this.store.data.each(function(d){
19560 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
19561 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
19562 time : d.data.start_time,
19563 title : d.data.title,
19564 description : d.data.description,
19565 venue : d.data.venue
19570 this.renderEvents();
19572 if(this.calevents.length && this.loadMask){
19573 this.maskEl.hide();
19577 onBeforeLoad: function()
19579 this.clearEvents();
19581 this.maskEl.show();
19595 * @class Roo.bootstrap.Popover
19596 * @extends Roo.bootstrap.Component
19597 * Bootstrap Popover class
19598 * @cfg {String} html contents of the popover (or false to use children..)
19599 * @cfg {String} title of popover (or false to hide)
19600 * @cfg {String} placement how it is placed
19601 * @cfg {String} trigger click || hover (or false to trigger manually)
19602 * @cfg {String} over what (parent or false to trigger manually.)
19603 * @cfg {Number} delay - delay before showing
19606 * Create a new Popover
19607 * @param {Object} config The config object
19610 Roo.bootstrap.Popover = function(config){
19611 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
19617 * After the popover show
19619 * @param {Roo.bootstrap.Popover} this
19624 * After the popover hide
19626 * @param {Roo.bootstrap.Popover} this
19632 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
19634 title: 'Fill in a title',
19637 placement : 'right',
19638 trigger : 'hover', // hover
19644 can_build_overlaid : false,
19646 getChildContainer : function()
19648 return this.el.select('.popover-content',true).first();
19651 getAutoCreate : function(){
19654 cls : 'popover roo-dynamic',
19655 style: 'display:block',
19661 cls : 'popover-inner',
19665 cls: 'popover-title popover-header',
19669 cls : 'popover-content popover-body',
19680 setTitle: function(str)
19683 this.el.select('.popover-title',true).first().dom.innerHTML = str;
19685 setContent: function(str)
19688 this.el.select('.popover-content',true).first().dom.innerHTML = str;
19690 // as it get's added to the bottom of the page.
19691 onRender : function(ct, position)
19693 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19695 var cfg = Roo.apply({}, this.getAutoCreate());
19699 cfg.cls += ' ' + this.cls;
19702 cfg.style = this.style;
19704 //Roo.log("adding to ");
19705 this.el = Roo.get(document.body).createChild(cfg, position);
19706 // Roo.log(this.el);
19711 initEvents : function()
19713 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
19714 this.el.enableDisplayMode('block');
19716 if (this.over === false) {
19719 if (this.triggers === false) {
19722 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19723 var triggers = this.trigger ? this.trigger.split(' ') : [];
19724 Roo.each(triggers, function(trigger) {
19726 if (trigger == 'click') {
19727 on_el.on('click', this.toggle, this);
19728 } else if (trigger != 'manual') {
19729 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
19730 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
19732 on_el.on(eventIn ,this.enter, this);
19733 on_el.on(eventOut, this.leave, this);
19744 toggle : function () {
19745 this.hoverState == 'in' ? this.leave() : this.enter();
19748 enter : function () {
19750 clearTimeout(this.timeout);
19752 this.hoverState = 'in';
19754 if (!this.delay || !this.delay.show) {
19759 this.timeout = setTimeout(function () {
19760 if (_t.hoverState == 'in') {
19763 }, this.delay.show)
19766 leave : function() {
19767 clearTimeout(this.timeout);
19769 this.hoverState = 'out';
19771 if (!this.delay || !this.delay.hide) {
19776 this.timeout = setTimeout(function () {
19777 if (_t.hoverState == 'out') {
19780 }, this.delay.hide)
19783 show : function (on_el)
19786 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19790 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
19791 if (this.html !== false) {
19792 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
19794 this.el.removeClass([
19795 'fade','top','bottom', 'left', 'right','in',
19796 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
19798 if (!this.title.length) {
19799 this.el.select('.popover-title',true).hide();
19802 var placement = typeof this.placement == 'function' ?
19803 this.placement.call(this, this.el, on_el) :
19806 var autoToken = /\s?auto?\s?/i;
19807 var autoPlace = autoToken.test(placement);
19809 placement = placement.replace(autoToken, '') || 'top';
19813 //this.el.setXY([0,0]);
19815 this.el.dom.style.display='block';
19816 this.el.addClass(placement);
19818 //this.el.appendTo(on_el);
19820 var p = this.getPosition();
19821 var box = this.el.getBox();
19826 var align = Roo.bootstrap.Popover.alignment[placement];
19829 this.el.alignTo(on_el, align[0],align[1]);
19830 //var arrow = this.el.select('.arrow',true).first();
19831 //arrow.set(align[2],
19833 this.el.addClass('in');
19836 if (this.el.hasClass('fade')) {
19840 this.hoverState = 'in';
19842 this.fireEvent('show', this);
19847 this.el.setXY([0,0]);
19848 this.el.removeClass('in');
19850 this.hoverState = null;
19852 this.fireEvent('hide', this);
19857 Roo.bootstrap.Popover.alignment = {
19858 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19859 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19860 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19861 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19872 * @class Roo.bootstrap.Progress
19873 * @extends Roo.bootstrap.Component
19874 * Bootstrap Progress class
19875 * @cfg {Boolean} striped striped of the progress bar
19876 * @cfg {Boolean} active animated of the progress bar
19880 * Create a new Progress
19881 * @param {Object} config The config object
19884 Roo.bootstrap.Progress = function(config){
19885 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19888 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19893 getAutoCreate : function(){
19901 cfg.cls += ' progress-striped';
19905 cfg.cls += ' active';
19924 * @class Roo.bootstrap.ProgressBar
19925 * @extends Roo.bootstrap.Component
19926 * Bootstrap ProgressBar class
19927 * @cfg {Number} aria_valuenow aria-value now
19928 * @cfg {Number} aria_valuemin aria-value min
19929 * @cfg {Number} aria_valuemax aria-value max
19930 * @cfg {String} label label for the progress bar
19931 * @cfg {String} panel (success | info | warning | danger )
19932 * @cfg {String} role role of the progress bar
19933 * @cfg {String} sr_only text
19937 * Create a new ProgressBar
19938 * @param {Object} config The config object
19941 Roo.bootstrap.ProgressBar = function(config){
19942 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19945 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19949 aria_valuemax : 100,
19955 getAutoCreate : function()
19960 cls: 'progress-bar',
19961 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19973 cfg.role = this.role;
19976 if(this.aria_valuenow){
19977 cfg['aria-valuenow'] = this.aria_valuenow;
19980 if(this.aria_valuemin){
19981 cfg['aria-valuemin'] = this.aria_valuemin;
19984 if(this.aria_valuemax){
19985 cfg['aria-valuemax'] = this.aria_valuemax;
19988 if(this.label && !this.sr_only){
19989 cfg.html = this.label;
19993 cfg.cls += ' progress-bar-' + this.panel;
19999 update : function(aria_valuenow)
20001 this.aria_valuenow = aria_valuenow;
20003 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
20018 * @class Roo.bootstrap.TabGroup
20019 * @extends Roo.bootstrap.Column
20020 * Bootstrap Column class
20021 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
20022 * @cfg {Boolean} carousel true to make the group behave like a carousel
20023 * @cfg {Boolean} bullets show bullets for the panels
20024 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
20025 * @cfg {Number} timer auto slide timer .. default 0 millisecond
20026 * @cfg {Boolean} showarrow (true|false) show arrow default true
20029 * Create a new TabGroup
20030 * @param {Object} config The config object
20033 Roo.bootstrap.TabGroup = function(config){
20034 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
20036 this.navId = Roo.id();
20039 Roo.bootstrap.TabGroup.register(this);
20043 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
20046 transition : false,
20051 slideOnTouch : false,
20054 getAutoCreate : function()
20056 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
20058 cfg.cls += ' tab-content';
20060 if (this.carousel) {
20061 cfg.cls += ' carousel slide';
20064 cls : 'carousel-inner',
20068 if(this.bullets && !Roo.isTouch){
20071 cls : 'carousel-bullets',
20075 if(this.bullets_cls){
20076 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
20083 cfg.cn[0].cn.push(bullets);
20086 if(this.showarrow){
20087 cfg.cn[0].cn.push({
20089 class : 'carousel-arrow',
20093 class : 'carousel-prev',
20097 class : 'fa fa-chevron-left'
20103 class : 'carousel-next',
20107 class : 'fa fa-chevron-right'
20120 initEvents: function()
20122 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
20123 // this.el.on("touchstart", this.onTouchStart, this);
20126 if(this.autoslide){
20129 this.slideFn = window.setInterval(function() {
20130 _this.showPanelNext();
20134 if(this.showarrow){
20135 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
20136 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
20142 // onTouchStart : function(e, el, o)
20144 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
20148 // this.showPanelNext();
20152 getChildContainer : function()
20154 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
20158 * register a Navigation item
20159 * @param {Roo.bootstrap.NavItem} the navitem to add
20161 register : function(item)
20163 this.tabs.push( item);
20164 item.navId = this.navId; // not really needed..
20169 getActivePanel : function()
20172 Roo.each(this.tabs, function(t) {
20182 getPanelByName : function(n)
20185 Roo.each(this.tabs, function(t) {
20186 if (t.tabId == n) {
20194 indexOfPanel : function(p)
20197 Roo.each(this.tabs, function(t,i) {
20198 if (t.tabId == p.tabId) {
20207 * show a specific panel
20208 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
20209 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
20211 showPanel : function (pan)
20213 if(this.transition || typeof(pan) == 'undefined'){
20214 Roo.log("waiting for the transitionend");
20218 if (typeof(pan) == 'number') {
20219 pan = this.tabs[pan];
20222 if (typeof(pan) == 'string') {
20223 pan = this.getPanelByName(pan);
20226 var cur = this.getActivePanel();
20229 Roo.log('pan or acitve pan is undefined');
20233 if (pan.tabId == this.getActivePanel().tabId) {
20237 if (false === cur.fireEvent('beforedeactivate')) {
20241 if(this.bullets > 0 && !Roo.isTouch){
20242 this.setActiveBullet(this.indexOfPanel(pan));
20245 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
20247 //class="carousel-item carousel-item-next carousel-item-left"
20249 this.transition = true;
20250 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
20251 var lr = dir == 'next' ? 'left' : 'right';
20252 pan.el.addClass(dir); // or prev
20253 pan.el.addClass('carousel-item-' + dir); // or prev
20254 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
20255 cur.el.addClass(lr); // or right
20256 pan.el.addClass(lr);
20257 cur.el.addClass('carousel-item-' +lr); // or right
20258 pan.el.addClass('carousel-item-' +lr);
20262 cur.el.on('transitionend', function() {
20263 Roo.log("trans end?");
20265 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
20266 pan.setActive(true);
20268 cur.el.removeClass([lr, 'carousel-item-' + lr]);
20269 cur.setActive(false);
20271 _this.transition = false;
20273 }, this, { single: true } );
20278 cur.setActive(false);
20279 pan.setActive(true);
20284 showPanelNext : function()
20286 var i = this.indexOfPanel(this.getActivePanel());
20288 if (i >= this.tabs.length - 1 && !this.autoslide) {
20292 if (i >= this.tabs.length - 1 && this.autoslide) {
20296 this.showPanel(this.tabs[i+1]);
20299 showPanelPrev : function()
20301 var i = this.indexOfPanel(this.getActivePanel());
20303 if (i < 1 && !this.autoslide) {
20307 if (i < 1 && this.autoslide) {
20308 i = this.tabs.length;
20311 this.showPanel(this.tabs[i-1]);
20315 addBullet: function()
20317 if(!this.bullets || Roo.isTouch){
20320 var ctr = this.el.select('.carousel-bullets',true).first();
20321 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
20322 var bullet = ctr.createChild({
20323 cls : 'bullet bullet-' + i
20324 },ctr.dom.lastChild);
20329 bullet.on('click', (function(e, el, o, ii, t){
20331 e.preventDefault();
20333 this.showPanel(ii);
20335 if(this.autoslide && this.slideFn){
20336 clearInterval(this.slideFn);
20337 this.slideFn = window.setInterval(function() {
20338 _this.showPanelNext();
20342 }).createDelegate(this, [i, bullet], true));
20347 setActiveBullet : function(i)
20353 Roo.each(this.el.select('.bullet', true).elements, function(el){
20354 el.removeClass('selected');
20357 var bullet = this.el.select('.bullet-' + i, true).first();
20363 bullet.addClass('selected');
20374 Roo.apply(Roo.bootstrap.TabGroup, {
20378 * register a Navigation Group
20379 * @param {Roo.bootstrap.NavGroup} the navgroup to add
20381 register : function(navgrp)
20383 this.groups[navgrp.navId] = navgrp;
20387 * fetch a Navigation Group based on the navigation ID
20388 * if one does not exist , it will get created.
20389 * @param {string} the navgroup to add
20390 * @returns {Roo.bootstrap.NavGroup} the navgroup
20392 get: function(navId) {
20393 if (typeof(this.groups[navId]) == 'undefined') {
20394 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
20396 return this.groups[navId] ;
20411 * @class Roo.bootstrap.TabPanel
20412 * @extends Roo.bootstrap.Component
20413 * Bootstrap TabPanel class
20414 * @cfg {Boolean} active panel active
20415 * @cfg {String} html panel content
20416 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
20417 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
20418 * @cfg {String} href click to link..
20419 * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
20423 * Create a new TabPanel
20424 * @param {Object} config The config object
20427 Roo.bootstrap.TabPanel = function(config){
20428 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
20432 * Fires when the active status changes
20433 * @param {Roo.bootstrap.TabPanel} this
20434 * @param {Boolean} state the new state
20439 * @event beforedeactivate
20440 * Fires before a tab is de-activated - can be used to do validation on a form.
20441 * @param {Roo.bootstrap.TabPanel} this
20442 * @return {Boolean} false if there is an error
20445 'beforedeactivate': true
20448 this.tabId = this.tabId || Roo.id();
20452 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
20459 touchSlide : false,
20460 getAutoCreate : function(){
20465 // item is needed for carousel - not sure if it has any effect otherwise
20466 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
20467 html: this.html || ''
20471 cfg.cls += ' active';
20475 cfg.tabId = this.tabId;
20483 initEvents: function()
20485 var p = this.parent();
20487 this.navId = this.navId || p.navId;
20489 if (typeof(this.navId) != 'undefined') {
20490 // not really needed.. but just in case.. parent should be a NavGroup.
20491 var tg = Roo.bootstrap.TabGroup.get(this.navId);
20495 var i = tg.tabs.length - 1;
20497 if(this.active && tg.bullets > 0 && i < tg.bullets){
20498 tg.setActiveBullet(i);
20502 this.el.on('click', this.onClick, this);
20504 if(Roo.isTouch && this.touchSlide){
20505 this.el.on("touchstart", this.onTouchStart, this);
20506 this.el.on("touchmove", this.onTouchMove, this);
20507 this.el.on("touchend", this.onTouchEnd, this);
20512 onRender : function(ct, position)
20514 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
20517 setActive : function(state)
20519 Roo.log("panel - set active " + this.tabId + "=" + state);
20521 this.active = state;
20523 this.el.removeClass('active');
20525 } else if (!this.el.hasClass('active')) {
20526 this.el.addClass('active');
20529 this.fireEvent('changed', this, state);
20532 onClick : function(e)
20534 e.preventDefault();
20536 if(!this.href.length){
20540 window.location.href = this.href;
20549 onTouchStart : function(e)
20551 this.swiping = false;
20553 this.startX = e.browserEvent.touches[0].clientX;
20554 this.startY = e.browserEvent.touches[0].clientY;
20557 onTouchMove : function(e)
20559 this.swiping = true;
20561 this.endX = e.browserEvent.touches[0].clientX;
20562 this.endY = e.browserEvent.touches[0].clientY;
20565 onTouchEnd : function(e)
20572 var tabGroup = this.parent();
20574 if(this.endX > this.startX){ // swiping right
20575 tabGroup.showPanelPrev();
20579 if(this.startX > this.endX){ // swiping left
20580 tabGroup.showPanelNext();
20599 * @class Roo.bootstrap.DateField
20600 * @extends Roo.bootstrap.Input
20601 * Bootstrap DateField class
20602 * @cfg {Number} weekStart default 0
20603 * @cfg {String} viewMode default empty, (months|years)
20604 * @cfg {String} minViewMode default empty, (months|years)
20605 * @cfg {Number} startDate default -Infinity
20606 * @cfg {Number} endDate default Infinity
20607 * @cfg {Boolean} todayHighlight default false
20608 * @cfg {Boolean} todayBtn default false
20609 * @cfg {Boolean} calendarWeeks default false
20610 * @cfg {Object} daysOfWeekDisabled default empty
20611 * @cfg {Boolean} singleMode default false (true | false)
20613 * @cfg {Boolean} keyboardNavigation default true
20614 * @cfg {String} language default en
20617 * Create a new DateField
20618 * @param {Object} config The config object
20621 Roo.bootstrap.DateField = function(config){
20622 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
20626 * Fires when this field show.
20627 * @param {Roo.bootstrap.DateField} this
20628 * @param {Mixed} date The date value
20633 * Fires when this field hide.
20634 * @param {Roo.bootstrap.DateField} this
20635 * @param {Mixed} date The date value
20640 * Fires when select a date.
20641 * @param {Roo.bootstrap.DateField} this
20642 * @param {Mixed} date The date value
20646 * @event beforeselect
20647 * Fires when before select a date.
20648 * @param {Roo.bootstrap.DateField} this
20649 * @param {Mixed} date The date value
20651 beforeselect : true
20655 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
20658 * @cfg {String} format
20659 * The default date format string which can be overriden for localization support. The format must be
20660 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
20664 * @cfg {String} altFormats
20665 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
20666 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
20668 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
20676 todayHighlight : false,
20682 keyboardNavigation: true,
20684 calendarWeeks: false,
20686 startDate: -Infinity,
20690 daysOfWeekDisabled: [],
20694 singleMode : false,
20696 UTCDate: function()
20698 return new Date(Date.UTC.apply(Date, arguments));
20701 UTCToday: function()
20703 var today = new Date();
20704 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
20707 getDate: function() {
20708 var d = this.getUTCDate();
20709 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
20712 getUTCDate: function() {
20716 setDate: function(d) {
20717 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
20720 setUTCDate: function(d) {
20722 this.setValue(this.formatDate(this.date));
20725 onRender: function(ct, position)
20728 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
20730 this.language = this.language || 'en';
20731 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
20732 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
20734 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
20735 this.format = this.format || 'm/d/y';
20736 this.isInline = false;
20737 this.isInput = true;
20738 this.component = this.el.select('.add-on', true).first() || false;
20739 this.component = (this.component && this.component.length === 0) ? false : this.component;
20740 this.hasInput = this.component && this.inputEl().length;
20742 if (typeof(this.minViewMode === 'string')) {
20743 switch (this.minViewMode) {
20745 this.minViewMode = 1;
20748 this.minViewMode = 2;
20751 this.minViewMode = 0;
20756 if (typeof(this.viewMode === 'string')) {
20757 switch (this.viewMode) {
20770 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
20772 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
20774 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20776 this.picker().on('mousedown', this.onMousedown, this);
20777 this.picker().on('click', this.onClick, this);
20779 this.picker().addClass('datepicker-dropdown');
20781 this.startViewMode = this.viewMode;
20783 if(this.singleMode){
20784 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
20785 v.setVisibilityMode(Roo.Element.DISPLAY);
20789 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20790 v.setStyle('width', '189px');
20794 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
20795 if(!this.calendarWeeks){
20800 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20801 v.attr('colspan', function(i, val){
20802 return parseInt(val) + 1;
20807 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20809 this.setStartDate(this.startDate);
20810 this.setEndDate(this.endDate);
20812 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20819 if(this.isInline) {
20824 picker : function()
20826 return this.pickerEl;
20827 // return this.el.select('.datepicker', true).first();
20830 fillDow: function()
20832 var dowCnt = this.weekStart;
20841 if(this.calendarWeeks){
20849 while (dowCnt < this.weekStart + 7) {
20853 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20857 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20860 fillMonths: function()
20863 var months = this.picker().select('>.datepicker-months td', true).first();
20865 months.dom.innerHTML = '';
20871 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20874 months.createChild(month);
20881 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;
20883 if (this.date < this.startDate) {
20884 this.viewDate = new Date(this.startDate);
20885 } else if (this.date > this.endDate) {
20886 this.viewDate = new Date(this.endDate);
20888 this.viewDate = new Date(this.date);
20896 var d = new Date(this.viewDate),
20897 year = d.getUTCFullYear(),
20898 month = d.getUTCMonth(),
20899 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20900 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20901 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20902 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20903 currentDate = this.date && this.date.valueOf(),
20904 today = this.UTCToday();
20906 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20908 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20910 // this.picker.select('>tfoot th.today').
20911 // .text(dates[this.language].today)
20912 // .toggle(this.todayBtn !== false);
20914 this.updateNavArrows();
20917 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20919 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20921 prevMonth.setUTCDate(day);
20923 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20925 var nextMonth = new Date(prevMonth);
20927 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20929 nextMonth = nextMonth.valueOf();
20931 var fillMonths = false;
20933 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20935 while(prevMonth.valueOf() <= nextMonth) {
20938 if (prevMonth.getUTCDay() === this.weekStart) {
20940 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20948 if(this.calendarWeeks){
20949 // ISO 8601: First week contains first thursday.
20950 // ISO also states week starts on Monday, but we can be more abstract here.
20952 // Start of current week: based on weekstart/current date
20953 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20954 // Thursday of this week
20955 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20956 // First Thursday of year, year from thursday
20957 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20958 // Calendar week: ms between thursdays, div ms per day, div 7 days
20959 calWeek = (th - yth) / 864e5 / 7 + 1;
20961 fillMonths.cn.push({
20969 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20971 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20974 if (this.todayHighlight &&
20975 prevMonth.getUTCFullYear() == today.getFullYear() &&
20976 prevMonth.getUTCMonth() == today.getMonth() &&
20977 prevMonth.getUTCDate() == today.getDate()) {
20978 clsName += ' today';
20981 if (currentDate && prevMonth.valueOf() === currentDate) {
20982 clsName += ' active';
20985 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20986 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20987 clsName += ' disabled';
20990 fillMonths.cn.push({
20992 cls: 'day ' + clsName,
20993 html: prevMonth.getDate()
20996 prevMonth.setDate(prevMonth.getDate()+1);
20999 var currentYear = this.date && this.date.getUTCFullYear();
21000 var currentMonth = this.date && this.date.getUTCMonth();
21002 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
21004 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
21005 v.removeClass('active');
21007 if(currentYear === year && k === currentMonth){
21008 v.addClass('active');
21011 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
21012 v.addClass('disabled');
21018 year = parseInt(year/10, 10) * 10;
21020 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
21022 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
21025 for (var i = -1; i < 11; i++) {
21026 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
21028 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
21036 showMode: function(dir)
21039 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
21042 Roo.each(this.picker().select('>div',true).elements, function(v){
21043 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21046 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
21051 if(this.isInline) {
21055 this.picker().removeClass(['bottom', 'top']);
21057 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
21059 * place to the top of element!
21063 this.picker().addClass('top');
21064 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
21069 this.picker().addClass('bottom');
21071 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
21074 parseDate : function(value)
21076 if(!value || value instanceof Date){
21079 var v = Date.parseDate(value, this.format);
21080 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
21081 v = Date.parseDate(value, 'Y-m-d');
21083 if(!v && this.altFormats){
21084 if(!this.altFormatsArray){
21085 this.altFormatsArray = this.altFormats.split("|");
21087 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
21088 v = Date.parseDate(value, this.altFormatsArray[i]);
21094 formatDate : function(date, fmt)
21096 return (!date || !(date instanceof Date)) ?
21097 date : date.dateFormat(fmt || this.format);
21100 onFocus : function()
21102 Roo.bootstrap.DateField.superclass.onFocus.call(this);
21106 onBlur : function()
21108 Roo.bootstrap.DateField.superclass.onBlur.call(this);
21110 var d = this.inputEl().getValue();
21117 showPopup : function()
21119 this.picker().show();
21123 this.fireEvent('showpopup', this, this.date);
21126 hidePopup : function()
21128 if(this.isInline) {
21131 this.picker().hide();
21132 this.viewMode = this.startViewMode;
21135 this.fireEvent('hidepopup', this, this.date);
21139 onMousedown: function(e)
21141 e.stopPropagation();
21142 e.preventDefault();
21147 Roo.bootstrap.DateField.superclass.keyup.call(this);
21151 setValue: function(v)
21153 if(this.fireEvent('beforeselect', this, v) !== false){
21154 var d = new Date(this.parseDate(v) ).clearTime();
21156 if(isNaN(d.getTime())){
21157 this.date = this.viewDate = '';
21158 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21162 v = this.formatDate(d);
21164 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
21166 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
21170 this.fireEvent('select', this, this.date);
21174 getValue: function()
21176 return this.formatDate(this.date);
21179 fireKey: function(e)
21181 if (!this.picker().isVisible()){
21182 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21188 var dateChanged = false,
21190 newDate, newViewDate;
21195 e.preventDefault();
21199 if (!this.keyboardNavigation) {
21202 dir = e.keyCode == 37 ? -1 : 1;
21205 newDate = this.moveYear(this.date, dir);
21206 newViewDate = this.moveYear(this.viewDate, dir);
21207 } else if (e.shiftKey){
21208 newDate = this.moveMonth(this.date, dir);
21209 newViewDate = this.moveMonth(this.viewDate, dir);
21211 newDate = new Date(this.date);
21212 newDate.setUTCDate(this.date.getUTCDate() + dir);
21213 newViewDate = new Date(this.viewDate);
21214 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
21216 if (this.dateWithinRange(newDate)){
21217 this.date = newDate;
21218 this.viewDate = newViewDate;
21219 this.setValue(this.formatDate(this.date));
21221 e.preventDefault();
21222 dateChanged = true;
21227 if (!this.keyboardNavigation) {
21230 dir = e.keyCode == 38 ? -1 : 1;
21232 newDate = this.moveYear(this.date, dir);
21233 newViewDate = this.moveYear(this.viewDate, dir);
21234 } else if (e.shiftKey){
21235 newDate = this.moveMonth(this.date, dir);
21236 newViewDate = this.moveMonth(this.viewDate, dir);
21238 newDate = new Date(this.date);
21239 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
21240 newViewDate = new Date(this.viewDate);
21241 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
21243 if (this.dateWithinRange(newDate)){
21244 this.date = newDate;
21245 this.viewDate = newViewDate;
21246 this.setValue(this.formatDate(this.date));
21248 e.preventDefault();
21249 dateChanged = true;
21253 this.setValue(this.formatDate(this.date));
21255 e.preventDefault();
21258 this.setValue(this.formatDate(this.date));
21272 onClick: function(e)
21274 e.stopPropagation();
21275 e.preventDefault();
21277 var target = e.getTarget();
21279 if(target.nodeName.toLowerCase() === 'i'){
21280 target = Roo.get(target).dom.parentNode;
21283 var nodeName = target.nodeName;
21284 var className = target.className;
21285 var html = target.innerHTML;
21286 //Roo.log(nodeName);
21288 switch(nodeName.toLowerCase()) {
21290 switch(className) {
21296 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
21297 switch(this.viewMode){
21299 this.viewDate = this.moveMonth(this.viewDate, dir);
21303 this.viewDate = this.moveYear(this.viewDate, dir);
21309 var date = new Date();
21310 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
21312 this.setValue(this.formatDate(this.date));
21319 if (className.indexOf('disabled') < 0) {
21320 this.viewDate.setUTCDate(1);
21321 if (className.indexOf('month') > -1) {
21322 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
21324 var year = parseInt(html, 10) || 0;
21325 this.viewDate.setUTCFullYear(year);
21329 if(this.singleMode){
21330 this.setValue(this.formatDate(this.viewDate));
21341 //Roo.log(className);
21342 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
21343 var day = parseInt(html, 10) || 1;
21344 var year = this.viewDate.getUTCFullYear(),
21345 month = this.viewDate.getUTCMonth();
21347 if (className.indexOf('old') > -1) {
21354 } else if (className.indexOf('new') > -1) {
21362 //Roo.log([year,month,day]);
21363 this.date = this.UTCDate(year, month, day,0,0,0,0);
21364 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
21366 //Roo.log(this.formatDate(this.date));
21367 this.setValue(this.formatDate(this.date));
21374 setStartDate: function(startDate)
21376 this.startDate = startDate || -Infinity;
21377 if (this.startDate !== -Infinity) {
21378 this.startDate = this.parseDate(this.startDate);
21381 this.updateNavArrows();
21384 setEndDate: function(endDate)
21386 this.endDate = endDate || Infinity;
21387 if (this.endDate !== Infinity) {
21388 this.endDate = this.parseDate(this.endDate);
21391 this.updateNavArrows();
21394 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
21396 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
21397 if (typeof(this.daysOfWeekDisabled) !== 'object') {
21398 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
21400 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
21401 return parseInt(d, 10);
21404 this.updateNavArrows();
21407 updateNavArrows: function()
21409 if(this.singleMode){
21413 var d = new Date(this.viewDate),
21414 year = d.getUTCFullYear(),
21415 month = d.getUTCMonth();
21417 Roo.each(this.picker().select('.prev', true).elements, function(v){
21419 switch (this.viewMode) {
21422 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
21428 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
21435 Roo.each(this.picker().select('.next', true).elements, function(v){
21437 switch (this.viewMode) {
21440 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
21446 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
21454 moveMonth: function(date, dir)
21459 var new_date = new Date(date.valueOf()),
21460 day = new_date.getUTCDate(),
21461 month = new_date.getUTCMonth(),
21462 mag = Math.abs(dir),
21464 dir = dir > 0 ? 1 : -1;
21467 // If going back one month, make sure month is not current month
21468 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
21470 return new_date.getUTCMonth() == month;
21472 // If going forward one month, make sure month is as expected
21473 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
21475 return new_date.getUTCMonth() != new_month;
21477 new_month = month + dir;
21478 new_date.setUTCMonth(new_month);
21479 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
21480 if (new_month < 0 || new_month > 11) {
21481 new_month = (new_month + 12) % 12;
21484 // For magnitudes >1, move one month at a time...
21485 for (var i=0; i<mag; i++) {
21486 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
21487 new_date = this.moveMonth(new_date, dir);
21489 // ...then reset the day, keeping it in the new month
21490 new_month = new_date.getUTCMonth();
21491 new_date.setUTCDate(day);
21493 return new_month != new_date.getUTCMonth();
21496 // Common date-resetting loop -- if date is beyond end of month, make it
21499 new_date.setUTCDate(--day);
21500 new_date.setUTCMonth(new_month);
21505 moveYear: function(date, dir)
21507 return this.moveMonth(date, dir*12);
21510 dateWithinRange: function(date)
21512 return date >= this.startDate && date <= this.endDate;
21518 this.picker().remove();
21521 validateValue : function(value)
21523 if(this.getVisibilityEl().hasClass('hidden')){
21527 if(value.length < 1) {
21528 if(this.allowBlank){
21534 if(value.length < this.minLength){
21537 if(value.length > this.maxLength){
21541 var vt = Roo.form.VTypes;
21542 if(!vt[this.vtype](value, this)){
21546 if(typeof this.validator == "function"){
21547 var msg = this.validator(value);
21553 if(this.regex && !this.regex.test(value)){
21557 if(typeof(this.parseDate(value)) == 'undefined'){
21561 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
21565 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
21575 this.date = this.viewDate = '';
21577 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21582 Roo.apply(Roo.bootstrap.DateField, {
21593 html: '<i class="fa fa-arrow-left"/>'
21603 html: '<i class="fa fa-arrow-right"/>'
21645 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
21646 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
21647 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
21648 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21649 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
21662 navFnc: 'FullYear',
21667 navFnc: 'FullYear',
21672 Roo.apply(Roo.bootstrap.DateField, {
21676 cls: 'datepicker dropdown-menu roo-dynamic',
21680 cls: 'datepicker-days',
21684 cls: 'table-condensed',
21686 Roo.bootstrap.DateField.head,
21690 Roo.bootstrap.DateField.footer
21697 cls: 'datepicker-months',
21701 cls: 'table-condensed',
21703 Roo.bootstrap.DateField.head,
21704 Roo.bootstrap.DateField.content,
21705 Roo.bootstrap.DateField.footer
21712 cls: 'datepicker-years',
21716 cls: 'table-condensed',
21718 Roo.bootstrap.DateField.head,
21719 Roo.bootstrap.DateField.content,
21720 Roo.bootstrap.DateField.footer
21739 * @class Roo.bootstrap.TimeField
21740 * @extends Roo.bootstrap.Input
21741 * Bootstrap DateField class
21745 * Create a new TimeField
21746 * @param {Object} config The config object
21749 Roo.bootstrap.TimeField = function(config){
21750 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
21754 * Fires when this field show.
21755 * @param {Roo.bootstrap.DateField} thisthis
21756 * @param {Mixed} date The date value
21761 * Fires when this field hide.
21762 * @param {Roo.bootstrap.DateField} this
21763 * @param {Mixed} date The date value
21768 * Fires when select a date.
21769 * @param {Roo.bootstrap.DateField} this
21770 * @param {Mixed} date The date value
21776 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
21779 * @cfg {String} format
21780 * The default time format string which can be overriden for localization support. The format must be
21781 * valid according to {@link Date#parseDate} (defaults to 'H:i').
21785 onRender: function(ct, position)
21788 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
21790 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
21792 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21794 this.pop = this.picker().select('>.datepicker-time',true).first();
21795 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21797 this.picker().on('mousedown', this.onMousedown, this);
21798 this.picker().on('click', this.onClick, this);
21800 this.picker().addClass('datepicker-dropdown');
21805 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21806 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21807 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21808 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21809 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21810 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21814 fireKey: function(e){
21815 if (!this.picker().isVisible()){
21816 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21822 e.preventDefault();
21830 this.onTogglePeriod();
21833 this.onIncrementMinutes();
21836 this.onDecrementMinutes();
21845 onClick: function(e) {
21846 e.stopPropagation();
21847 e.preventDefault();
21850 picker : function()
21852 return this.el.select('.datepicker', true).first();
21855 fillTime: function()
21857 var time = this.pop.select('tbody', true).first();
21859 time.dom.innerHTML = '';
21874 cls: 'hours-up glyphicon glyphicon-chevron-up'
21894 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21915 cls: 'timepicker-hour',
21930 cls: 'timepicker-minute',
21945 cls: 'btn btn-primary period',
21967 cls: 'hours-down glyphicon glyphicon-chevron-down'
21987 cls: 'minutes-down glyphicon glyphicon-chevron-down'
22005 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
22012 var hours = this.time.getHours();
22013 var minutes = this.time.getMinutes();
22026 hours = hours - 12;
22030 hours = '0' + hours;
22034 minutes = '0' + minutes;
22037 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
22038 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
22039 this.pop.select('button', true).first().dom.innerHTML = period;
22045 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
22047 var cls = ['bottom'];
22049 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
22056 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
22061 this.picker().addClass(cls.join('-'));
22065 Roo.each(cls, function(c){
22067 _this.picker().setTop(_this.inputEl().getHeight());
22071 _this.picker().setTop(0 - _this.picker().getHeight());
22076 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
22080 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
22087 onFocus : function()
22089 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
22093 onBlur : function()
22095 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
22101 this.picker().show();
22106 this.fireEvent('show', this, this.date);
22111 this.picker().hide();
22114 this.fireEvent('hide', this, this.date);
22117 setTime : function()
22120 this.setValue(this.time.format(this.format));
22122 this.fireEvent('select', this, this.date);
22127 onMousedown: function(e){
22128 e.stopPropagation();
22129 e.preventDefault();
22132 onIncrementHours: function()
22134 Roo.log('onIncrementHours');
22135 this.time = this.time.add(Date.HOUR, 1);
22140 onDecrementHours: function()
22142 Roo.log('onDecrementHours');
22143 this.time = this.time.add(Date.HOUR, -1);
22147 onIncrementMinutes: function()
22149 Roo.log('onIncrementMinutes');
22150 this.time = this.time.add(Date.MINUTE, 1);
22154 onDecrementMinutes: function()
22156 Roo.log('onDecrementMinutes');
22157 this.time = this.time.add(Date.MINUTE, -1);
22161 onTogglePeriod: function()
22163 Roo.log('onTogglePeriod');
22164 this.time = this.time.add(Date.HOUR, 12);
22171 Roo.apply(Roo.bootstrap.TimeField, {
22201 cls: 'btn btn-info ok',
22213 Roo.apply(Roo.bootstrap.TimeField, {
22217 cls: 'datepicker dropdown-menu',
22221 cls: 'datepicker-time',
22225 cls: 'table-condensed',
22227 Roo.bootstrap.TimeField.content,
22228 Roo.bootstrap.TimeField.footer
22247 * @class Roo.bootstrap.MonthField
22248 * @extends Roo.bootstrap.Input
22249 * Bootstrap MonthField class
22251 * @cfg {String} language default en
22254 * Create a new MonthField
22255 * @param {Object} config The config object
22258 Roo.bootstrap.MonthField = function(config){
22259 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
22264 * Fires when this field show.
22265 * @param {Roo.bootstrap.MonthField} this
22266 * @param {Mixed} date The date value
22271 * Fires when this field hide.
22272 * @param {Roo.bootstrap.MonthField} this
22273 * @param {Mixed} date The date value
22278 * Fires when select a date.
22279 * @param {Roo.bootstrap.MonthField} this
22280 * @param {String} oldvalue The old value
22281 * @param {String} newvalue The new value
22287 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
22289 onRender: function(ct, position)
22292 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
22294 this.language = this.language || 'en';
22295 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
22296 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
22298 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
22299 this.isInline = false;
22300 this.isInput = true;
22301 this.component = this.el.select('.add-on', true).first() || false;
22302 this.component = (this.component && this.component.length === 0) ? false : this.component;
22303 this.hasInput = this.component && this.inputEL().length;
22305 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
22307 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22309 this.picker().on('mousedown', this.onMousedown, this);
22310 this.picker().on('click', this.onClick, this);
22312 this.picker().addClass('datepicker-dropdown');
22314 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
22315 v.setStyle('width', '189px');
22322 if(this.isInline) {
22328 setValue: function(v, suppressEvent)
22330 var o = this.getValue();
22332 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
22336 if(suppressEvent !== true){
22337 this.fireEvent('select', this, o, v);
22342 getValue: function()
22347 onClick: function(e)
22349 e.stopPropagation();
22350 e.preventDefault();
22352 var target = e.getTarget();
22354 if(target.nodeName.toLowerCase() === 'i'){
22355 target = Roo.get(target).dom.parentNode;
22358 var nodeName = target.nodeName;
22359 var className = target.className;
22360 var html = target.innerHTML;
22362 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
22366 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
22368 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22374 picker : function()
22376 return this.pickerEl;
22379 fillMonths: function()
22382 var months = this.picker().select('>.datepicker-months td', true).first();
22384 months.dom.innerHTML = '';
22390 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
22393 months.createChild(month);
22402 if(typeof(this.vIndex) == 'undefined' && this.value.length){
22403 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
22406 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
22407 e.removeClass('active');
22409 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
22410 e.addClass('active');
22417 if(this.isInline) {
22421 this.picker().removeClass(['bottom', 'top']);
22423 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
22425 * place to the top of element!
22429 this.picker().addClass('top');
22430 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
22435 this.picker().addClass('bottom');
22437 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
22440 onFocus : function()
22442 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
22446 onBlur : function()
22448 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
22450 var d = this.inputEl().getValue();
22459 this.picker().show();
22460 this.picker().select('>.datepicker-months', true).first().show();
22464 this.fireEvent('show', this, this.date);
22469 if(this.isInline) {
22472 this.picker().hide();
22473 this.fireEvent('hide', this, this.date);
22477 onMousedown: function(e)
22479 e.stopPropagation();
22480 e.preventDefault();
22485 Roo.bootstrap.MonthField.superclass.keyup.call(this);
22489 fireKey: function(e)
22491 if (!this.picker().isVisible()){
22492 if (e.keyCode == 27) {// allow escape to hide and re-show picker
22503 e.preventDefault();
22507 dir = e.keyCode == 37 ? -1 : 1;
22509 this.vIndex = this.vIndex + dir;
22511 if(this.vIndex < 0){
22515 if(this.vIndex > 11){
22519 if(isNaN(this.vIndex)){
22523 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22529 dir = e.keyCode == 38 ? -1 : 1;
22531 this.vIndex = this.vIndex + dir * 4;
22533 if(this.vIndex < 0){
22537 if(this.vIndex > 11){
22541 if(isNaN(this.vIndex)){
22545 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22550 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22551 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22555 e.preventDefault();
22558 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22559 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22575 this.picker().remove();
22580 Roo.apply(Roo.bootstrap.MonthField, {
22599 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
22600 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
22605 Roo.apply(Roo.bootstrap.MonthField, {
22609 cls: 'datepicker dropdown-menu roo-dynamic',
22613 cls: 'datepicker-months',
22617 cls: 'table-condensed',
22619 Roo.bootstrap.DateField.content
22639 * @class Roo.bootstrap.CheckBox
22640 * @extends Roo.bootstrap.Input
22641 * Bootstrap CheckBox class
22643 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
22644 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
22645 * @cfg {String} boxLabel The text that appears beside the checkbox
22646 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
22647 * @cfg {Boolean} checked initnal the element
22648 * @cfg {Boolean} inline inline the element (default false)
22649 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
22650 * @cfg {String} tooltip label tooltip
22653 * Create a new CheckBox
22654 * @param {Object} config The config object
22657 Roo.bootstrap.CheckBox = function(config){
22658 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
22663 * Fires when the element is checked or unchecked.
22664 * @param {Roo.bootstrap.CheckBox} this This input
22665 * @param {Boolean} checked The new checked value
22670 * Fires when the element is click.
22671 * @param {Roo.bootstrap.CheckBox} this This input
22678 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
22680 inputType: 'checkbox',
22689 // checkbox success does not make any sense really..
22694 getAutoCreate : function()
22696 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
22702 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
22705 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
22711 type : this.inputType,
22712 value : this.inputValue,
22713 cls : 'roo-' + this.inputType, //'form-box',
22714 placeholder : this.placeholder || ''
22718 if(this.inputType != 'radio'){
22722 cls : 'roo-hidden-value',
22723 value : this.checked ? this.inputValue : this.valueOff
22728 if (this.weight) { // Validity check?
22729 cfg.cls += " " + this.inputType + "-" + this.weight;
22732 if (this.disabled) {
22733 input.disabled=true;
22737 input.checked = this.checked;
22742 input.name = this.name;
22744 if(this.inputType != 'radio'){
22745 hidden.name = this.name;
22746 input.name = '_hidden_' + this.name;
22751 input.cls += ' input-' + this.size;
22756 ['xs','sm','md','lg'].map(function(size){
22757 if (settings[size]) {
22758 cfg.cls += ' col-' + size + '-' + settings[size];
22762 var inputblock = input;
22764 if (this.before || this.after) {
22767 cls : 'input-group',
22772 inputblock.cn.push({
22774 cls : 'input-group-addon',
22779 inputblock.cn.push(input);
22781 if(this.inputType != 'radio'){
22782 inputblock.cn.push(hidden);
22786 inputblock.cn.push({
22788 cls : 'input-group-addon',
22794 var boxLabelCfg = false;
22800 //'for': id, // box label is handled by onclick - so no for...
22802 html: this.boxLabel
22805 boxLabelCfg.tooltip = this.tooltip;
22811 if (align ==='left' && this.fieldLabel.length) {
22812 // Roo.log("left and has label");
22817 cls : 'control-label',
22818 html : this.fieldLabel
22829 cfg.cn[1].cn.push(boxLabelCfg);
22832 if(this.labelWidth > 12){
22833 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22836 if(this.labelWidth < 13 && this.labelmd == 0){
22837 this.labelmd = this.labelWidth;
22840 if(this.labellg > 0){
22841 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22842 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22845 if(this.labelmd > 0){
22846 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22847 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22850 if(this.labelsm > 0){
22851 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22852 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22855 if(this.labelxs > 0){
22856 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22857 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22860 } else if ( this.fieldLabel.length) {
22861 // Roo.log(" label");
22865 tag: this.boxLabel ? 'span' : 'label',
22867 cls: 'control-label box-input-label',
22868 //cls : 'input-group-addon',
22869 html : this.fieldLabel
22876 cfg.cn.push(boxLabelCfg);
22881 // Roo.log(" no label && no align");
22882 cfg.cn = [ inputblock ] ;
22884 cfg.cn.push(boxLabelCfg);
22892 if(this.inputType != 'radio'){
22893 cfg.cn.push(hidden);
22901 * return the real input element.
22903 inputEl: function ()
22905 return this.el.select('input.roo-' + this.inputType,true).first();
22907 hiddenEl: function ()
22909 return this.el.select('input.roo-hidden-value',true).first();
22912 labelEl: function()
22914 return this.el.select('label.control-label',true).first();
22916 /* depricated... */
22920 return this.labelEl();
22923 boxLabelEl: function()
22925 return this.el.select('label.box-label',true).first();
22928 initEvents : function()
22930 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22932 this.inputEl().on('click', this.onClick, this);
22934 if (this.boxLabel) {
22935 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22938 this.startValue = this.getValue();
22941 Roo.bootstrap.CheckBox.register(this);
22945 onClick : function(e)
22947 if(this.fireEvent('click', this, e) !== false){
22948 this.setChecked(!this.checked);
22953 setChecked : function(state,suppressEvent)
22955 this.startValue = this.getValue();
22957 if(this.inputType == 'radio'){
22959 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22960 e.dom.checked = false;
22963 this.inputEl().dom.checked = true;
22965 this.inputEl().dom.value = this.inputValue;
22967 if(suppressEvent !== true){
22968 this.fireEvent('check', this, true);
22976 this.checked = state;
22978 this.inputEl().dom.checked = state;
22981 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22983 if(suppressEvent !== true){
22984 this.fireEvent('check', this, state);
22990 getValue : function()
22992 if(this.inputType == 'radio'){
22993 return this.getGroupValue();
22996 return this.hiddenEl().dom.value;
23000 getGroupValue : function()
23002 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
23006 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
23009 setValue : function(v,suppressEvent)
23011 if(this.inputType == 'radio'){
23012 this.setGroupValue(v, suppressEvent);
23016 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
23021 setGroupValue : function(v, suppressEvent)
23023 this.startValue = this.getValue();
23025 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23026 e.dom.checked = false;
23028 if(e.dom.value == v){
23029 e.dom.checked = true;
23033 if(suppressEvent !== true){
23034 this.fireEvent('check', this, true);
23042 validate : function()
23044 if(this.getVisibilityEl().hasClass('hidden')){
23050 (this.inputType == 'radio' && this.validateRadio()) ||
23051 (this.inputType == 'checkbox' && this.validateCheckbox())
23057 this.markInvalid();
23061 validateRadio : function()
23063 if(this.getVisibilityEl().hasClass('hidden')){
23067 if(this.allowBlank){
23073 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23074 if(!e.dom.checked){
23086 validateCheckbox : function()
23089 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
23090 //return (this.getValue() == this.inputValue) ? true : false;
23093 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23101 for(var i in group){
23102 if(group[i].el.isVisible(true)){
23110 for(var i in group){
23115 r = (group[i].getValue() == group[i].inputValue) ? true : false;
23122 * Mark this field as valid
23124 markValid : function()
23128 this.fireEvent('valid', this);
23130 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23133 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23140 if(this.inputType == 'radio'){
23141 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23142 var fg = e.findParent('.form-group', false, true);
23143 if (Roo.bootstrap.version == 3) {
23144 fg.removeClass([_this.invalidClass, _this.validClass]);
23145 fg.addClass(_this.validClass);
23147 fg.removeClass(['is-valid', 'is-invalid']);
23148 fg.addClass('is-valid');
23156 var fg = this.el.findParent('.form-group', false, true);
23157 if (Roo.bootstrap.version == 3) {
23158 fg.removeClass([this.invalidClass, this.validClass]);
23159 fg.addClass(this.validClass);
23161 fg.removeClass(['is-valid', 'is-invalid']);
23162 fg.addClass('is-valid');
23167 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23173 for(var i in group){
23174 var fg = group[i].el.findParent('.form-group', false, true);
23175 if (Roo.bootstrap.version == 3) {
23176 fg.removeClass([this.invalidClass, this.validClass]);
23177 fg.addClass(this.validClass);
23179 fg.removeClass(['is-valid', 'is-invalid']);
23180 fg.addClass('is-valid');
23186 * Mark this field as invalid
23187 * @param {String} msg The validation message
23189 markInvalid : function(msg)
23191 if(this.allowBlank){
23197 this.fireEvent('invalid', this, msg);
23199 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23202 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23206 label.markInvalid();
23209 if(this.inputType == 'radio'){
23211 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23212 var fg = e.findParent('.form-group', false, true);
23213 if (Roo.bootstrap.version == 3) {
23214 fg.removeClass([_this.invalidClass, _this.validClass]);
23215 fg.addClass(_this.invalidClass);
23217 fg.removeClass(['is-invalid', 'is-valid']);
23218 fg.addClass('is-invalid');
23226 var fg = this.el.findParent('.form-group', false, true);
23227 if (Roo.bootstrap.version == 3) {
23228 fg.removeClass([_this.invalidClass, _this.validClass]);
23229 fg.addClass(_this.invalidClass);
23231 fg.removeClass(['is-invalid', 'is-valid']);
23232 fg.addClass('is-invalid');
23237 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23243 for(var i in group){
23244 var fg = group[i].el.findParent('.form-group', false, true);
23245 if (Roo.bootstrap.version == 3) {
23246 fg.removeClass([_this.invalidClass, _this.validClass]);
23247 fg.addClass(_this.invalidClass);
23249 fg.removeClass(['is-invalid', 'is-valid']);
23250 fg.addClass('is-invalid');
23256 clearInvalid : function()
23258 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
23260 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
23262 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23264 if (label && label.iconEl) {
23265 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
23266 label.iconEl.removeClass(['is-invalid', 'is-valid']);
23270 disable : function()
23272 if(this.inputType != 'radio'){
23273 Roo.bootstrap.CheckBox.superclass.disable.call(this);
23280 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23281 _this.getActionEl().addClass(this.disabledClass);
23282 e.dom.disabled = true;
23286 this.disabled = true;
23287 this.fireEvent("disable", this);
23291 enable : function()
23293 if(this.inputType != 'radio'){
23294 Roo.bootstrap.CheckBox.superclass.enable.call(this);
23301 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23302 _this.getActionEl().removeClass(this.disabledClass);
23303 e.dom.disabled = false;
23307 this.disabled = false;
23308 this.fireEvent("enable", this);
23312 setBoxLabel : function(v)
23317 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23323 Roo.apply(Roo.bootstrap.CheckBox, {
23328 * register a CheckBox Group
23329 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
23331 register : function(checkbox)
23333 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
23334 this.groups[checkbox.groupId] = {};
23337 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
23341 this.groups[checkbox.groupId][checkbox.name] = checkbox;
23345 * fetch a CheckBox Group based on the group ID
23346 * @param {string} the group ID
23347 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
23349 get: function(groupId) {
23350 if (typeof(this.groups[groupId]) == 'undefined') {
23354 return this.groups[groupId] ;
23367 * @class Roo.bootstrap.Radio
23368 * @extends Roo.bootstrap.Component
23369 * Bootstrap Radio class
23370 * @cfg {String} boxLabel - the label associated
23371 * @cfg {String} value - the value of radio
23374 * Create a new Radio
23375 * @param {Object} config The config object
23377 Roo.bootstrap.Radio = function(config){
23378 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
23382 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
23388 getAutoCreate : function()
23392 cls : 'form-group radio',
23397 html : this.boxLabel
23405 initEvents : function()
23407 this.parent().register(this);
23409 this.el.on('click', this.onClick, this);
23413 onClick : function(e)
23415 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
23416 this.setChecked(true);
23420 setChecked : function(state, suppressEvent)
23422 this.parent().setValue(this.value, suppressEvent);
23426 setBoxLabel : function(v)
23431 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23446 * @class Roo.bootstrap.SecurePass
23447 * @extends Roo.bootstrap.Input
23448 * Bootstrap SecurePass class
23452 * Create a new SecurePass
23453 * @param {Object} config The config object
23456 Roo.bootstrap.SecurePass = function (config) {
23457 // these go here, so the translation tool can replace them..
23459 PwdEmpty: "Please type a password, and then retype it to confirm.",
23460 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23461 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23462 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23463 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23464 FNInPwd: "Your password can't contain your first name. Please type a different password.",
23465 LNInPwd: "Your password can't contain your last name. Please type a different password.",
23466 TooWeak: "Your password is Too Weak."
23468 this.meterLabel = "Password strength:";
23469 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
23470 this.meterClass = [
23471 "roo-password-meter-tooweak",
23472 "roo-password-meter-weak",
23473 "roo-password-meter-medium",
23474 "roo-password-meter-strong",
23475 "roo-password-meter-grey"
23480 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
23483 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
23485 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
23487 * PwdEmpty: "Please type a password, and then retype it to confirm.",
23488 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23489 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23490 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23491 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23492 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
23493 * LNInPwd: "Your password can't contain your last name. Please type a different password."
23503 * @cfg {String/Object} Label for the strength meter (defaults to
23504 * 'Password strength:')
23509 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
23510 * ['Weak', 'Medium', 'Strong'])
23513 pwdStrengths: false,
23526 initEvents: function ()
23528 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
23530 if (this.el.is('input[type=password]') && Roo.isSafari) {
23531 this.el.on('keydown', this.SafariOnKeyDown, this);
23534 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
23537 onRender: function (ct, position)
23539 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
23540 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
23541 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
23543 this.trigger.createChild({
23548 cls: 'roo-password-meter-grey col-xs-12',
23551 //width: this.meterWidth + 'px'
23555 cls: 'roo-password-meter-text'
23561 if (this.hideTrigger) {
23562 this.trigger.setDisplayed(false);
23564 this.setSize(this.width || '', this.height || '');
23567 onDestroy: function ()
23569 if (this.trigger) {
23570 this.trigger.removeAllListeners();
23571 this.trigger.remove();
23574 this.wrap.remove();
23576 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
23579 checkStrength: function ()
23581 var pwd = this.inputEl().getValue();
23582 if (pwd == this._lastPwd) {
23587 if (this.ClientSideStrongPassword(pwd)) {
23589 } else if (this.ClientSideMediumPassword(pwd)) {
23591 } else if (this.ClientSideWeakPassword(pwd)) {
23597 Roo.log('strength1: ' + strength);
23599 //var pm = this.trigger.child('div/div/div').dom;
23600 var pm = this.trigger.child('div/div');
23601 pm.removeClass(this.meterClass);
23602 pm.addClass(this.meterClass[strength]);
23605 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23607 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23609 this._lastPwd = pwd;
23613 Roo.bootstrap.SecurePass.superclass.reset.call(this);
23615 this._lastPwd = '';
23617 var pm = this.trigger.child('div/div');
23618 pm.removeClass(this.meterClass);
23619 pm.addClass('roo-password-meter-grey');
23622 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23625 this.inputEl().dom.type='password';
23628 validateValue: function (value)
23630 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
23633 if (value.length == 0) {
23634 if (this.allowBlank) {
23635 this.clearInvalid();
23639 this.markInvalid(this.errors.PwdEmpty);
23640 this.errorMsg = this.errors.PwdEmpty;
23648 if (!value.match(/[\x21-\x7e]+/)) {
23649 this.markInvalid(this.errors.PwdBadChar);
23650 this.errorMsg = this.errors.PwdBadChar;
23653 if (value.length < 6) {
23654 this.markInvalid(this.errors.PwdShort);
23655 this.errorMsg = this.errors.PwdShort;
23658 if (value.length > 16) {
23659 this.markInvalid(this.errors.PwdLong);
23660 this.errorMsg = this.errors.PwdLong;
23664 if (this.ClientSideStrongPassword(value)) {
23666 } else if (this.ClientSideMediumPassword(value)) {
23668 } else if (this.ClientSideWeakPassword(value)) {
23675 if (strength < 2) {
23676 //this.markInvalid(this.errors.TooWeak);
23677 this.errorMsg = this.errors.TooWeak;
23682 console.log('strength2: ' + strength);
23684 //var pm = this.trigger.child('div/div/div').dom;
23686 var pm = this.trigger.child('div/div');
23687 pm.removeClass(this.meterClass);
23688 pm.addClass(this.meterClass[strength]);
23690 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23692 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23694 this.errorMsg = '';
23698 CharacterSetChecks: function (type)
23701 this.fResult = false;
23704 isctype: function (character, type)
23707 case this.kCapitalLetter:
23708 if (character >= 'A' && character <= 'Z') {
23713 case this.kSmallLetter:
23714 if (character >= 'a' && character <= 'z') {
23720 if (character >= '0' && character <= '9') {
23725 case this.kPunctuation:
23726 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
23737 IsLongEnough: function (pwd, size)
23739 return !(pwd == null || isNaN(size) || pwd.length < size);
23742 SpansEnoughCharacterSets: function (word, nb)
23744 if (!this.IsLongEnough(word, nb))
23749 var characterSetChecks = new Array(
23750 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
23751 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
23754 for (var index = 0; index < word.length; ++index) {
23755 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23756 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
23757 characterSetChecks[nCharSet].fResult = true;
23764 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23765 if (characterSetChecks[nCharSet].fResult) {
23770 if (nCharSets < nb) {
23776 ClientSideStrongPassword: function (pwd)
23778 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
23781 ClientSideMediumPassword: function (pwd)
23783 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
23786 ClientSideWeakPassword: function (pwd)
23788 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
23791 })//<script type="text/javascript">
23794 * Based Ext JS Library 1.1.1
23795 * Copyright(c) 2006-2007, Ext JS, LLC.
23801 * @class Roo.HtmlEditorCore
23802 * @extends Roo.Component
23803 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23805 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23808 Roo.HtmlEditorCore = function(config){
23811 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23816 * @event initialize
23817 * Fires when the editor is fully initialized (including the iframe)
23818 * @param {Roo.HtmlEditorCore} this
23823 * Fires when the editor is first receives the focus. Any insertion must wait
23824 * until after this event.
23825 * @param {Roo.HtmlEditorCore} this
23829 * @event beforesync
23830 * Fires before the textarea is updated with content from the editor iframe. Return false
23831 * to cancel the sync.
23832 * @param {Roo.HtmlEditorCore} this
23833 * @param {String} html
23837 * @event beforepush
23838 * Fires before the iframe editor is updated with content from the textarea. Return false
23839 * to cancel the push.
23840 * @param {Roo.HtmlEditorCore} this
23841 * @param {String} html
23846 * Fires when the textarea is updated with content from the editor iframe.
23847 * @param {Roo.HtmlEditorCore} this
23848 * @param {String} html
23853 * Fires when the iframe editor is updated with content from the textarea.
23854 * @param {Roo.HtmlEditorCore} this
23855 * @param {String} html
23860 * @event editorevent
23861 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23862 * @param {Roo.HtmlEditorCore} this
23868 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23870 // defaults : white / black...
23871 this.applyBlacklists();
23878 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23882 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23888 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23893 * @cfg {Number} height (in pixels)
23897 * @cfg {Number} width (in pixels)
23902 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23905 stylesheets: false,
23910 // private properties
23911 validationEvent : false,
23913 initialized : false,
23915 sourceEditMode : false,
23916 onFocus : Roo.emptyFn,
23918 hideMode:'offsets',
23922 // blacklist + whitelisted elements..
23929 * Protected method that will not generally be called directly. It
23930 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23931 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23933 getDocMarkup : function(){
23937 // inherit styels from page...??
23938 if (this.stylesheets === false) {
23940 Roo.get(document.head).select('style').each(function(node) {
23941 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23944 Roo.get(document.head).select('link').each(function(node) {
23945 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23948 } else if (!this.stylesheets.length) {
23950 st = '<style type="text/css">' +
23951 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23954 for (var i in this.stylesheets) {
23955 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
23960 st += '<style type="text/css">' +
23961 'IMG { cursor: pointer } ' +
23964 var cls = 'roo-htmleditor-body';
23966 if(this.bodyCls.length){
23967 cls += ' ' + this.bodyCls;
23970 return '<html><head>' + st +
23971 //<style type="text/css">' +
23972 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23974 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23978 onRender : function(ct, position)
23981 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23982 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23985 this.el.dom.style.border = '0 none';
23986 this.el.dom.setAttribute('tabIndex', -1);
23987 this.el.addClass('x-hidden hide');
23991 if(Roo.isIE){ // fix IE 1px bogus margin
23992 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23996 this.frameId = Roo.id();
24000 var iframe = this.owner.wrap.createChild({
24002 cls: 'form-control', // bootstrap..
24004 name: this.frameId,
24005 frameBorder : 'no',
24006 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24011 this.iframe = iframe.dom;
24013 this.assignDocWin();
24015 this.doc.designMode = 'on';
24018 this.doc.write(this.getDocMarkup());
24022 var task = { // must defer to wait for browser to be ready
24024 //console.log("run task?" + this.doc.readyState);
24025 this.assignDocWin();
24026 if(this.doc.body || this.doc.readyState == 'complete'){
24028 this.doc.designMode="on";
24032 Roo.TaskMgr.stop(task);
24033 this.initEditor.defer(10, this);
24040 Roo.TaskMgr.start(task);
24045 onResize : function(w, h)
24047 Roo.log('resize: ' +w + ',' + h );
24048 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
24052 if(typeof w == 'number'){
24054 this.iframe.style.width = w + 'px';
24056 if(typeof h == 'number'){
24058 this.iframe.style.height = h + 'px';
24060 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
24067 * Toggles the editor between standard and source edit mode.
24068 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24070 toggleSourceEdit : function(sourceEditMode){
24072 this.sourceEditMode = sourceEditMode === true;
24074 if(this.sourceEditMode){
24076 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
24079 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
24080 //this.iframe.className = '';
24083 //this.setSize(this.owner.wrap.getSize());
24084 //this.fireEvent('editmodechange', this, this.sourceEditMode);
24091 * Protected method that will not generally be called directly. If you need/want
24092 * custom HTML cleanup, this is the method you should override.
24093 * @param {String} html The HTML to be cleaned
24094 * return {String} The cleaned HTML
24096 cleanHtml : function(html){
24097 html = String(html);
24098 if(html.length > 5){
24099 if(Roo.isSafari){ // strip safari nonsense
24100 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24103 if(html == ' '){
24110 * HTML Editor -> Textarea
24111 * Protected method that will not generally be called directly. Syncs the contents
24112 * of the editor iframe with the textarea.
24114 syncValue : function(){
24115 if(this.initialized){
24116 var bd = (this.doc.body || this.doc.documentElement);
24117 //this.cleanUpPaste(); -- this is done else where and causes havoc..
24118 var html = bd.innerHTML;
24120 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24121 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
24123 html = '<div style="'+m[0]+'">' + html + '</div>';
24126 html = this.cleanHtml(html);
24127 // fix up the special chars.. normaly like back quotes in word...
24128 // however we do not want to do this with chinese..
24129 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
24131 var cc = match.charCodeAt();
24133 // Get the character value, handling surrogate pairs
24134 if (match.length == 2) {
24135 // It's a surrogate pair, calculate the Unicode code point
24136 var high = match.charCodeAt(0) - 0xD800;
24137 var low = match.charCodeAt(1) - 0xDC00;
24138 cc = (high * 0x400) + low + 0x10000;
24140 (cc >= 0x4E00 && cc < 0xA000 ) ||
24141 (cc >= 0x3400 && cc < 0x4E00 ) ||
24142 (cc >= 0xf900 && cc < 0xfb00 )
24147 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
24148 return "&#" + cc + ";";
24155 if(this.owner.fireEvent('beforesync', this, html) !== false){
24156 this.el.dom.value = html;
24157 this.owner.fireEvent('sync', this, html);
24163 * Protected method that will not generally be called directly. Pushes the value of the textarea
24164 * into the iframe editor.
24166 pushValue : function(){
24167 if(this.initialized){
24168 var v = this.el.dom.value.trim();
24170 // if(v.length < 1){
24174 if(this.owner.fireEvent('beforepush', this, v) !== false){
24175 var d = (this.doc.body || this.doc.documentElement);
24177 this.cleanUpPaste();
24178 this.el.dom.value = d.innerHTML;
24179 this.owner.fireEvent('push', this, v);
24185 deferFocus : function(){
24186 this.focus.defer(10, this);
24190 focus : function(){
24191 if(this.win && !this.sourceEditMode){
24198 assignDocWin: function()
24200 var iframe = this.iframe;
24203 this.doc = iframe.contentWindow.document;
24204 this.win = iframe.contentWindow;
24206 // if (!Roo.get(this.frameId)) {
24209 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24210 // this.win = Roo.get(this.frameId).dom.contentWindow;
24212 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
24216 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24217 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
24222 initEditor : function(){
24223 //console.log("INIT EDITOR");
24224 this.assignDocWin();
24228 this.doc.designMode="on";
24230 this.doc.write(this.getDocMarkup());
24233 var dbody = (this.doc.body || this.doc.documentElement);
24234 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24235 // this copies styles from the containing element into thsi one..
24236 // not sure why we need all of this..
24237 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24239 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
24240 //ss['background-attachment'] = 'fixed'; // w3c
24241 dbody.bgProperties = 'fixed'; // ie
24242 //Roo.DomHelper.applyStyles(dbody, ss);
24243 Roo.EventManager.on(this.doc, {
24244 //'mousedown': this.onEditorEvent,
24245 'mouseup': this.onEditorEvent,
24246 'dblclick': this.onEditorEvent,
24247 'click': this.onEditorEvent,
24248 'keyup': this.onEditorEvent,
24253 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24255 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24256 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24258 this.initialized = true;
24260 this.owner.fireEvent('initialize', this);
24265 onDestroy : function(){
24271 //for (var i =0; i < this.toolbars.length;i++) {
24272 // // fixme - ask toolbars for heights?
24273 // this.toolbars[i].onDestroy();
24276 //this.wrap.dom.innerHTML = '';
24277 //this.wrap.remove();
24282 onFirstFocus : function(){
24284 this.assignDocWin();
24287 this.activated = true;
24290 if(Roo.isGecko){ // prevent silly gecko errors
24292 var s = this.win.getSelection();
24293 if(!s.focusNode || s.focusNode.nodeType != 3){
24294 var r = s.getRangeAt(0);
24295 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24300 this.execCmd('useCSS', true);
24301 this.execCmd('styleWithCSS', false);
24304 this.owner.fireEvent('activate', this);
24308 adjustFont: function(btn){
24309 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24310 //if(Roo.isSafari){ // safari
24313 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24314 if(Roo.isSafari){ // safari
24315 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24316 v = (v < 10) ? 10 : v;
24317 v = (v > 48) ? 48 : v;
24318 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24323 v = Math.max(1, v+adjust);
24325 this.execCmd('FontSize', v );
24328 onEditorEvent : function(e)
24330 this.owner.fireEvent('editorevent', this, e);
24331 // this.updateToolbar();
24332 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
24335 insertTag : function(tg)
24337 // could be a bit smarter... -> wrap the current selected tRoo..
24338 if (tg.toLowerCase() == 'span' ||
24339 tg.toLowerCase() == 'code' ||
24340 tg.toLowerCase() == 'sup' ||
24341 tg.toLowerCase() == 'sub'
24344 range = this.createRange(this.getSelection());
24345 var wrappingNode = this.doc.createElement(tg.toLowerCase());
24346 wrappingNode.appendChild(range.extractContents());
24347 range.insertNode(wrappingNode);
24354 this.execCmd("formatblock", tg);
24358 insertText : function(txt)
24362 var range = this.createRange();
24363 range.deleteContents();
24364 //alert(Sender.getAttribute('label'));
24366 range.insertNode(this.doc.createTextNode(txt));
24372 * Executes a Midas editor command on the editor document and performs necessary focus and
24373 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24374 * @param {String} cmd The Midas command
24375 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24377 relayCmd : function(cmd, value){
24379 this.execCmd(cmd, value);
24380 this.owner.fireEvent('editorevent', this);
24381 //this.updateToolbar();
24382 this.owner.deferFocus();
24386 * Executes a Midas editor command directly on the editor document.
24387 * For visual commands, you should use {@link #relayCmd} instead.
24388 * <b>This should only be called after the editor is initialized.</b>
24389 * @param {String} cmd The Midas command
24390 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24392 execCmd : function(cmd, value){
24393 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24400 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24402 * @param {String} text | dom node..
24404 insertAtCursor : function(text)
24407 if(!this.activated){
24413 var r = this.doc.selection.createRange();
24424 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24428 // from jquery ui (MIT licenced)
24430 var win = this.win;
24432 if (win.getSelection && win.getSelection().getRangeAt) {
24433 range = win.getSelection().getRangeAt(0);
24434 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
24435 range.insertNode(node);
24436 } else if (win.document.selection && win.document.selection.createRange) {
24437 // no firefox support
24438 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24439 win.document.selection.createRange().pasteHTML(txt);
24441 // no firefox support
24442 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24443 this.execCmd('InsertHTML', txt);
24452 mozKeyPress : function(e){
24454 var c = e.getCharCode(), cmd;
24457 c = String.fromCharCode(c).toLowerCase();
24471 this.cleanUpPaste.defer(100, this);
24479 e.preventDefault();
24487 fixKeys : function(){ // load time branching for fastest keydown performance
24489 return function(e){
24490 var k = e.getKey(), r;
24493 r = this.doc.selection.createRange();
24496 r.pasteHTML('    ');
24503 r = this.doc.selection.createRange();
24505 var target = r.parentElement();
24506 if(!target || target.tagName.toLowerCase() != 'li'){
24508 r.pasteHTML('<br />');
24514 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24515 this.cleanUpPaste.defer(100, this);
24521 }else if(Roo.isOpera){
24522 return function(e){
24523 var k = e.getKey();
24527 this.execCmd('InsertHTML','    ');
24530 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24531 this.cleanUpPaste.defer(100, this);
24536 }else if(Roo.isSafari){
24537 return function(e){
24538 var k = e.getKey();
24542 this.execCmd('InsertText','\t');
24546 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24547 this.cleanUpPaste.defer(100, this);
24555 getAllAncestors: function()
24557 var p = this.getSelectedNode();
24560 a.push(p); // push blank onto stack..
24561 p = this.getParentElement();
24565 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24569 a.push(this.doc.body);
24573 lastSelNode : false,
24576 getSelection : function()
24578 this.assignDocWin();
24579 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24582 getSelectedNode: function()
24584 // this may only work on Gecko!!!
24586 // should we cache this!!!!
24591 var range = this.createRange(this.getSelection()).cloneRange();
24594 var parent = range.parentElement();
24596 var testRange = range.duplicate();
24597 testRange.moveToElementText(parent);
24598 if (testRange.inRange(range)) {
24601 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24604 parent = parent.parentElement;
24609 // is ancestor a text element.
24610 var ac = range.commonAncestorContainer;
24611 if (ac.nodeType == 3) {
24612 ac = ac.parentNode;
24615 var ar = ac.childNodes;
24618 var other_nodes = [];
24619 var has_other_nodes = false;
24620 for (var i=0;i<ar.length;i++) {
24621 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24624 // fullly contained node.
24626 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24631 // probably selected..
24632 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24633 other_nodes.push(ar[i]);
24637 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24642 has_other_nodes = true;
24644 if (!nodes.length && other_nodes.length) {
24645 nodes= other_nodes;
24647 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24653 createRange: function(sel)
24655 // this has strange effects when using with
24656 // top toolbar - not sure if it's a great idea.
24657 //this.editor.contentWindow.focus();
24658 if (typeof sel != "undefined") {
24660 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24662 return this.doc.createRange();
24665 return this.doc.createRange();
24668 getParentElement: function()
24671 this.assignDocWin();
24672 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24674 var range = this.createRange(sel);
24677 var p = range.commonAncestorContainer;
24678 while (p.nodeType == 3) { // text node
24689 * Range intersection.. the hard stuff...
24693 * [ -- selected range --- ]
24697 * if end is before start or hits it. fail.
24698 * if start is after end or hits it fail.
24700 * if either hits (but other is outside. - then it's not
24706 // @see http://www.thismuchiknow.co.uk/?p=64.
24707 rangeIntersectsNode : function(range, node)
24709 var nodeRange = node.ownerDocument.createRange();
24711 nodeRange.selectNode(node);
24713 nodeRange.selectNodeContents(node);
24716 var rangeStartRange = range.cloneRange();
24717 rangeStartRange.collapse(true);
24719 var rangeEndRange = range.cloneRange();
24720 rangeEndRange.collapse(false);
24722 var nodeStartRange = nodeRange.cloneRange();
24723 nodeStartRange.collapse(true);
24725 var nodeEndRange = nodeRange.cloneRange();
24726 nodeEndRange.collapse(false);
24728 return rangeStartRange.compareBoundaryPoints(
24729 Range.START_TO_START, nodeEndRange) == -1 &&
24730 rangeEndRange.compareBoundaryPoints(
24731 Range.START_TO_START, nodeStartRange) == 1;
24735 rangeCompareNode : function(range, node)
24737 var nodeRange = node.ownerDocument.createRange();
24739 nodeRange.selectNode(node);
24741 nodeRange.selectNodeContents(node);
24745 range.collapse(true);
24747 nodeRange.collapse(true);
24749 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
24750 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
24752 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
24754 var nodeIsBefore = ss == 1;
24755 var nodeIsAfter = ee == -1;
24757 if (nodeIsBefore && nodeIsAfter) {
24760 if (!nodeIsBefore && nodeIsAfter) {
24761 return 1; //right trailed.
24764 if (nodeIsBefore && !nodeIsAfter) {
24765 return 2; // left trailed.
24771 // private? - in a new class?
24772 cleanUpPaste : function()
24774 // cleans up the whole document..
24775 Roo.log('cleanuppaste');
24777 this.cleanUpChildren(this.doc.body);
24778 var clean = this.cleanWordChars(this.doc.body.innerHTML);
24779 if (clean != this.doc.body.innerHTML) {
24780 this.doc.body.innerHTML = clean;
24785 cleanWordChars : function(input) {// change the chars to hex code
24786 var he = Roo.HtmlEditorCore;
24788 var output = input;
24789 Roo.each(he.swapCodes, function(sw) {
24790 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
24792 output = output.replace(swapper, sw[1]);
24799 cleanUpChildren : function (n)
24801 if (!n.childNodes.length) {
24804 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24805 this.cleanUpChild(n.childNodes[i]);
24812 cleanUpChild : function (node)
24815 //console.log(node);
24816 if (node.nodeName == "#text") {
24817 // clean up silly Windows -- stuff?
24820 if (node.nodeName == "#comment") {
24821 node.parentNode.removeChild(node);
24822 // clean up silly Windows -- stuff?
24825 var lcname = node.tagName.toLowerCase();
24826 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24827 // whitelist of tags..
24829 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24831 node.parentNode.removeChild(node);
24836 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24838 // spans with no attributes - just remove them..
24839 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24840 remove_keep_children = true;
24843 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24844 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24846 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24847 // remove_keep_children = true;
24850 if (remove_keep_children) {
24851 this.cleanUpChildren(node);
24852 // inserts everything just before this node...
24853 while (node.childNodes.length) {
24854 var cn = node.childNodes[0];
24855 node.removeChild(cn);
24856 node.parentNode.insertBefore(cn, node);
24858 node.parentNode.removeChild(node);
24862 if (!node.attributes || !node.attributes.length) {
24867 this.cleanUpChildren(node);
24871 function cleanAttr(n,v)
24874 if (v.match(/^\./) || v.match(/^\//)) {
24877 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24880 if (v.match(/^#/)) {
24883 if (v.match(/^\{/)) { // allow template editing.
24886 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24887 node.removeAttribute(n);
24891 var cwhite = this.cwhite;
24892 var cblack = this.cblack;
24894 function cleanStyle(n,v)
24896 if (v.match(/expression/)) { //XSS?? should we even bother..
24897 node.removeAttribute(n);
24901 var parts = v.split(/;/);
24904 Roo.each(parts, function(p) {
24905 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24909 var l = p.split(':').shift().replace(/\s+/g,'');
24910 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24912 if ( cwhite.length && cblack.indexOf(l) > -1) {
24913 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24914 //node.removeAttribute(n);
24918 // only allow 'c whitelisted system attributes'
24919 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24920 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24921 //node.removeAttribute(n);
24931 if (clean.length) {
24932 node.setAttribute(n, clean.join(';'));
24934 node.removeAttribute(n);
24940 for (var i = node.attributes.length-1; i > -1 ; i--) {
24941 var a = node.attributes[i];
24944 if (a.name.toLowerCase().substr(0,2)=='on') {
24945 node.removeAttribute(a.name);
24948 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24949 node.removeAttribute(a.name);
24952 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24953 cleanAttr(a.name,a.value); // fixme..
24956 if (a.name == 'style') {
24957 cleanStyle(a.name,a.value);
24960 /// clean up MS crap..
24961 // tecnically this should be a list of valid class'es..
24964 if (a.name == 'class') {
24965 if (a.value.match(/^Mso/)) {
24966 node.removeAttribute('class');
24969 if (a.value.match(/^body$/)) {
24970 node.removeAttribute('class');
24981 this.cleanUpChildren(node);
24987 * Clean up MS wordisms...
24989 cleanWord : function(node)
24992 this.cleanWord(this.doc.body);
24997 node.nodeName == 'SPAN' &&
24998 !node.hasAttributes() &&
24999 node.childNodes.length == 1 &&
25000 node.firstChild.nodeName == "#text"
25002 var textNode = node.firstChild;
25003 node.removeChild(textNode);
25004 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
25005 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
25007 node.parentNode.insertBefore(textNode, node);
25008 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
25009 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
25011 node.parentNode.removeChild(node);
25014 if (node.nodeName == "#text") {
25015 // clean up silly Windows -- stuff?
25018 if (node.nodeName == "#comment") {
25019 node.parentNode.removeChild(node);
25020 // clean up silly Windows -- stuff?
25024 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
25025 node.parentNode.removeChild(node);
25028 //Roo.log(node.tagName);
25029 // remove - but keep children..
25030 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
25031 //Roo.log('-- removed');
25032 while (node.childNodes.length) {
25033 var cn = node.childNodes[0];
25034 node.removeChild(cn);
25035 node.parentNode.insertBefore(cn, node);
25036 // move node to parent - and clean it..
25037 this.cleanWord(cn);
25039 node.parentNode.removeChild(node);
25040 /// no need to iterate chidlren = it's got none..
25041 //this.iterateChildren(node, this.cleanWord);
25045 if (node.className.length) {
25047 var cn = node.className.split(/\W+/);
25049 Roo.each(cn, function(cls) {
25050 if (cls.match(/Mso[a-zA-Z]+/)) {
25055 node.className = cna.length ? cna.join(' ') : '';
25057 node.removeAttribute("class");
25061 if (node.hasAttribute("lang")) {
25062 node.removeAttribute("lang");
25065 if (node.hasAttribute("style")) {
25067 var styles = node.getAttribute("style").split(";");
25069 Roo.each(styles, function(s) {
25070 if (!s.match(/:/)) {
25073 var kv = s.split(":");
25074 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
25077 // what ever is left... we allow.
25080 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25081 if (!nstyle.length) {
25082 node.removeAttribute('style');
25085 this.iterateChildren(node, this.cleanWord);
25091 * iterateChildren of a Node, calling fn each time, using this as the scole..
25092 * @param {DomNode} node node to iterate children of.
25093 * @param {Function} fn method of this class to call on each item.
25095 iterateChildren : function(node, fn)
25097 if (!node.childNodes.length) {
25100 for (var i = node.childNodes.length-1; i > -1 ; i--) {
25101 fn.call(this, node.childNodes[i])
25107 * cleanTableWidths.
25109 * Quite often pasting from word etc.. results in tables with column and widths.
25110 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
25113 cleanTableWidths : function(node)
25118 this.cleanTableWidths(this.doc.body);
25123 if (node.nodeName == "#text" || node.nodeName == "#comment") {
25126 Roo.log(node.tagName);
25127 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
25128 this.iterateChildren(node, this.cleanTableWidths);
25131 if (node.hasAttribute('width')) {
25132 node.removeAttribute('width');
25136 if (node.hasAttribute("style")) {
25139 var styles = node.getAttribute("style").split(";");
25141 Roo.each(styles, function(s) {
25142 if (!s.match(/:/)) {
25145 var kv = s.split(":");
25146 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
25149 // what ever is left... we allow.
25152 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25153 if (!nstyle.length) {
25154 node.removeAttribute('style');
25158 this.iterateChildren(node, this.cleanTableWidths);
25166 domToHTML : function(currentElement, depth, nopadtext) {
25168 depth = depth || 0;
25169 nopadtext = nopadtext || false;
25171 if (!currentElement) {
25172 return this.domToHTML(this.doc.body);
25175 //Roo.log(currentElement);
25177 var allText = false;
25178 var nodeName = currentElement.nodeName;
25179 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
25181 if (nodeName == '#text') {
25183 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
25188 if (nodeName != 'BODY') {
25191 // Prints the node tagName, such as <A>, <IMG>, etc
25194 for(i = 0; i < currentElement.attributes.length;i++) {
25196 var aname = currentElement.attributes.item(i).name;
25197 if (!currentElement.attributes.item(i).value.length) {
25200 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
25203 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
25212 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
25215 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
25220 // Traverse the tree
25222 var currentElementChild = currentElement.childNodes.item(i);
25223 var allText = true;
25224 var innerHTML = '';
25226 while (currentElementChild) {
25227 // Formatting code (indent the tree so it looks nice on the screen)
25228 var nopad = nopadtext;
25229 if (lastnode == 'SPAN') {
25233 if (currentElementChild.nodeName == '#text') {
25234 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
25235 toadd = nopadtext ? toadd : toadd.trim();
25236 if (!nopad && toadd.length > 80) {
25237 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
25239 innerHTML += toadd;
25242 currentElementChild = currentElement.childNodes.item(i);
25248 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
25250 // Recursively traverse the tree structure of the child node
25251 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
25252 lastnode = currentElementChild.nodeName;
25254 currentElementChild=currentElement.childNodes.item(i);
25260 // The remaining code is mostly for formatting the tree
25261 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
25266 ret+= "</"+tagName+">";
25272 applyBlacklists : function()
25274 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
25275 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
25279 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
25280 if (b.indexOf(tag) > -1) {
25283 this.white.push(tag);
25287 Roo.each(w, function(tag) {
25288 if (b.indexOf(tag) > -1) {
25291 if (this.white.indexOf(tag) > -1) {
25294 this.white.push(tag);
25299 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
25300 if (w.indexOf(tag) > -1) {
25303 this.black.push(tag);
25307 Roo.each(b, function(tag) {
25308 if (w.indexOf(tag) > -1) {
25311 if (this.black.indexOf(tag) > -1) {
25314 this.black.push(tag);
25319 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
25320 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
25324 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
25325 if (b.indexOf(tag) > -1) {
25328 this.cwhite.push(tag);
25332 Roo.each(w, function(tag) {
25333 if (b.indexOf(tag) > -1) {
25336 if (this.cwhite.indexOf(tag) > -1) {
25339 this.cwhite.push(tag);
25344 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
25345 if (w.indexOf(tag) > -1) {
25348 this.cblack.push(tag);
25352 Roo.each(b, function(tag) {
25353 if (w.indexOf(tag) > -1) {
25356 if (this.cblack.indexOf(tag) > -1) {
25359 this.cblack.push(tag);
25364 setStylesheets : function(stylesheets)
25366 if(typeof(stylesheets) == 'string'){
25367 Roo.get(this.iframe.contentDocument.head).createChild({
25369 rel : 'stylesheet',
25378 Roo.each(stylesheets, function(s) {
25383 Roo.get(_this.iframe.contentDocument.head).createChild({
25385 rel : 'stylesheet',
25394 removeStylesheets : function()
25398 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
25403 setStyle : function(style)
25405 Roo.get(this.iframe.contentDocument.head).createChild({
25414 // hide stuff that is not compatible
25428 * @event specialkey
25432 * @cfg {String} fieldClass @hide
25435 * @cfg {String} focusClass @hide
25438 * @cfg {String} autoCreate @hide
25441 * @cfg {String} inputType @hide
25444 * @cfg {String} invalidClass @hide
25447 * @cfg {String} invalidText @hide
25450 * @cfg {String} msgFx @hide
25453 * @cfg {String} validateOnBlur @hide
25457 Roo.HtmlEditorCore.white = [
25458 'area', 'br', 'img', 'input', 'hr', 'wbr',
25460 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
25461 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
25462 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
25463 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
25464 'table', 'ul', 'xmp',
25466 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
25469 'dir', 'menu', 'ol', 'ul', 'dl',
25475 Roo.HtmlEditorCore.black = [
25476 // 'embed', 'object', // enable - backend responsiblity to clean thiese
25478 'base', 'basefont', 'bgsound', 'blink', 'body',
25479 'frame', 'frameset', 'head', 'html', 'ilayer',
25480 'iframe', 'layer', 'link', 'meta', 'object',
25481 'script', 'style' ,'title', 'xml' // clean later..
25483 Roo.HtmlEditorCore.clean = [
25484 'script', 'style', 'title', 'xml'
25486 Roo.HtmlEditorCore.remove = [
25491 Roo.HtmlEditorCore.ablack = [
25495 Roo.HtmlEditorCore.aclean = [
25496 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
25500 Roo.HtmlEditorCore.pwhite= [
25501 'http', 'https', 'mailto'
25504 // white listed style attributes.
25505 Roo.HtmlEditorCore.cwhite= [
25506 // 'text-align', /// default is to allow most things..
25512 // black listed style attributes.
25513 Roo.HtmlEditorCore.cblack= [
25514 // 'font-size' -- this can be set by the project
25518 Roo.HtmlEditorCore.swapCodes =[
25537 * @class Roo.bootstrap.HtmlEditor
25538 * @extends Roo.bootstrap.TextArea
25539 * Bootstrap HtmlEditor class
25542 * Create a new HtmlEditor
25543 * @param {Object} config The config object
25546 Roo.bootstrap.HtmlEditor = function(config){
25547 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
25548 if (!this.toolbars) {
25549 this.toolbars = [];
25552 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
25555 * @event initialize
25556 * Fires when the editor is fully initialized (including the iframe)
25557 * @param {HtmlEditor} this
25562 * Fires when the editor is first receives the focus. Any insertion must wait
25563 * until after this event.
25564 * @param {HtmlEditor} this
25568 * @event beforesync
25569 * Fires before the textarea is updated with content from the editor iframe. Return false
25570 * to cancel the sync.
25571 * @param {HtmlEditor} this
25572 * @param {String} html
25576 * @event beforepush
25577 * Fires before the iframe editor is updated with content from the textarea. Return false
25578 * to cancel the push.
25579 * @param {HtmlEditor} this
25580 * @param {String} html
25585 * Fires when the textarea is updated with content from the editor iframe.
25586 * @param {HtmlEditor} this
25587 * @param {String} html
25592 * Fires when the iframe editor is updated with content from the textarea.
25593 * @param {HtmlEditor} this
25594 * @param {String} html
25598 * @event editmodechange
25599 * Fires when the editor switches edit modes
25600 * @param {HtmlEditor} this
25601 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
25603 editmodechange: true,
25605 * @event editorevent
25606 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
25607 * @param {HtmlEditor} this
25611 * @event firstfocus
25612 * Fires when on first focus - needed by toolbars..
25613 * @param {HtmlEditor} this
25618 * Auto save the htmlEditor value as a file into Events
25619 * @param {HtmlEditor} this
25623 * @event savedpreview
25624 * preview the saved version of htmlEditor
25625 * @param {HtmlEditor} this
25632 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
25636 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
25641 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
25646 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
25651 * @cfg {Number} height (in pixels)
25655 * @cfg {Number} width (in pixels)
25660 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
25663 stylesheets: false,
25668 // private properties
25669 validationEvent : false,
25671 initialized : false,
25674 onFocus : Roo.emptyFn,
25676 hideMode:'offsets',
25678 tbContainer : false,
25682 toolbarContainer :function() {
25683 return this.wrap.select('.x-html-editor-tb',true).first();
25687 * Protected method that will not generally be called directly. It
25688 * is called when the editor creates its toolbar. Override this method if you need to
25689 * add custom toolbar buttons.
25690 * @param {HtmlEditor} editor
25692 createToolbar : function(){
25693 Roo.log('renewing');
25694 Roo.log("create toolbars");
25696 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
25697 this.toolbars[0].render(this.toolbarContainer());
25701 // if (!editor.toolbars || !editor.toolbars.length) {
25702 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
25705 // for (var i =0 ; i < editor.toolbars.length;i++) {
25706 // editor.toolbars[i] = Roo.factory(
25707 // typeof(editor.toolbars[i]) == 'string' ?
25708 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
25709 // Roo.bootstrap.HtmlEditor);
25710 // editor.toolbars[i].init(editor);
25716 onRender : function(ct, position)
25718 // Roo.log("Call onRender: " + this.xtype);
25720 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
25722 this.wrap = this.inputEl().wrap({
25723 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
25726 this.editorcore.onRender(ct, position);
25728 if (this.resizable) {
25729 this.resizeEl = new Roo.Resizable(this.wrap, {
25733 minHeight : this.height,
25734 height: this.height,
25735 handles : this.resizable,
25738 resize : function(r, w, h) {
25739 _t.onResize(w,h); // -something
25745 this.createToolbar(this);
25748 if(!this.width && this.resizable){
25749 this.setSize(this.wrap.getSize());
25751 if (this.resizeEl) {
25752 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
25753 // should trigger onReize..
25759 onResize : function(w, h)
25761 Roo.log('resize: ' +w + ',' + h );
25762 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
25766 if(this.inputEl() ){
25767 if(typeof w == 'number'){
25768 var aw = w - this.wrap.getFrameWidth('lr');
25769 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
25772 if(typeof h == 'number'){
25773 var tbh = -11; // fixme it needs to tool bar size!
25774 for (var i =0; i < this.toolbars.length;i++) {
25775 // fixme - ask toolbars for heights?
25776 tbh += this.toolbars[i].el.getHeight();
25777 //if (this.toolbars[i].footer) {
25778 // tbh += this.toolbars[i].footer.el.getHeight();
25786 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
25787 ah -= 5; // knock a few pixes off for look..
25788 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
25792 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
25793 this.editorcore.onResize(ew,eh);
25798 * Toggles the editor between standard and source edit mode.
25799 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
25801 toggleSourceEdit : function(sourceEditMode)
25803 this.editorcore.toggleSourceEdit(sourceEditMode);
25805 if(this.editorcore.sourceEditMode){
25806 Roo.log('editor - showing textarea');
25809 // Roo.log(this.syncValue());
25811 this.inputEl().removeClass(['hide', 'x-hidden']);
25812 this.inputEl().dom.removeAttribute('tabIndex');
25813 this.inputEl().focus();
25815 Roo.log('editor - hiding textarea');
25817 // Roo.log(this.pushValue());
25820 this.inputEl().addClass(['hide', 'x-hidden']);
25821 this.inputEl().dom.setAttribute('tabIndex', -1);
25822 //this.deferFocus();
25825 if(this.resizable){
25826 this.setSize(this.wrap.getSize());
25829 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25832 // private (for BoxComponent)
25833 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25835 // private (for BoxComponent)
25836 getResizeEl : function(){
25840 // private (for BoxComponent)
25841 getPositionEl : function(){
25846 initEvents : function(){
25847 this.originalValue = this.getValue();
25851 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25854 // markInvalid : Roo.emptyFn,
25856 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25859 // clearInvalid : Roo.emptyFn,
25861 setValue : function(v){
25862 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25863 this.editorcore.pushValue();
25868 deferFocus : function(){
25869 this.focus.defer(10, this);
25873 focus : function(){
25874 this.editorcore.focus();
25880 onDestroy : function(){
25886 for (var i =0; i < this.toolbars.length;i++) {
25887 // fixme - ask toolbars for heights?
25888 this.toolbars[i].onDestroy();
25891 this.wrap.dom.innerHTML = '';
25892 this.wrap.remove();
25897 onFirstFocus : function(){
25898 //Roo.log("onFirstFocus");
25899 this.editorcore.onFirstFocus();
25900 for (var i =0; i < this.toolbars.length;i++) {
25901 this.toolbars[i].onFirstFocus();
25907 syncValue : function()
25909 this.editorcore.syncValue();
25912 pushValue : function()
25914 this.editorcore.pushValue();
25918 // hide stuff that is not compatible
25932 * @event specialkey
25936 * @cfg {String} fieldClass @hide
25939 * @cfg {String} focusClass @hide
25942 * @cfg {String} autoCreate @hide
25945 * @cfg {String} inputType @hide
25949 * @cfg {String} invalidText @hide
25952 * @cfg {String} msgFx @hide
25955 * @cfg {String} validateOnBlur @hide
25964 Roo.namespace('Roo.bootstrap.htmleditor');
25966 * @class Roo.bootstrap.HtmlEditorToolbar1
25972 new Roo.bootstrap.HtmlEditor({
25975 new Roo.bootstrap.HtmlEditorToolbar1({
25976 disable : { fonts: 1 , format: 1, ..., ... , ...],
25982 * @cfg {Object} disable List of elements to disable..
25983 * @cfg {Array} btns List of additional buttons.
25987 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25990 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25993 Roo.apply(this, config);
25995 // default disabled, based on 'good practice'..
25996 this.disable = this.disable || {};
25997 Roo.applyIf(this.disable, {
26000 specialElements : true
26002 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
26004 this.editor = config.editor;
26005 this.editorcore = config.editor.editorcore;
26007 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
26009 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
26010 // dont call parent... till later.
26012 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
26017 editorcore : false,
26022 "h1","h2","h3","h4","h5","h6",
26024 "abbr", "acronym", "address", "cite", "samp", "var",
26028 onRender : function(ct, position)
26030 // Roo.log("Call onRender: " + this.xtype);
26032 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
26034 this.el.dom.style.marginBottom = '0';
26036 var editorcore = this.editorcore;
26037 var editor= this.editor;
26040 var btn = function(id,cmd , toggle, handler, html){
26042 var event = toggle ? 'toggle' : 'click';
26047 xns: Roo.bootstrap,
26051 enableToggle:toggle !== false,
26053 pressed : toggle ? false : null,
26056 a.listeners[toggle ? 'toggle' : 'click'] = function() {
26057 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
26063 // var cb_box = function...
26068 xns: Roo.bootstrap,
26073 xns: Roo.bootstrap,
26077 Roo.each(this.formats, function(f) {
26078 style.menu.items.push({
26080 xns: Roo.bootstrap,
26081 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
26086 editorcore.insertTag(this.tagname);
26093 children.push(style);
26095 btn('bold',false,true);
26096 btn('italic',false,true);
26097 btn('align-left', 'justifyleft',true);
26098 btn('align-center', 'justifycenter',true);
26099 btn('align-right' , 'justifyright',true);
26100 btn('link', false, false, function(btn) {
26101 //Roo.log("create link?");
26102 var url = prompt(this.createLinkText, this.defaultLinkValue);
26103 if(url && url != 'http:/'+'/'){
26104 this.editorcore.relayCmd('createlink', url);
26107 btn('list','insertunorderedlist',true);
26108 btn('pencil', false,true, function(btn){
26110 this.toggleSourceEdit(btn.pressed);
26113 if (this.editor.btns.length > 0) {
26114 for (var i = 0; i<this.editor.btns.length; i++) {
26115 children.push(this.editor.btns[i]);
26123 xns: Roo.bootstrap,
26128 xns: Roo.bootstrap,
26133 cog.menu.items.push({
26135 xns: Roo.bootstrap,
26136 html : Clean styles,
26141 editorcore.insertTag(this.tagname);
26150 this.xtype = 'NavSimplebar';
26152 for(var i=0;i< children.length;i++) {
26154 this.buttons.add(this.addxtypeChild(children[i]));
26158 editor.on('editorevent', this.updateToolbar, this);
26160 onBtnClick : function(id)
26162 this.editorcore.relayCmd(id);
26163 this.editorcore.focus();
26167 * Protected method that will not generally be called directly. It triggers
26168 * a toolbar update by reading the markup state of the current selection in the editor.
26170 updateToolbar: function(){
26172 if(!this.editorcore.activated){
26173 this.editor.onFirstFocus(); // is this neeed?
26177 var btns = this.buttons;
26178 var doc = this.editorcore.doc;
26179 btns.get('bold').setActive(doc.queryCommandState('bold'));
26180 btns.get('italic').setActive(doc.queryCommandState('italic'));
26181 //btns.get('underline').setActive(doc.queryCommandState('underline'));
26183 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
26184 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
26185 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
26187 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
26188 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
26191 var ans = this.editorcore.getAllAncestors();
26192 if (this.formatCombo) {
26195 var store = this.formatCombo.store;
26196 this.formatCombo.setValue("");
26197 for (var i =0; i < ans.length;i++) {
26198 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
26200 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
26208 // hides menus... - so this cant be on a menu...
26209 Roo.bootstrap.MenuMgr.hideAll();
26211 Roo.bootstrap.MenuMgr.hideAll();
26212 //this.editorsyncValue();
26214 onFirstFocus: function() {
26215 this.buttons.each(function(item){
26219 toggleSourceEdit : function(sourceEditMode){
26222 if(sourceEditMode){
26223 Roo.log("disabling buttons");
26224 this.buttons.each( function(item){
26225 if(item.cmd != 'pencil'){
26231 Roo.log("enabling buttons");
26232 if(this.editorcore.initialized){
26233 this.buttons.each( function(item){
26239 Roo.log("calling toggole on editor");
26240 // tell the editor that it's been pressed..
26241 this.editor.toggleSourceEdit(sourceEditMode);
26255 * @class Roo.bootstrap.Markdown
26256 * @extends Roo.bootstrap.TextArea
26257 * Bootstrap Showdown editable area
26258 * @cfg {string} content
26261 * Create a new Showdown
26264 Roo.bootstrap.Markdown = function(config){
26265 Roo.bootstrap.Markdown.superclass.constructor.call(this, config);
26269 Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea, {
26273 initEvents : function()
26276 Roo.bootstrap.TextArea.prototype.initEvents.call(this);
26277 this.markdownEl = this.el.createChild({
26278 cls : 'roo-markdown-area'
26280 this.inputEl().addClass('d-none');
26281 if (this.getValue() == '') {
26282 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26285 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26287 this.markdownEl.on('click', this.toggleTextEdit, this);
26288 this.on('blur', this.toggleTextEdit, this);
26289 this.on('specialkey', this.resizeTextArea, this);
26292 toggleTextEdit : function()
26294 var sh = this.markdownEl.getHeight();
26295 this.inputEl().addClass('d-none');
26296 this.markdownEl.addClass('d-none');
26297 if (!this.editing) {
26299 this.inputEl().setHeight(Math.min(500, Math.max(sh,(this.getValue().split("\n").length+1) * 30)));
26300 this.inputEl().removeClass('d-none');
26301 this.inputEl().focus();
26302 this.editing = true;
26305 // show showdown...
26306 this.updateMarkdown();
26307 this.markdownEl.removeClass('d-none');
26308 this.editing = false;
26311 updateMarkdown : function()
26313 if (this.getValue() == '') {
26314 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26318 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26321 resizeTextArea: function () {
26324 Roo.log([sh, this.getValue().split("\n").length * 30]);
26325 this.inputEl().setHeight(Math.min(500, Math.max(sh, (this.getValue().split("\n").length +1) * 30)));
26327 setValue : function(val)
26329 Roo.bootstrap.TextArea.prototype.setValue.call(this,val);
26330 if (!this.editing) {
26331 this.updateMarkdown();
26337 if (!this.editing) {
26338 this.toggleTextEdit();
26346 * @class Roo.bootstrap.Table.AbstractSelectionModel
26347 * @extends Roo.util.Observable
26348 * Abstract base class for grid SelectionModels. It provides the interface that should be
26349 * implemented by descendant classes. This class should not be directly instantiated.
26352 Roo.bootstrap.Table.AbstractSelectionModel = function(){
26353 this.locked = false;
26354 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
26358 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
26359 /** @ignore Called by the grid automatically. Do not call directly. */
26360 init : function(grid){
26366 * Locks the selections.
26369 this.locked = true;
26373 * Unlocks the selections.
26375 unlock : function(){
26376 this.locked = false;
26380 * Returns true if the selections are locked.
26381 * @return {Boolean}
26383 isLocked : function(){
26384 return this.locked;
26388 initEvents : function ()
26394 * @extends Roo.bootstrap.Table.AbstractSelectionModel
26395 * @class Roo.bootstrap.Table.RowSelectionModel
26396 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
26397 * It supports multiple selections and keyboard selection/navigation.
26399 * @param {Object} config
26402 Roo.bootstrap.Table.RowSelectionModel = function(config){
26403 Roo.apply(this, config);
26404 this.selections = new Roo.util.MixedCollection(false, function(o){
26409 this.lastActive = false;
26413 * @event selectionchange
26414 * Fires when the selection changes
26415 * @param {SelectionModel} this
26417 "selectionchange" : true,
26419 * @event afterselectionchange
26420 * Fires after the selection changes (eg. by key press or clicking)
26421 * @param {SelectionModel} this
26423 "afterselectionchange" : true,
26425 * @event beforerowselect
26426 * Fires when a row is selected being selected, return false to cancel.
26427 * @param {SelectionModel} this
26428 * @param {Number} rowIndex The selected index
26429 * @param {Boolean} keepExisting False if other selections will be cleared
26431 "beforerowselect" : true,
26434 * Fires when a row is selected.
26435 * @param {SelectionModel} this
26436 * @param {Number} rowIndex The selected index
26437 * @param {Roo.data.Record} r The record
26439 "rowselect" : true,
26441 * @event rowdeselect
26442 * Fires when a row is deselected.
26443 * @param {SelectionModel} this
26444 * @param {Number} rowIndex The selected index
26446 "rowdeselect" : true
26448 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
26449 this.locked = false;
26452 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
26454 * @cfg {Boolean} singleSelect
26455 * True to allow selection of only one row at a time (defaults to false)
26457 singleSelect : false,
26460 initEvents : function()
26463 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
26464 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
26465 //}else{ // allow click to work like normal
26466 // this.grid.on("rowclick", this.handleDragableRowClick, this);
26468 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
26469 this.grid.on("rowclick", this.handleMouseDown, this);
26471 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
26472 "up" : function(e){
26474 this.selectPrevious(e.shiftKey);
26475 }else if(this.last !== false && this.lastActive !== false){
26476 var last = this.last;
26477 this.selectRange(this.last, this.lastActive-1);
26478 this.grid.getView().focusRow(this.lastActive);
26479 if(last !== false){
26483 this.selectFirstRow();
26485 this.fireEvent("afterselectionchange", this);
26487 "down" : function(e){
26489 this.selectNext(e.shiftKey);
26490 }else if(this.last !== false && this.lastActive !== false){
26491 var last = this.last;
26492 this.selectRange(this.last, this.lastActive+1);
26493 this.grid.getView().focusRow(this.lastActive);
26494 if(last !== false){
26498 this.selectFirstRow();
26500 this.fireEvent("afterselectionchange", this);
26504 this.grid.store.on('load', function(){
26505 this.selections.clear();
26508 var view = this.grid.view;
26509 view.on("refresh", this.onRefresh, this);
26510 view.on("rowupdated", this.onRowUpdated, this);
26511 view.on("rowremoved", this.onRemove, this);
26516 onRefresh : function()
26518 var ds = this.grid.store, i, v = this.grid.view;
26519 var s = this.selections;
26520 s.each(function(r){
26521 if((i = ds.indexOfId(r.id)) != -1){
26530 onRemove : function(v, index, r){
26531 this.selections.remove(r);
26535 onRowUpdated : function(v, index, r){
26536 if(this.isSelected(r)){
26537 v.onRowSelect(index);
26543 * @param {Array} records The records to select
26544 * @param {Boolean} keepExisting (optional) True to keep existing selections
26546 selectRecords : function(records, keepExisting)
26549 this.clearSelections();
26551 var ds = this.grid.store;
26552 for(var i = 0, len = records.length; i < len; i++){
26553 this.selectRow(ds.indexOf(records[i]), true);
26558 * Gets the number of selected rows.
26561 getCount : function(){
26562 return this.selections.length;
26566 * Selects the first row in the grid.
26568 selectFirstRow : function(){
26573 * Select the last row.
26574 * @param {Boolean} keepExisting (optional) True to keep existing selections
26576 selectLastRow : function(keepExisting){
26577 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
26578 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
26582 * Selects the row immediately following the last selected row.
26583 * @param {Boolean} keepExisting (optional) True to keep existing selections
26585 selectNext : function(keepExisting)
26587 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
26588 this.selectRow(this.last+1, keepExisting);
26589 this.grid.getView().focusRow(this.last);
26594 * Selects the row that precedes the last selected row.
26595 * @param {Boolean} keepExisting (optional) True to keep existing selections
26597 selectPrevious : function(keepExisting){
26599 this.selectRow(this.last-1, keepExisting);
26600 this.grid.getView().focusRow(this.last);
26605 * Returns the selected records
26606 * @return {Array} Array of selected records
26608 getSelections : function(){
26609 return [].concat(this.selections.items);
26613 * Returns the first selected record.
26616 getSelected : function(){
26617 return this.selections.itemAt(0);
26622 * Clears all selections.
26624 clearSelections : function(fast)
26630 var ds = this.grid.store;
26631 var s = this.selections;
26632 s.each(function(r){
26633 this.deselectRow(ds.indexOfId(r.id));
26637 this.selections.clear();
26644 * Selects all rows.
26646 selectAll : function(){
26650 this.selections.clear();
26651 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
26652 this.selectRow(i, true);
26657 * Returns True if there is a selection.
26658 * @return {Boolean}
26660 hasSelection : function(){
26661 return this.selections.length > 0;
26665 * Returns True if the specified row is selected.
26666 * @param {Number/Record} record The record or index of the record to check
26667 * @return {Boolean}
26669 isSelected : function(index){
26670 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
26671 return (r && this.selections.key(r.id) ? true : false);
26675 * Returns True if the specified record id is selected.
26676 * @param {String} id The id of record to check
26677 * @return {Boolean}
26679 isIdSelected : function(id){
26680 return (this.selections.key(id) ? true : false);
26685 handleMouseDBClick : function(e, t){
26689 handleMouseDown : function(e, t)
26691 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
26692 if(this.isLocked() || rowIndex < 0 ){
26695 if(e.shiftKey && this.last !== false){
26696 var last = this.last;
26697 this.selectRange(last, rowIndex, e.ctrlKey);
26698 this.last = last; // reset the last
26702 var isSelected = this.isSelected(rowIndex);
26703 //Roo.log("select row:" + rowIndex);
26705 this.deselectRow(rowIndex);
26707 this.selectRow(rowIndex, true);
26711 if(e.button !== 0 && isSelected){
26712 alert('rowIndex 2: ' + rowIndex);
26713 view.focusRow(rowIndex);
26714 }else if(e.ctrlKey && isSelected){
26715 this.deselectRow(rowIndex);
26716 }else if(!isSelected){
26717 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
26718 view.focusRow(rowIndex);
26722 this.fireEvent("afterselectionchange", this);
26725 handleDragableRowClick : function(grid, rowIndex, e)
26727 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
26728 this.selectRow(rowIndex, false);
26729 grid.view.focusRow(rowIndex);
26730 this.fireEvent("afterselectionchange", this);
26735 * Selects multiple rows.
26736 * @param {Array} rows Array of the indexes of the row to select
26737 * @param {Boolean} keepExisting (optional) True to keep existing selections
26739 selectRows : function(rows, keepExisting){
26741 this.clearSelections();
26743 for(var i = 0, len = rows.length; i < len; i++){
26744 this.selectRow(rows[i], true);
26749 * Selects a range of rows. All rows in between startRow and endRow are also selected.
26750 * @param {Number} startRow The index of the first row in the range
26751 * @param {Number} endRow The index of the last row in the range
26752 * @param {Boolean} keepExisting (optional) True to retain existing selections
26754 selectRange : function(startRow, endRow, keepExisting){
26759 this.clearSelections();
26761 if(startRow <= endRow){
26762 for(var i = startRow; i <= endRow; i++){
26763 this.selectRow(i, true);
26766 for(var i = startRow; i >= endRow; i--){
26767 this.selectRow(i, true);
26773 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
26774 * @param {Number} startRow The index of the first row in the range
26775 * @param {Number} endRow The index of the last row in the range
26777 deselectRange : function(startRow, endRow, preventViewNotify){
26781 for(var i = startRow; i <= endRow; i++){
26782 this.deselectRow(i, preventViewNotify);
26788 * @param {Number} row The index of the row to select
26789 * @param {Boolean} keepExisting (optional) True to keep existing selections
26791 selectRow : function(index, keepExisting, preventViewNotify)
26793 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
26796 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
26797 if(!keepExisting || this.singleSelect){
26798 this.clearSelections();
26801 var r = this.grid.store.getAt(index);
26802 //console.log('selectRow - record id :' + r.id);
26804 this.selections.add(r);
26805 this.last = this.lastActive = index;
26806 if(!preventViewNotify){
26807 var proxy = new Roo.Element(
26808 this.grid.getRowDom(index)
26810 proxy.addClass('bg-info info');
26812 this.fireEvent("rowselect", this, index, r);
26813 this.fireEvent("selectionchange", this);
26819 * @param {Number} row The index of the row to deselect
26821 deselectRow : function(index, preventViewNotify)
26826 if(this.last == index){
26829 if(this.lastActive == index){
26830 this.lastActive = false;
26833 var r = this.grid.store.getAt(index);
26838 this.selections.remove(r);
26839 //.console.log('deselectRow - record id :' + r.id);
26840 if(!preventViewNotify){
26842 var proxy = new Roo.Element(
26843 this.grid.getRowDom(index)
26845 proxy.removeClass('bg-info info');
26847 this.fireEvent("rowdeselect", this, index);
26848 this.fireEvent("selectionchange", this);
26852 restoreLast : function(){
26854 this.last = this._last;
26859 acceptsNav : function(row, col, cm){
26860 return !cm.isHidden(col) && cm.isCellEditable(col, row);
26864 onEditorKey : function(field, e){
26865 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
26870 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
26872 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
26874 }else if(k == e.ENTER && !e.ctrlKey){
26878 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
26880 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
26882 }else if(k == e.ESC){
26886 g.startEditing(newCell[0], newCell[1]);
26892 * Ext JS Library 1.1.1
26893 * Copyright(c) 2006-2007, Ext JS, LLC.
26895 * Originally Released Under LGPL - original licence link has changed is not relivant.
26898 * <script type="text/javascript">
26902 * @class Roo.bootstrap.PagingToolbar
26903 * @extends Roo.bootstrap.NavSimplebar
26904 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26906 * Create a new PagingToolbar
26907 * @param {Object} config The config object
26908 * @param {Roo.data.Store} store
26910 Roo.bootstrap.PagingToolbar = function(config)
26912 // old args format still supported... - xtype is prefered..
26913 // created from xtype...
26915 this.ds = config.dataSource;
26917 if (config.store && !this.ds) {
26918 this.store= Roo.factory(config.store, Roo.data);
26919 this.ds = this.store;
26920 this.ds.xmodule = this.xmodule || false;
26923 this.toolbarItems = [];
26924 if (config.items) {
26925 this.toolbarItems = config.items;
26928 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26933 this.bind(this.ds);
26936 if (Roo.bootstrap.version == 4) {
26937 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26939 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26944 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26946 * @cfg {Roo.data.Store} dataSource
26947 * The underlying data store providing the paged data
26950 * @cfg {String/HTMLElement/Element} container
26951 * container The id or element that will contain the toolbar
26954 * @cfg {Boolean} displayInfo
26955 * True to display the displayMsg (defaults to false)
26958 * @cfg {Number} pageSize
26959 * The number of records to display per page (defaults to 20)
26963 * @cfg {String} displayMsg
26964 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26966 displayMsg : 'Displaying {0} - {1} of {2}',
26968 * @cfg {String} emptyMsg
26969 * The message to display when no records are found (defaults to "No data to display")
26971 emptyMsg : 'No data to display',
26973 * Customizable piece of the default paging text (defaults to "Page")
26976 beforePageText : "Page",
26978 * Customizable piece of the default paging text (defaults to "of %0")
26981 afterPageText : "of {0}",
26983 * Customizable piece of the default paging text (defaults to "First Page")
26986 firstText : "First Page",
26988 * Customizable piece of the default paging text (defaults to "Previous Page")
26991 prevText : "Previous Page",
26993 * Customizable piece of the default paging text (defaults to "Next Page")
26996 nextText : "Next Page",
26998 * Customizable piece of the default paging text (defaults to "Last Page")
27001 lastText : "Last Page",
27003 * Customizable piece of the default paging text (defaults to "Refresh")
27006 refreshText : "Refresh",
27010 onRender : function(ct, position)
27012 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
27013 this.navgroup.parentId = this.id;
27014 this.navgroup.onRender(this.el, null);
27015 // add the buttons to the navgroup
27017 if(this.displayInfo){
27018 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
27019 this.displayEl = this.el.select('.x-paging-info', true).first();
27020 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
27021 // this.displayEl = navel.el.select('span',true).first();
27027 Roo.each(_this.buttons, function(e){ // this might need to use render????
27028 Roo.factory(e).render(_this.el);
27032 Roo.each(_this.toolbarItems, function(e) {
27033 _this.navgroup.addItem(e);
27037 this.first = this.navgroup.addItem({
27038 tooltip: this.firstText,
27039 cls: "prev btn-outline-secondary",
27040 html : ' <i class="fa fa-step-backward"></i>',
27042 preventDefault: true,
27043 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
27046 this.prev = this.navgroup.addItem({
27047 tooltip: this.prevText,
27048 cls: "prev btn-outline-secondary",
27049 html : ' <i class="fa fa-backward"></i>',
27051 preventDefault: true,
27052 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
27054 //this.addSeparator();
27057 var field = this.navgroup.addItem( {
27059 cls : 'x-paging-position btn-outline-secondary',
27061 html : this.beforePageText +
27062 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
27063 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
27066 this.field = field.el.select('input', true).first();
27067 this.field.on("keydown", this.onPagingKeydown, this);
27068 this.field.on("focus", function(){this.dom.select();});
27071 this.afterTextEl = field.el.select('.x-paging-after',true).first();
27072 //this.field.setHeight(18);
27073 //this.addSeparator();
27074 this.next = this.navgroup.addItem({
27075 tooltip: this.nextText,
27076 cls: "next btn-outline-secondary",
27077 html : ' <i class="fa fa-forward"></i>',
27079 preventDefault: true,
27080 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
27082 this.last = this.navgroup.addItem({
27083 tooltip: this.lastText,
27084 html : ' <i class="fa fa-step-forward"></i>',
27085 cls: "next btn-outline-secondary",
27087 preventDefault: true,
27088 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
27090 //this.addSeparator();
27091 this.loading = this.navgroup.addItem({
27092 tooltip: this.refreshText,
27093 cls: "btn-outline-secondary",
27094 html : ' <i class="fa fa-refresh"></i>',
27095 preventDefault: true,
27096 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
27102 updateInfo : function(){
27103 if(this.displayEl){
27104 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
27105 var msg = count == 0 ?
27109 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27111 this.displayEl.update(msg);
27116 onLoad : function(ds, r, o)
27118 this.cursor = o.params.start ? o.params.start : 0;
27120 var d = this.getPageData(),
27125 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
27126 this.field.dom.value = ap;
27127 this.first.setDisabled(ap == 1);
27128 this.prev.setDisabled(ap == 1);
27129 this.next.setDisabled(ap == ps);
27130 this.last.setDisabled(ap == ps);
27131 this.loading.enable();
27136 getPageData : function(){
27137 var total = this.ds.getTotalCount();
27140 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27141 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27146 onLoadError : function(){
27147 this.loading.enable();
27151 onPagingKeydown : function(e){
27152 var k = e.getKey();
27153 var d = this.getPageData();
27155 var v = this.field.dom.value, pageNum;
27156 if(!v || isNaN(pageNum = parseInt(v, 10))){
27157 this.field.dom.value = d.activePage;
27160 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27161 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27164 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))
27166 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27167 this.field.dom.value = pageNum;
27168 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27171 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27173 var v = this.field.dom.value, pageNum;
27174 var increment = (e.shiftKey) ? 10 : 1;
27175 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
27178 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27179 this.field.dom.value = d.activePage;
27182 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27184 this.field.dom.value = parseInt(v, 10) + increment;
27185 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27186 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27193 beforeLoad : function(){
27195 this.loading.disable();
27200 onClick : function(which){
27209 ds.load({params:{start: 0, limit: this.pageSize}});
27212 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27215 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27218 var total = ds.getTotalCount();
27219 var extra = total % this.pageSize;
27220 var lastStart = extra ? (total - extra) : total-this.pageSize;
27221 ds.load({params:{start: lastStart, limit: this.pageSize}});
27224 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27230 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27231 * @param {Roo.data.Store} store The data store to unbind
27233 unbind : function(ds){
27234 ds.un("beforeload", this.beforeLoad, this);
27235 ds.un("load", this.onLoad, this);
27236 ds.un("loadexception", this.onLoadError, this);
27237 ds.un("remove", this.updateInfo, this);
27238 ds.un("add", this.updateInfo, this);
27239 this.ds = undefined;
27243 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27244 * @param {Roo.data.Store} store The data store to bind
27246 bind : function(ds){
27247 ds.on("beforeload", this.beforeLoad, this);
27248 ds.on("load", this.onLoad, this);
27249 ds.on("loadexception", this.onLoadError, this);
27250 ds.on("remove", this.updateInfo, this);
27251 ds.on("add", this.updateInfo, this);
27262 * @class Roo.bootstrap.MessageBar
27263 * @extends Roo.bootstrap.Component
27264 * Bootstrap MessageBar class
27265 * @cfg {String} html contents of the MessageBar
27266 * @cfg {String} weight (info | success | warning | danger) default info
27267 * @cfg {String} beforeClass insert the bar before the given class
27268 * @cfg {Boolean} closable (true | false) default false
27269 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
27272 * Create a new Element
27273 * @param {Object} config The config object
27276 Roo.bootstrap.MessageBar = function(config){
27277 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
27280 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
27286 beforeClass: 'bootstrap-sticky-wrap',
27288 getAutoCreate : function(){
27292 cls: 'alert alert-dismissable alert-' + this.weight,
27297 html: this.html || ''
27303 cfg.cls += ' alert-messages-fixed';
27317 onRender : function(ct, position)
27319 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
27322 var cfg = Roo.apply({}, this.getAutoCreate());
27326 cfg.cls += ' ' + this.cls;
27329 cfg.style = this.style;
27331 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
27333 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27336 this.el.select('>button.close').on('click', this.hide, this);
27342 if (!this.rendered) {
27348 this.fireEvent('show', this);
27354 if (!this.rendered) {
27360 this.fireEvent('hide', this);
27363 update : function()
27365 // var e = this.el.dom.firstChild;
27367 // if(this.closable){
27368 // e = e.nextSibling;
27371 // e.data = this.html || '';
27373 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
27389 * @class Roo.bootstrap.Graph
27390 * @extends Roo.bootstrap.Component
27391 * Bootstrap Graph class
27395 @cfg {String} graphtype bar | vbar | pie
27396 @cfg {number} g_x coodinator | centre x (pie)
27397 @cfg {number} g_y coodinator | centre y (pie)
27398 @cfg {number} g_r radius (pie)
27399 @cfg {number} g_height height of the chart (respected by all elements in the set)
27400 @cfg {number} g_width width of the chart (respected by all elements in the set)
27401 @cfg {Object} title The title of the chart
27404 -opts (object) options for the chart
27406 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
27407 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
27409 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.
27410 o stacked (boolean) whether or not to tread values as in a stacked bar chart
27412 o stretch (boolean)
27414 -opts (object) options for the pie
27417 o startAngle (number)
27418 o endAngle (number)
27422 * Create a new Input
27423 * @param {Object} config The config object
27426 Roo.bootstrap.Graph = function(config){
27427 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
27433 * The img click event for the img.
27434 * @param {Roo.EventObject} e
27440 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
27451 //g_colors: this.colors,
27458 getAutoCreate : function(){
27469 onRender : function(ct,position){
27472 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
27474 if (typeof(Raphael) == 'undefined') {
27475 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
27479 this.raphael = Raphael(this.el.dom);
27481 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27482 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27483 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27484 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
27486 r.text(160, 10, "Single Series Chart").attr(txtattr);
27487 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
27488 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
27489 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
27491 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
27492 r.barchart(330, 10, 300, 220, data1);
27493 r.barchart(10, 250, 300, 220, data2, {stacked: true});
27494 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
27497 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27498 // r.barchart(30, 30, 560, 250, xdata, {
27499 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
27500 // axis : "0 0 1 1",
27501 // axisxlabels : xdata
27502 // //yvalues : cols,
27505 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27507 // this.load(null,xdata,{
27508 // axis : "0 0 1 1",
27509 // axisxlabels : xdata
27514 load : function(graphtype,xdata,opts)
27516 this.raphael.clear();
27518 graphtype = this.graphtype;
27523 var r = this.raphael,
27524 fin = function () {
27525 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
27527 fout = function () {
27528 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
27530 pfin = function() {
27531 this.sector.stop();
27532 this.sector.scale(1.1, 1.1, this.cx, this.cy);
27535 this.label[0].stop();
27536 this.label[0].attr({ r: 7.5 });
27537 this.label[1].attr({ "font-weight": 800 });
27540 pfout = function() {
27541 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
27544 this.label[0].animate({ r: 5 }, 500, "bounce");
27545 this.label[1].attr({ "font-weight": 400 });
27551 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27554 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27557 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
27558 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
27560 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
27567 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
27572 setTitle: function(o)
27577 initEvents: function() {
27580 this.el.on('click', this.onClick, this);
27584 onClick : function(e)
27586 Roo.log('img onclick');
27587 this.fireEvent('click', this, e);
27599 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27602 * @class Roo.bootstrap.dash.NumberBox
27603 * @extends Roo.bootstrap.Component
27604 * Bootstrap NumberBox class
27605 * @cfg {String} headline Box headline
27606 * @cfg {String} content Box content
27607 * @cfg {String} icon Box icon
27608 * @cfg {String} footer Footer text
27609 * @cfg {String} fhref Footer href
27612 * Create a new NumberBox
27613 * @param {Object} config The config object
27617 Roo.bootstrap.dash.NumberBox = function(config){
27618 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
27622 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
27631 getAutoCreate : function(){
27635 cls : 'small-box ',
27643 cls : 'roo-headline',
27644 html : this.headline
27648 cls : 'roo-content',
27649 html : this.content
27663 cls : 'ion ' + this.icon
27672 cls : 'small-box-footer',
27673 href : this.fhref || '#',
27677 cfg.cn.push(footer);
27684 onRender : function(ct,position){
27685 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
27692 setHeadline: function (value)
27694 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
27697 setFooter: function (value, href)
27699 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
27702 this.el.select('a.small-box-footer',true).first().attr('href', href);
27707 setContent: function (value)
27709 this.el.select('.roo-content',true).first().dom.innerHTML = value;
27712 initEvents: function()
27726 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27729 * @class Roo.bootstrap.dash.TabBox
27730 * @extends Roo.bootstrap.Component
27731 * Bootstrap TabBox class
27732 * @cfg {String} title Title of the TabBox
27733 * @cfg {String} icon Icon of the TabBox
27734 * @cfg {Boolean} showtabs (true|false) show the tabs default true
27735 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
27738 * Create a new TabBox
27739 * @param {Object} config The config object
27743 Roo.bootstrap.dash.TabBox = function(config){
27744 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
27749 * When a pane is added
27750 * @param {Roo.bootstrap.dash.TabPane} pane
27754 * @event activatepane
27755 * When a pane is activated
27756 * @param {Roo.bootstrap.dash.TabPane} pane
27758 "activatepane" : true
27766 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
27771 tabScrollable : false,
27773 getChildContainer : function()
27775 return this.el.select('.tab-content', true).first();
27778 getAutoCreate : function(){
27782 cls: 'pull-left header',
27790 cls: 'fa ' + this.icon
27796 cls: 'nav nav-tabs pull-right',
27802 if(this.tabScrollable){
27809 cls: 'nav nav-tabs pull-right',
27820 cls: 'nav-tabs-custom',
27825 cls: 'tab-content no-padding',
27833 initEvents : function()
27835 //Roo.log('add add pane handler');
27836 this.on('addpane', this.onAddPane, this);
27839 * Updates the box title
27840 * @param {String} html to set the title to.
27842 setTitle : function(value)
27844 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
27846 onAddPane : function(pane)
27848 this.panes.push(pane);
27849 //Roo.log('addpane');
27851 // tabs are rendere left to right..
27852 if(!this.showtabs){
27856 var ctr = this.el.select('.nav-tabs', true).first();
27859 var existing = ctr.select('.nav-tab',true);
27860 var qty = existing.getCount();;
27863 var tab = ctr.createChild({
27865 cls : 'nav-tab' + (qty ? '' : ' active'),
27873 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
27876 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
27878 pane.el.addClass('active');
27883 onTabClick : function(ev,un,ob,pane)
27885 //Roo.log('tab - prev default');
27886 ev.preventDefault();
27889 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
27890 pane.tab.addClass('active');
27891 //Roo.log(pane.title);
27892 this.getChildContainer().select('.tab-pane',true).removeClass('active');
27893 // technically we should have a deactivate event.. but maybe add later.
27894 // and it should not de-activate the selected tab...
27895 this.fireEvent('activatepane', pane);
27896 pane.el.addClass('active');
27897 pane.fireEvent('activate');
27902 getActivePane : function()
27905 Roo.each(this.panes, function(p) {
27906 if(p.el.hasClass('active')){
27927 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27929 * @class Roo.bootstrap.TabPane
27930 * @extends Roo.bootstrap.Component
27931 * Bootstrap TabPane class
27932 * @cfg {Boolean} active (false | true) Default false
27933 * @cfg {String} title title of panel
27937 * Create a new TabPane
27938 * @param {Object} config The config object
27941 Roo.bootstrap.dash.TabPane = function(config){
27942 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27948 * When a pane is activated
27949 * @param {Roo.bootstrap.dash.TabPane} pane
27956 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27961 // the tabBox that this is attached to.
27964 getAutoCreate : function()
27972 cfg.cls += ' active';
27977 initEvents : function()
27979 //Roo.log('trigger add pane handler');
27980 this.parent().fireEvent('addpane', this)
27984 * Updates the tab title
27985 * @param {String} html to set the title to.
27987 setTitle: function(str)
27993 this.tab.select('a', true).first().dom.innerHTML = str;
28010 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28013 * @class Roo.bootstrap.menu.Menu
28014 * @extends Roo.bootstrap.Component
28015 * Bootstrap Menu class - container for Menu
28016 * @cfg {String} html Text of the menu
28017 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
28018 * @cfg {String} icon Font awesome icon
28019 * @cfg {String} pos Menu align to (top | bottom) default bottom
28023 * Create a new Menu
28024 * @param {Object} config The config object
28028 Roo.bootstrap.menu.Menu = function(config){
28029 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
28033 * @event beforeshow
28034 * Fires before this menu is displayed
28035 * @param {Roo.bootstrap.menu.Menu} this
28039 * @event beforehide
28040 * Fires before this menu is hidden
28041 * @param {Roo.bootstrap.menu.Menu} this
28046 * Fires after this menu is displayed
28047 * @param {Roo.bootstrap.menu.Menu} this
28052 * Fires after this menu is hidden
28053 * @param {Roo.bootstrap.menu.Menu} this
28058 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
28059 * @param {Roo.bootstrap.menu.Menu} this
28060 * @param {Roo.EventObject} e
28067 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
28071 weight : 'default',
28076 getChildContainer : function() {
28077 if(this.isSubMenu){
28081 return this.el.select('ul.dropdown-menu', true).first();
28084 getAutoCreate : function()
28089 cls : 'roo-menu-text',
28097 cls : 'fa ' + this.icon
28108 cls : 'dropdown-button btn btn-' + this.weight,
28113 cls : 'dropdown-toggle btn btn-' + this.weight,
28123 cls : 'dropdown-menu'
28129 if(this.pos == 'top'){
28130 cfg.cls += ' dropup';
28133 if(this.isSubMenu){
28136 cls : 'dropdown-menu'
28143 onRender : function(ct, position)
28145 this.isSubMenu = ct.hasClass('dropdown-submenu');
28147 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
28150 initEvents : function()
28152 if(this.isSubMenu){
28156 this.hidden = true;
28158 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
28159 this.triggerEl.on('click', this.onTriggerPress, this);
28161 this.buttonEl = this.el.select('button.dropdown-button', true).first();
28162 this.buttonEl.on('click', this.onClick, this);
28168 if(this.isSubMenu){
28172 return this.el.select('ul.dropdown-menu', true).first();
28175 onClick : function(e)
28177 this.fireEvent("click", this, e);
28180 onTriggerPress : function(e)
28182 if (this.isVisible()) {
28189 isVisible : function(){
28190 return !this.hidden;
28195 this.fireEvent("beforeshow", this);
28197 this.hidden = false;
28198 this.el.addClass('open');
28200 Roo.get(document).on("mouseup", this.onMouseUp, this);
28202 this.fireEvent("show", this);
28209 this.fireEvent("beforehide", this);
28211 this.hidden = true;
28212 this.el.removeClass('open');
28214 Roo.get(document).un("mouseup", this.onMouseUp);
28216 this.fireEvent("hide", this);
28219 onMouseUp : function()
28233 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28236 * @class Roo.bootstrap.menu.Item
28237 * @extends Roo.bootstrap.Component
28238 * Bootstrap MenuItem class
28239 * @cfg {Boolean} submenu (true | false) default false
28240 * @cfg {String} html text of the item
28241 * @cfg {String} href the link
28242 * @cfg {Boolean} disable (true | false) default false
28243 * @cfg {Boolean} preventDefault (true | false) default true
28244 * @cfg {String} icon Font awesome icon
28245 * @cfg {String} pos Submenu align to (left | right) default right
28249 * Create a new Item
28250 * @param {Object} config The config object
28254 Roo.bootstrap.menu.Item = function(config){
28255 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
28259 * Fires when the mouse is hovering over this menu
28260 * @param {Roo.bootstrap.menu.Item} this
28261 * @param {Roo.EventObject} e
28266 * Fires when the mouse exits this menu
28267 * @param {Roo.bootstrap.menu.Item} this
28268 * @param {Roo.EventObject} e
28274 * The raw click event for the entire grid.
28275 * @param {Roo.EventObject} e
28281 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
28286 preventDefault: true,
28291 getAutoCreate : function()
28296 cls : 'roo-menu-item-text',
28304 cls : 'fa ' + this.icon
28313 href : this.href || '#',
28320 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
28324 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
28326 if(this.pos == 'left'){
28327 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
28334 initEvents : function()
28336 this.el.on('mouseover', this.onMouseOver, this);
28337 this.el.on('mouseout', this.onMouseOut, this);
28339 this.el.select('a', true).first().on('click', this.onClick, this);
28343 onClick : function(e)
28345 if(this.preventDefault){
28346 e.preventDefault();
28349 this.fireEvent("click", this, e);
28352 onMouseOver : function(e)
28354 if(this.submenu && this.pos == 'left'){
28355 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
28358 this.fireEvent("mouseover", this, e);
28361 onMouseOut : function(e)
28363 this.fireEvent("mouseout", this, e);
28375 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28378 * @class Roo.bootstrap.menu.Separator
28379 * @extends Roo.bootstrap.Component
28380 * Bootstrap Separator class
28383 * Create a new Separator
28384 * @param {Object} config The config object
28388 Roo.bootstrap.menu.Separator = function(config){
28389 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
28392 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
28394 getAutoCreate : function(){
28415 * @class Roo.bootstrap.Tooltip
28416 * Bootstrap Tooltip class
28417 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
28418 * to determine which dom element triggers the tooltip.
28420 * It needs to add support for additional attributes like tooltip-position
28423 * Create a new Toolti
28424 * @param {Object} config The config object
28427 Roo.bootstrap.Tooltip = function(config){
28428 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
28430 this.alignment = Roo.bootstrap.Tooltip.alignment;
28432 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
28433 this.alignment = config.alignment;
28438 Roo.apply(Roo.bootstrap.Tooltip, {
28440 * @function init initialize tooltip monitoring.
28444 currentTip : false,
28445 currentRegion : false,
28451 Roo.get(document).on('mouseover', this.enter ,this);
28452 Roo.get(document).on('mouseout', this.leave, this);
28455 this.currentTip = new Roo.bootstrap.Tooltip();
28458 enter : function(ev)
28460 var dom = ev.getTarget();
28462 //Roo.log(['enter',dom]);
28463 var el = Roo.fly(dom);
28464 if (this.currentEl) {
28466 //Roo.log(this.currentEl);
28467 //Roo.log(this.currentEl.contains(dom));
28468 if (this.currentEl == el) {
28471 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
28477 if (this.currentTip.el) {
28478 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
28482 if(!el || el.dom == document){
28488 // you can not look for children, as if el is the body.. then everythign is the child..
28489 if (!el.attr('tooltip')) { //
28490 if (!el.select("[tooltip]").elements.length) {
28493 // is the mouse over this child...?
28494 bindEl = el.select("[tooltip]").first();
28495 var xy = ev.getXY();
28496 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
28497 //Roo.log("not in region.");
28500 //Roo.log("child element over..");
28503 this.currentEl = bindEl;
28504 this.currentTip.bind(bindEl);
28505 this.currentRegion = Roo.lib.Region.getRegion(dom);
28506 this.currentTip.enter();
28509 leave : function(ev)
28511 var dom = ev.getTarget();
28512 //Roo.log(['leave',dom]);
28513 if (!this.currentEl) {
28518 if (dom != this.currentEl.dom) {
28521 var xy = ev.getXY();
28522 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
28525 // only activate leave if mouse cursor is outside... bounding box..
28530 if (this.currentTip) {
28531 this.currentTip.leave();
28533 //Roo.log('clear currentEl');
28534 this.currentEl = false;
28539 'left' : ['r-l', [-2,0], 'right'],
28540 'right' : ['l-r', [2,0], 'left'],
28541 'bottom' : ['t-b', [0,2], 'top'],
28542 'top' : [ 'b-t', [0,-2], 'bottom']
28548 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
28553 delay : null, // can be { show : 300 , hide: 500}
28557 hoverState : null, //???
28559 placement : 'bottom',
28563 getAutoCreate : function(){
28570 cls : 'tooltip-arrow arrow'
28573 cls : 'tooltip-inner'
28580 bind : function(el)
28585 initEvents : function()
28587 this.arrowEl = this.el.select('.arrow', true).first();
28588 this.innerEl = this.el.select('.tooltip-inner', true).first();
28591 enter : function () {
28593 if (this.timeout != null) {
28594 clearTimeout(this.timeout);
28597 this.hoverState = 'in';
28598 //Roo.log("enter - show");
28599 if (!this.delay || !this.delay.show) {
28604 this.timeout = setTimeout(function () {
28605 if (_t.hoverState == 'in') {
28608 }, this.delay.show);
28612 clearTimeout(this.timeout);
28614 this.hoverState = 'out';
28615 if (!this.delay || !this.delay.hide) {
28621 this.timeout = setTimeout(function () {
28622 //Roo.log("leave - timeout");
28624 if (_t.hoverState == 'out') {
28626 Roo.bootstrap.Tooltip.currentEl = false;
28631 show : function (msg)
28634 this.render(document.body);
28637 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
28639 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
28641 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
28643 this.el.removeClass(['fade','top','bottom', 'left', 'right','in',
28644 'bs-tooltip-top','bs-tooltip-bottom', 'bs-tooltip-left', 'bs-tooltip-right']);
28646 var placement = typeof this.placement == 'function' ?
28647 this.placement.call(this, this.el, on_el) :
28650 var autoToken = /\s?auto?\s?/i;
28651 var autoPlace = autoToken.test(placement);
28653 placement = placement.replace(autoToken, '') || 'top';
28657 //this.el.setXY([0,0]);
28659 //this.el.dom.style.display='block';
28661 //this.el.appendTo(on_el);
28663 var p = this.getPosition();
28664 var box = this.el.getBox();
28670 var align = this.alignment[placement];
28672 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
28674 if(placement == 'top' || placement == 'bottom'){
28676 placement = 'right';
28679 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
28680 placement = 'left';
28683 var scroll = Roo.select('body', true).first().getScroll();
28685 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
28689 align = this.alignment[placement];
28691 this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
28695 this.el.alignTo(this.bindEl, align[0],align[1]);
28696 //var arrow = this.el.select('.arrow',true).first();
28697 //arrow.set(align[2],
28699 this.el.addClass(placement);
28700 this.el.addClass("bs-tooltip-"+ placement);
28702 this.el.addClass('in fade show');
28704 this.hoverState = null;
28706 if (this.el.hasClass('fade')) {
28721 //this.el.setXY([0,0]);
28722 this.el.removeClass(['show', 'in']);
28738 * @class Roo.bootstrap.LocationPicker
28739 * @extends Roo.bootstrap.Component
28740 * Bootstrap LocationPicker class
28741 * @cfg {Number} latitude Position when init default 0
28742 * @cfg {Number} longitude Position when init default 0
28743 * @cfg {Number} zoom default 15
28744 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
28745 * @cfg {Boolean} mapTypeControl default false
28746 * @cfg {Boolean} disableDoubleClickZoom default false
28747 * @cfg {Boolean} scrollwheel default true
28748 * @cfg {Boolean} streetViewControl default false
28749 * @cfg {Number} radius default 0
28750 * @cfg {String} locationName
28751 * @cfg {Boolean} draggable default true
28752 * @cfg {Boolean} enableAutocomplete default false
28753 * @cfg {Boolean} enableReverseGeocode default true
28754 * @cfg {String} markerTitle
28757 * Create a new LocationPicker
28758 * @param {Object} config The config object
28762 Roo.bootstrap.LocationPicker = function(config){
28764 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
28769 * Fires when the picker initialized.
28770 * @param {Roo.bootstrap.LocationPicker} this
28771 * @param {Google Location} location
28775 * @event positionchanged
28776 * Fires when the picker position changed.
28777 * @param {Roo.bootstrap.LocationPicker} this
28778 * @param {Google Location} location
28780 positionchanged : true,
28783 * Fires when the map resize.
28784 * @param {Roo.bootstrap.LocationPicker} this
28789 * Fires when the map show.
28790 * @param {Roo.bootstrap.LocationPicker} this
28795 * Fires when the map hide.
28796 * @param {Roo.bootstrap.LocationPicker} this
28801 * Fires when click the map.
28802 * @param {Roo.bootstrap.LocationPicker} this
28803 * @param {Map event} e
28807 * @event mapRightClick
28808 * Fires when right click the map.
28809 * @param {Roo.bootstrap.LocationPicker} this
28810 * @param {Map event} e
28812 mapRightClick : true,
28814 * @event markerClick
28815 * Fires when click the marker.
28816 * @param {Roo.bootstrap.LocationPicker} this
28817 * @param {Map event} e
28819 markerClick : true,
28821 * @event markerRightClick
28822 * Fires when right click the marker.
28823 * @param {Roo.bootstrap.LocationPicker} this
28824 * @param {Map event} e
28826 markerRightClick : true,
28828 * @event OverlayViewDraw
28829 * Fires when OverlayView Draw
28830 * @param {Roo.bootstrap.LocationPicker} this
28832 OverlayViewDraw : true,
28834 * @event OverlayViewOnAdd
28835 * Fires when OverlayView Draw
28836 * @param {Roo.bootstrap.LocationPicker} this
28838 OverlayViewOnAdd : true,
28840 * @event OverlayViewOnRemove
28841 * Fires when OverlayView Draw
28842 * @param {Roo.bootstrap.LocationPicker} this
28844 OverlayViewOnRemove : true,
28846 * @event OverlayViewShow
28847 * Fires when OverlayView Draw
28848 * @param {Roo.bootstrap.LocationPicker} this
28849 * @param {Pixel} cpx
28851 OverlayViewShow : true,
28853 * @event OverlayViewHide
28854 * Fires when OverlayView Draw
28855 * @param {Roo.bootstrap.LocationPicker} this
28857 OverlayViewHide : true,
28859 * @event loadexception
28860 * Fires when load google lib failed.
28861 * @param {Roo.bootstrap.LocationPicker} this
28863 loadexception : true
28868 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
28870 gMapContext: false,
28876 mapTypeControl: false,
28877 disableDoubleClickZoom: false,
28879 streetViewControl: false,
28883 enableAutocomplete: false,
28884 enableReverseGeocode: true,
28887 getAutoCreate: function()
28892 cls: 'roo-location-picker'
28898 initEvents: function(ct, position)
28900 if(!this.el.getWidth() || this.isApplied()){
28904 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28909 initial: function()
28911 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
28912 this.fireEvent('loadexception', this);
28916 if(!this.mapTypeId){
28917 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28920 this.gMapContext = this.GMapContext();
28922 this.initOverlayView();
28924 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28928 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28929 _this.setPosition(_this.gMapContext.marker.position);
28932 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28933 _this.fireEvent('mapClick', this, event);
28937 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28938 _this.fireEvent('mapRightClick', this, event);
28942 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28943 _this.fireEvent('markerClick', this, event);
28947 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28948 _this.fireEvent('markerRightClick', this, event);
28952 this.setPosition(this.gMapContext.location);
28954 this.fireEvent('initial', this, this.gMapContext.location);
28957 initOverlayView: function()
28961 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28965 _this.fireEvent('OverlayViewDraw', _this);
28970 _this.fireEvent('OverlayViewOnAdd', _this);
28973 onRemove: function()
28975 _this.fireEvent('OverlayViewOnRemove', _this);
28978 show: function(cpx)
28980 _this.fireEvent('OverlayViewShow', _this, cpx);
28985 _this.fireEvent('OverlayViewHide', _this);
28991 fromLatLngToContainerPixel: function(event)
28993 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28996 isApplied: function()
28998 return this.getGmapContext() == false ? false : true;
29001 getGmapContext: function()
29003 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
29006 GMapContext: function()
29008 var position = new google.maps.LatLng(this.latitude, this.longitude);
29010 var _map = new google.maps.Map(this.el.dom, {
29013 mapTypeId: this.mapTypeId,
29014 mapTypeControl: this.mapTypeControl,
29015 disableDoubleClickZoom: this.disableDoubleClickZoom,
29016 scrollwheel: this.scrollwheel,
29017 streetViewControl: this.streetViewControl,
29018 locationName: this.locationName,
29019 draggable: this.draggable,
29020 enableAutocomplete: this.enableAutocomplete,
29021 enableReverseGeocode: this.enableReverseGeocode
29024 var _marker = new google.maps.Marker({
29025 position: position,
29027 title: this.markerTitle,
29028 draggable: this.draggable
29035 location: position,
29036 radius: this.radius,
29037 locationName: this.locationName,
29038 addressComponents: {
29039 formatted_address: null,
29040 addressLine1: null,
29041 addressLine2: null,
29043 streetNumber: null,
29047 stateOrProvince: null
29050 domContainer: this.el.dom,
29051 geodecoder: new google.maps.Geocoder()
29055 drawCircle: function(center, radius, options)
29057 if (this.gMapContext.circle != null) {
29058 this.gMapContext.circle.setMap(null);
29062 options = Roo.apply({}, options, {
29063 strokeColor: "#0000FF",
29064 strokeOpacity: .35,
29066 fillColor: "#0000FF",
29070 options.map = this.gMapContext.map;
29071 options.radius = radius;
29072 options.center = center;
29073 this.gMapContext.circle = new google.maps.Circle(options);
29074 return this.gMapContext.circle;
29080 setPosition: function(location)
29082 this.gMapContext.location = location;
29083 this.gMapContext.marker.setPosition(location);
29084 this.gMapContext.map.panTo(location);
29085 this.drawCircle(location, this.gMapContext.radius, {});
29089 if (this.gMapContext.settings.enableReverseGeocode) {
29090 this.gMapContext.geodecoder.geocode({
29091 latLng: this.gMapContext.location
29092 }, function(results, status) {
29094 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
29095 _this.gMapContext.locationName = results[0].formatted_address;
29096 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
29098 _this.fireEvent('positionchanged', this, location);
29105 this.fireEvent('positionchanged', this, location);
29110 google.maps.event.trigger(this.gMapContext.map, "resize");
29112 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
29114 this.fireEvent('resize', this);
29117 setPositionByLatLng: function(latitude, longitude)
29119 this.setPosition(new google.maps.LatLng(latitude, longitude));
29122 getCurrentPosition: function()
29125 latitude: this.gMapContext.location.lat(),
29126 longitude: this.gMapContext.location.lng()
29130 getAddressName: function()
29132 return this.gMapContext.locationName;
29135 getAddressComponents: function()
29137 return this.gMapContext.addressComponents;
29140 address_component_from_google_geocode: function(address_components)
29144 for (var i = 0; i < address_components.length; i++) {
29145 var component = address_components[i];
29146 if (component.types.indexOf("postal_code") >= 0) {
29147 result.postalCode = component.short_name;
29148 } else if (component.types.indexOf("street_number") >= 0) {
29149 result.streetNumber = component.short_name;
29150 } else if (component.types.indexOf("route") >= 0) {
29151 result.streetName = component.short_name;
29152 } else if (component.types.indexOf("neighborhood") >= 0) {
29153 result.city = component.short_name;
29154 } else if (component.types.indexOf("locality") >= 0) {
29155 result.city = component.short_name;
29156 } else if (component.types.indexOf("sublocality") >= 0) {
29157 result.district = component.short_name;
29158 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
29159 result.stateOrProvince = component.short_name;
29160 } else if (component.types.indexOf("country") >= 0) {
29161 result.country = component.short_name;
29165 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
29166 result.addressLine2 = "";
29170 setZoomLevel: function(zoom)
29172 this.gMapContext.map.setZoom(zoom);
29185 this.fireEvent('show', this);
29196 this.fireEvent('hide', this);
29201 Roo.apply(Roo.bootstrap.LocationPicker, {
29203 OverlayView : function(map, options)
29205 options = options || {};
29212 * @class Roo.bootstrap.Alert
29213 * @extends Roo.bootstrap.Component
29214 * Bootstrap Alert class - shows an alert area box
29216 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
29217 Enter a valid email address
29220 * @cfg {String} title The title of alert
29221 * @cfg {String} html The content of alert
29222 * @cfg {String} weight ( success | info | warning | danger )
29223 * @cfg {String} faicon font-awesomeicon
29226 * Create a new alert
29227 * @param {Object} config The config object
29231 Roo.bootstrap.Alert = function(config){
29232 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
29236 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
29243 getAutoCreate : function()
29252 cls : 'roo-alert-icon'
29257 cls : 'roo-alert-title',
29262 cls : 'roo-alert-text',
29269 cfg.cn[0].cls += ' fa ' + this.faicon;
29273 cfg.cls += ' alert-' + this.weight;
29279 initEvents: function()
29281 this.el.setVisibilityMode(Roo.Element.DISPLAY);
29284 setTitle : function(str)
29286 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
29289 setText : function(str)
29291 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
29294 setWeight : function(weight)
29297 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
29300 this.weight = weight;
29302 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
29305 setIcon : function(icon)
29308 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
29311 this.faicon = icon;
29313 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
29334 * @class Roo.bootstrap.UploadCropbox
29335 * @extends Roo.bootstrap.Component
29336 * Bootstrap UploadCropbox class
29337 * @cfg {String} emptyText show when image has been loaded
29338 * @cfg {String} rotateNotify show when image too small to rotate
29339 * @cfg {Number} errorTimeout default 3000
29340 * @cfg {Number} minWidth default 300
29341 * @cfg {Number} minHeight default 300
29342 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
29343 * @cfg {Boolean} isDocument (true|false) default false
29344 * @cfg {String} url action url
29345 * @cfg {String} paramName default 'imageUpload'
29346 * @cfg {String} method default POST
29347 * @cfg {Boolean} loadMask (true|false) default true
29348 * @cfg {Boolean} loadingText default 'Loading...'
29351 * Create a new UploadCropbox
29352 * @param {Object} config The config object
29355 Roo.bootstrap.UploadCropbox = function(config){
29356 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
29360 * @event beforeselectfile
29361 * Fire before select file
29362 * @param {Roo.bootstrap.UploadCropbox} this
29364 "beforeselectfile" : true,
29367 * Fire after initEvent
29368 * @param {Roo.bootstrap.UploadCropbox} this
29373 * Fire after initEvent
29374 * @param {Roo.bootstrap.UploadCropbox} this
29375 * @param {String} data
29380 * Fire when preparing the file data
29381 * @param {Roo.bootstrap.UploadCropbox} this
29382 * @param {Object} file
29387 * Fire when get exception
29388 * @param {Roo.bootstrap.UploadCropbox} this
29389 * @param {XMLHttpRequest} xhr
29391 "exception" : true,
29393 * @event beforeloadcanvas
29394 * Fire before load the canvas
29395 * @param {Roo.bootstrap.UploadCropbox} this
29396 * @param {String} src
29398 "beforeloadcanvas" : true,
29401 * Fire when trash image
29402 * @param {Roo.bootstrap.UploadCropbox} this
29407 * Fire when download the image
29408 * @param {Roo.bootstrap.UploadCropbox} this
29412 * @event footerbuttonclick
29413 * Fire when footerbuttonclick
29414 * @param {Roo.bootstrap.UploadCropbox} this
29415 * @param {String} type
29417 "footerbuttonclick" : true,
29421 * @param {Roo.bootstrap.UploadCropbox} this
29426 * Fire when rotate the image
29427 * @param {Roo.bootstrap.UploadCropbox} this
29428 * @param {String} pos
29433 * Fire when inspect the file
29434 * @param {Roo.bootstrap.UploadCropbox} this
29435 * @param {Object} file
29440 * Fire when xhr upload the file
29441 * @param {Roo.bootstrap.UploadCropbox} this
29442 * @param {Object} data
29447 * Fire when arrange the file data
29448 * @param {Roo.bootstrap.UploadCropbox} this
29449 * @param {Object} formData
29454 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
29457 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
29459 emptyText : 'Click to upload image',
29460 rotateNotify : 'Image is too small to rotate',
29461 errorTimeout : 3000,
29475 cropType : 'image/jpeg',
29477 canvasLoaded : false,
29478 isDocument : false,
29480 paramName : 'imageUpload',
29482 loadingText : 'Loading...',
29485 getAutoCreate : function()
29489 cls : 'roo-upload-cropbox',
29493 cls : 'roo-upload-cropbox-selector',
29498 cls : 'roo-upload-cropbox-body',
29499 style : 'cursor:pointer',
29503 cls : 'roo-upload-cropbox-preview'
29507 cls : 'roo-upload-cropbox-thumb'
29511 cls : 'roo-upload-cropbox-empty-notify',
29512 html : this.emptyText
29516 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
29517 html : this.rotateNotify
29523 cls : 'roo-upload-cropbox-footer',
29526 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
29536 onRender : function(ct, position)
29538 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
29540 if (this.buttons.length) {
29542 Roo.each(this.buttons, function(bb) {
29544 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
29546 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
29552 this.maskEl = this.el;
29556 initEvents : function()
29558 this.urlAPI = (window.createObjectURL && window) ||
29559 (window.URL && URL.revokeObjectURL && URL) ||
29560 (window.webkitURL && webkitURL);
29562 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
29563 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29565 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
29566 this.selectorEl.hide();
29568 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
29569 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29571 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
29572 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29573 this.thumbEl.hide();
29575 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
29576 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29578 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
29579 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29580 this.errorEl.hide();
29582 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
29583 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29584 this.footerEl.hide();
29586 this.setThumbBoxSize();
29592 this.fireEvent('initial', this);
29599 window.addEventListener("resize", function() { _this.resize(); } );
29601 this.bodyEl.on('click', this.beforeSelectFile, this);
29604 this.bodyEl.on('touchstart', this.onTouchStart, this);
29605 this.bodyEl.on('touchmove', this.onTouchMove, this);
29606 this.bodyEl.on('touchend', this.onTouchEnd, this);
29610 this.bodyEl.on('mousedown', this.onMouseDown, this);
29611 this.bodyEl.on('mousemove', this.onMouseMove, this);
29612 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
29613 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
29614 Roo.get(document).on('mouseup', this.onMouseUp, this);
29617 this.selectorEl.on('change', this.onFileSelected, this);
29623 this.baseScale = 1;
29625 this.baseRotate = 1;
29626 this.dragable = false;
29627 this.pinching = false;
29630 this.cropData = false;
29631 this.notifyEl.dom.innerHTML = this.emptyText;
29633 this.selectorEl.dom.value = '';
29637 resize : function()
29639 if(this.fireEvent('resize', this) != false){
29640 this.setThumbBoxPosition();
29641 this.setCanvasPosition();
29645 onFooterButtonClick : function(e, el, o, type)
29648 case 'rotate-left' :
29649 this.onRotateLeft(e);
29651 case 'rotate-right' :
29652 this.onRotateRight(e);
29655 this.beforeSelectFile(e);
29670 this.fireEvent('footerbuttonclick', this, type);
29673 beforeSelectFile : function(e)
29675 e.preventDefault();
29677 if(this.fireEvent('beforeselectfile', this) != false){
29678 this.selectorEl.dom.click();
29682 onFileSelected : function(e)
29684 e.preventDefault();
29686 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29690 var file = this.selectorEl.dom.files[0];
29692 if(this.fireEvent('inspect', this, file) != false){
29693 this.prepare(file);
29698 trash : function(e)
29700 this.fireEvent('trash', this);
29703 download : function(e)
29705 this.fireEvent('download', this);
29708 loadCanvas : function(src)
29710 if(this.fireEvent('beforeloadcanvas', this, src) != false){
29714 this.imageEl = document.createElement('img');
29718 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
29720 this.imageEl.src = src;
29724 onLoadCanvas : function()
29726 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
29727 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
29729 this.bodyEl.un('click', this.beforeSelectFile, this);
29731 this.notifyEl.hide();
29732 this.thumbEl.show();
29733 this.footerEl.show();
29735 this.baseRotateLevel();
29737 if(this.isDocument){
29738 this.setThumbBoxSize();
29741 this.setThumbBoxPosition();
29743 this.baseScaleLevel();
29749 this.canvasLoaded = true;
29752 this.maskEl.unmask();
29757 setCanvasPosition : function()
29759 if(!this.canvasEl){
29763 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
29764 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
29766 this.previewEl.setLeft(pw);
29767 this.previewEl.setTop(ph);
29771 onMouseDown : function(e)
29775 this.dragable = true;
29776 this.pinching = false;
29778 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
29779 this.dragable = false;
29783 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29784 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29788 onMouseMove : function(e)
29792 if(!this.canvasLoaded){
29796 if (!this.dragable){
29800 var minX = Math.ceil(this.thumbEl.getLeft(true));
29801 var minY = Math.ceil(this.thumbEl.getTop(true));
29803 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
29804 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
29806 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29807 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29809 x = x - this.mouseX;
29810 y = y - this.mouseY;
29812 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
29813 var bgY = Math.ceil(y + this.previewEl.getTop(true));
29815 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
29816 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
29818 this.previewEl.setLeft(bgX);
29819 this.previewEl.setTop(bgY);
29821 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29822 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29825 onMouseUp : function(e)
29829 this.dragable = false;
29832 onMouseWheel : function(e)
29836 this.startScale = this.scale;
29838 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
29840 if(!this.zoomable()){
29841 this.scale = this.startScale;
29850 zoomable : function()
29852 var minScale = this.thumbEl.getWidth() / this.minWidth;
29854 if(this.minWidth < this.minHeight){
29855 minScale = this.thumbEl.getHeight() / this.minHeight;
29858 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
29859 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
29863 (this.rotate == 0 || this.rotate == 180) &&
29865 width > this.imageEl.OriginWidth ||
29866 height > this.imageEl.OriginHeight ||
29867 (width < this.minWidth && height < this.minHeight)
29875 (this.rotate == 90 || this.rotate == 270) &&
29877 width > this.imageEl.OriginWidth ||
29878 height > this.imageEl.OriginHeight ||
29879 (width < this.minHeight && height < this.minWidth)
29886 !this.isDocument &&
29887 (this.rotate == 0 || this.rotate == 180) &&
29889 width < this.minWidth ||
29890 width > this.imageEl.OriginWidth ||
29891 height < this.minHeight ||
29892 height > this.imageEl.OriginHeight
29899 !this.isDocument &&
29900 (this.rotate == 90 || this.rotate == 270) &&
29902 width < this.minHeight ||
29903 width > this.imageEl.OriginWidth ||
29904 height < this.minWidth ||
29905 height > this.imageEl.OriginHeight
29915 onRotateLeft : function(e)
29917 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29919 var minScale = this.thumbEl.getWidth() / this.minWidth;
29921 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29922 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29924 this.startScale = this.scale;
29926 while (this.getScaleLevel() < minScale){
29928 this.scale = this.scale + 1;
29930 if(!this.zoomable()){
29935 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29936 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29941 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29948 this.scale = this.startScale;
29950 this.onRotateFail();
29955 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29957 if(this.isDocument){
29958 this.setThumbBoxSize();
29959 this.setThumbBoxPosition();
29960 this.setCanvasPosition();
29965 this.fireEvent('rotate', this, 'left');
29969 onRotateRight : function(e)
29971 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29973 var minScale = this.thumbEl.getWidth() / this.minWidth;
29975 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29976 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29978 this.startScale = this.scale;
29980 while (this.getScaleLevel() < minScale){
29982 this.scale = this.scale + 1;
29984 if(!this.zoomable()){
29989 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29990 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29995 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
30002 this.scale = this.startScale;
30004 this.onRotateFail();
30009 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
30011 if(this.isDocument){
30012 this.setThumbBoxSize();
30013 this.setThumbBoxPosition();
30014 this.setCanvasPosition();
30019 this.fireEvent('rotate', this, 'right');
30022 onRotateFail : function()
30024 this.errorEl.show(true);
30028 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
30033 this.previewEl.dom.innerHTML = '';
30035 var canvasEl = document.createElement("canvas");
30037 var contextEl = canvasEl.getContext("2d");
30039 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30040 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30041 var center = this.imageEl.OriginWidth / 2;
30043 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
30044 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30045 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30046 center = this.imageEl.OriginHeight / 2;
30049 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
30051 contextEl.translate(center, center);
30052 contextEl.rotate(this.rotate * Math.PI / 180);
30054 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30056 this.canvasEl = document.createElement("canvas");
30058 this.contextEl = this.canvasEl.getContext("2d");
30060 switch (this.rotate) {
30063 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30064 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30066 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30071 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30072 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30074 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30075 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);
30079 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30084 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30085 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30087 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30088 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);
30092 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);
30097 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30098 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30100 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30101 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30105 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);
30112 this.previewEl.appendChild(this.canvasEl);
30114 this.setCanvasPosition();
30119 if(!this.canvasLoaded){
30123 var imageCanvas = document.createElement("canvas");
30125 var imageContext = imageCanvas.getContext("2d");
30127 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
30128 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
30130 var center = imageCanvas.width / 2;
30132 imageContext.translate(center, center);
30134 imageContext.rotate(this.rotate * Math.PI / 180);
30136 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30138 var canvas = document.createElement("canvas");
30140 var context = canvas.getContext("2d");
30142 canvas.width = this.minWidth;
30143 canvas.height = this.minHeight;
30145 switch (this.rotate) {
30148 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30149 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30151 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30152 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30154 var targetWidth = this.minWidth - 2 * x;
30155 var targetHeight = this.minHeight - 2 * y;
30159 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30160 scale = targetWidth / width;
30163 if(x > 0 && y == 0){
30164 scale = targetHeight / height;
30167 if(x > 0 && y > 0){
30168 scale = targetWidth / width;
30170 if(width < height){
30171 scale = targetHeight / height;
30175 context.scale(scale, scale);
30177 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30178 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30180 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30181 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30183 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30188 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30189 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30191 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30192 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30194 var targetWidth = this.minWidth - 2 * x;
30195 var targetHeight = this.minHeight - 2 * y;
30199 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30200 scale = targetWidth / width;
30203 if(x > 0 && y == 0){
30204 scale = targetHeight / height;
30207 if(x > 0 && y > 0){
30208 scale = targetWidth / width;
30210 if(width < height){
30211 scale = targetHeight / height;
30215 context.scale(scale, scale);
30217 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30218 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30220 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30221 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30223 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30225 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30230 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30231 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30233 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30234 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30236 var targetWidth = this.minWidth - 2 * x;
30237 var targetHeight = this.minHeight - 2 * y;
30241 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30242 scale = targetWidth / width;
30245 if(x > 0 && y == 0){
30246 scale = targetHeight / height;
30249 if(x > 0 && y > 0){
30250 scale = targetWidth / width;
30252 if(width < height){
30253 scale = targetHeight / height;
30257 context.scale(scale, scale);
30259 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30260 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30262 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30263 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30265 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30266 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30268 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30273 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30274 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30276 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30277 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30279 var targetWidth = this.minWidth - 2 * x;
30280 var targetHeight = this.minHeight - 2 * y;
30284 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30285 scale = targetWidth / width;
30288 if(x > 0 && y == 0){
30289 scale = targetHeight / height;
30292 if(x > 0 && y > 0){
30293 scale = targetWidth / width;
30295 if(width < height){
30296 scale = targetHeight / height;
30300 context.scale(scale, scale);
30302 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30303 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30305 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30306 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30308 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30310 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30317 this.cropData = canvas.toDataURL(this.cropType);
30319 if(this.fireEvent('crop', this, this.cropData) !== false){
30320 this.process(this.file, this.cropData);
30327 setThumbBoxSize : function()
30331 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
30332 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
30333 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
30335 this.minWidth = width;
30336 this.minHeight = height;
30338 if(this.rotate == 90 || this.rotate == 270){
30339 this.minWidth = height;
30340 this.minHeight = width;
30345 width = Math.ceil(this.minWidth * height / this.minHeight);
30347 if(this.minWidth > this.minHeight){
30349 height = Math.ceil(this.minHeight * width / this.minWidth);
30352 this.thumbEl.setStyle({
30353 width : width + 'px',
30354 height : height + 'px'
30361 setThumbBoxPosition : function()
30363 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
30364 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
30366 this.thumbEl.setLeft(x);
30367 this.thumbEl.setTop(y);
30371 baseRotateLevel : function()
30373 this.baseRotate = 1;
30376 typeof(this.exif) != 'undefined' &&
30377 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
30378 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
30380 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
30383 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
30387 baseScaleLevel : function()
30391 if(this.isDocument){
30393 if(this.baseRotate == 6 || this.baseRotate == 8){
30395 height = this.thumbEl.getHeight();
30396 this.baseScale = height / this.imageEl.OriginWidth;
30398 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
30399 width = this.thumbEl.getWidth();
30400 this.baseScale = width / this.imageEl.OriginHeight;
30406 height = this.thumbEl.getHeight();
30407 this.baseScale = height / this.imageEl.OriginHeight;
30409 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
30410 width = this.thumbEl.getWidth();
30411 this.baseScale = width / this.imageEl.OriginWidth;
30417 if(this.baseRotate == 6 || this.baseRotate == 8){
30419 width = this.thumbEl.getHeight();
30420 this.baseScale = width / this.imageEl.OriginHeight;
30422 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
30423 height = this.thumbEl.getWidth();
30424 this.baseScale = height / this.imageEl.OriginHeight;
30427 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30428 height = this.thumbEl.getWidth();
30429 this.baseScale = height / this.imageEl.OriginHeight;
30431 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
30432 width = this.thumbEl.getHeight();
30433 this.baseScale = width / this.imageEl.OriginWidth;
30440 width = this.thumbEl.getWidth();
30441 this.baseScale = width / this.imageEl.OriginWidth;
30443 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
30444 height = this.thumbEl.getHeight();
30445 this.baseScale = height / this.imageEl.OriginHeight;
30448 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30450 height = this.thumbEl.getHeight();
30451 this.baseScale = height / this.imageEl.OriginHeight;
30453 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
30454 width = this.thumbEl.getWidth();
30455 this.baseScale = width / this.imageEl.OriginWidth;
30463 getScaleLevel : function()
30465 return this.baseScale * Math.pow(1.1, this.scale);
30468 onTouchStart : function(e)
30470 if(!this.canvasLoaded){
30471 this.beforeSelectFile(e);
30475 var touches = e.browserEvent.touches;
30481 if(touches.length == 1){
30482 this.onMouseDown(e);
30486 if(touches.length != 2){
30492 for(var i = 0, finger; finger = touches[i]; i++){
30493 coords.push(finger.pageX, finger.pageY);
30496 var x = Math.pow(coords[0] - coords[2], 2);
30497 var y = Math.pow(coords[1] - coords[3], 2);
30499 this.startDistance = Math.sqrt(x + y);
30501 this.startScale = this.scale;
30503 this.pinching = true;
30504 this.dragable = false;
30508 onTouchMove : function(e)
30510 if(!this.pinching && !this.dragable){
30514 var touches = e.browserEvent.touches;
30521 this.onMouseMove(e);
30527 for(var i = 0, finger; finger = touches[i]; i++){
30528 coords.push(finger.pageX, finger.pageY);
30531 var x = Math.pow(coords[0] - coords[2], 2);
30532 var y = Math.pow(coords[1] - coords[3], 2);
30534 this.endDistance = Math.sqrt(x + y);
30536 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
30538 if(!this.zoomable()){
30539 this.scale = this.startScale;
30547 onTouchEnd : function(e)
30549 this.pinching = false;
30550 this.dragable = false;
30554 process : function(file, crop)
30557 this.maskEl.mask(this.loadingText);
30560 this.xhr = new XMLHttpRequest();
30562 file.xhr = this.xhr;
30564 this.xhr.open(this.method, this.url, true);
30567 "Accept": "application/json",
30568 "Cache-Control": "no-cache",
30569 "X-Requested-With": "XMLHttpRequest"
30572 for (var headerName in headers) {
30573 var headerValue = headers[headerName];
30575 this.xhr.setRequestHeader(headerName, headerValue);
30581 this.xhr.onload = function()
30583 _this.xhrOnLoad(_this.xhr);
30586 this.xhr.onerror = function()
30588 _this.xhrOnError(_this.xhr);
30591 var formData = new FormData();
30593 formData.append('returnHTML', 'NO');
30596 formData.append('crop', crop);
30599 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
30600 formData.append(this.paramName, file, file.name);
30603 if(typeof(file.filename) != 'undefined'){
30604 formData.append('filename', file.filename);
30607 if(typeof(file.mimetype) != 'undefined'){
30608 formData.append('mimetype', file.mimetype);
30611 if(this.fireEvent('arrange', this, formData) != false){
30612 this.xhr.send(formData);
30616 xhrOnLoad : function(xhr)
30619 this.maskEl.unmask();
30622 if (xhr.readyState !== 4) {
30623 this.fireEvent('exception', this, xhr);
30627 var response = Roo.decode(xhr.responseText);
30629 if(!response.success){
30630 this.fireEvent('exception', this, xhr);
30634 var response = Roo.decode(xhr.responseText);
30636 this.fireEvent('upload', this, response);
30640 xhrOnError : function()
30643 this.maskEl.unmask();
30646 Roo.log('xhr on error');
30648 var response = Roo.decode(xhr.responseText);
30654 prepare : function(file)
30657 this.maskEl.mask(this.loadingText);
30663 if(typeof(file) === 'string'){
30664 this.loadCanvas(file);
30668 if(!file || !this.urlAPI){
30673 this.cropType = file.type;
30677 if(this.fireEvent('prepare', this, this.file) != false){
30679 var reader = new FileReader();
30681 reader.onload = function (e) {
30682 if (e.target.error) {
30683 Roo.log(e.target.error);
30687 var buffer = e.target.result,
30688 dataView = new DataView(buffer),
30690 maxOffset = dataView.byteLength - 4,
30694 if (dataView.getUint16(0) === 0xffd8) {
30695 while (offset < maxOffset) {
30696 markerBytes = dataView.getUint16(offset);
30698 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
30699 markerLength = dataView.getUint16(offset + 2) + 2;
30700 if (offset + markerLength > dataView.byteLength) {
30701 Roo.log('Invalid meta data: Invalid segment size.');
30705 if(markerBytes == 0xffe1){
30706 _this.parseExifData(
30713 offset += markerLength;
30723 var url = _this.urlAPI.createObjectURL(_this.file);
30725 _this.loadCanvas(url);
30730 reader.readAsArrayBuffer(this.file);
30736 parseExifData : function(dataView, offset, length)
30738 var tiffOffset = offset + 10,
30742 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30743 // No Exif data, might be XMP data instead
30747 // Check for the ASCII code for "Exif" (0x45786966):
30748 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30749 // No Exif data, might be XMP data instead
30752 if (tiffOffset + 8 > dataView.byteLength) {
30753 Roo.log('Invalid Exif data: Invalid segment size.');
30756 // Check for the two null bytes:
30757 if (dataView.getUint16(offset + 8) !== 0x0000) {
30758 Roo.log('Invalid Exif data: Missing byte alignment offset.');
30761 // Check the byte alignment:
30762 switch (dataView.getUint16(tiffOffset)) {
30764 littleEndian = true;
30767 littleEndian = false;
30770 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
30773 // Check for the TIFF tag marker (0x002A):
30774 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
30775 Roo.log('Invalid Exif data: Missing TIFF marker.');
30778 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
30779 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
30781 this.parseExifTags(
30784 tiffOffset + dirOffset,
30789 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
30794 if (dirOffset + 6 > dataView.byteLength) {
30795 Roo.log('Invalid Exif data: Invalid directory offset.');
30798 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
30799 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
30800 if (dirEndOffset + 4 > dataView.byteLength) {
30801 Roo.log('Invalid Exif data: Invalid directory size.');
30804 for (i = 0; i < tagsNumber; i += 1) {
30808 dirOffset + 2 + 12 * i, // tag offset
30812 // Return the offset to the next directory:
30813 return dataView.getUint32(dirEndOffset, littleEndian);
30816 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
30818 var tag = dataView.getUint16(offset, littleEndian);
30820 this.exif[tag] = this.getExifValue(
30824 dataView.getUint16(offset + 2, littleEndian), // tag type
30825 dataView.getUint32(offset + 4, littleEndian), // tag length
30830 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
30832 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
30841 Roo.log('Invalid Exif data: Invalid tag type.');
30845 tagSize = tagType.size * length;
30846 // Determine if the value is contained in the dataOffset bytes,
30847 // or if the value at the dataOffset is a pointer to the actual data:
30848 dataOffset = tagSize > 4 ?
30849 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
30850 if (dataOffset + tagSize > dataView.byteLength) {
30851 Roo.log('Invalid Exif data: Invalid data offset.');
30854 if (length === 1) {
30855 return tagType.getValue(dataView, dataOffset, littleEndian);
30858 for (i = 0; i < length; i += 1) {
30859 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
30862 if (tagType.ascii) {
30864 // Concatenate the chars:
30865 for (i = 0; i < values.length; i += 1) {
30867 // Ignore the terminating NULL byte(s):
30868 if (c === '\u0000') {
30880 Roo.apply(Roo.bootstrap.UploadCropbox, {
30882 'Orientation': 0x0112
30886 1: 0, //'top-left',
30888 3: 180, //'bottom-right',
30889 // 4: 'bottom-left',
30891 6: 90, //'right-top',
30892 // 7: 'right-bottom',
30893 8: 270 //'left-bottom'
30897 // byte, 8-bit unsigned int:
30899 getValue: function (dataView, dataOffset) {
30900 return dataView.getUint8(dataOffset);
30904 // ascii, 8-bit byte:
30906 getValue: function (dataView, dataOffset) {
30907 return String.fromCharCode(dataView.getUint8(dataOffset));
30912 // short, 16 bit int:
30914 getValue: function (dataView, dataOffset, littleEndian) {
30915 return dataView.getUint16(dataOffset, littleEndian);
30919 // long, 32 bit int:
30921 getValue: function (dataView, dataOffset, littleEndian) {
30922 return dataView.getUint32(dataOffset, littleEndian);
30926 // rational = two long values, first is numerator, second is denominator:
30928 getValue: function (dataView, dataOffset, littleEndian) {
30929 return dataView.getUint32(dataOffset, littleEndian) /
30930 dataView.getUint32(dataOffset + 4, littleEndian);
30934 // slong, 32 bit signed int:
30936 getValue: function (dataView, dataOffset, littleEndian) {
30937 return dataView.getInt32(dataOffset, littleEndian);
30941 // srational, two slongs, first is numerator, second is denominator:
30943 getValue: function (dataView, dataOffset, littleEndian) {
30944 return dataView.getInt32(dataOffset, littleEndian) /
30945 dataView.getInt32(dataOffset + 4, littleEndian);
30955 cls : 'btn-group roo-upload-cropbox-rotate-left',
30956 action : 'rotate-left',
30960 cls : 'btn btn-default',
30961 html : '<i class="fa fa-undo"></i>'
30967 cls : 'btn-group roo-upload-cropbox-picture',
30968 action : 'picture',
30972 cls : 'btn btn-default',
30973 html : '<i class="fa fa-picture-o"></i>'
30979 cls : 'btn-group roo-upload-cropbox-rotate-right',
30980 action : 'rotate-right',
30984 cls : 'btn btn-default',
30985 html : '<i class="fa fa-repeat"></i>'
30993 cls : 'btn-group roo-upload-cropbox-rotate-left',
30994 action : 'rotate-left',
30998 cls : 'btn btn-default',
30999 html : '<i class="fa fa-undo"></i>'
31005 cls : 'btn-group roo-upload-cropbox-download',
31006 action : 'download',
31010 cls : 'btn btn-default',
31011 html : '<i class="fa fa-download"></i>'
31017 cls : 'btn-group roo-upload-cropbox-crop',
31022 cls : 'btn btn-default',
31023 html : '<i class="fa fa-crop"></i>'
31029 cls : 'btn-group roo-upload-cropbox-trash',
31034 cls : 'btn btn-default',
31035 html : '<i class="fa fa-trash"></i>'
31041 cls : 'btn-group roo-upload-cropbox-rotate-right',
31042 action : 'rotate-right',
31046 cls : 'btn btn-default',
31047 html : '<i class="fa fa-repeat"></i>'
31055 cls : 'btn-group roo-upload-cropbox-rotate-left',
31056 action : 'rotate-left',
31060 cls : 'btn btn-default',
31061 html : '<i class="fa fa-undo"></i>'
31067 cls : 'btn-group roo-upload-cropbox-rotate-right',
31068 action : 'rotate-right',
31072 cls : 'btn btn-default',
31073 html : '<i class="fa fa-repeat"></i>'
31086 * @class Roo.bootstrap.DocumentManager
31087 * @extends Roo.bootstrap.Component
31088 * Bootstrap DocumentManager class
31089 * @cfg {String} paramName default 'imageUpload'
31090 * @cfg {String} toolTipName default 'filename'
31091 * @cfg {String} method default POST
31092 * @cfg {String} url action url
31093 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
31094 * @cfg {Boolean} multiple multiple upload default true
31095 * @cfg {Number} thumbSize default 300
31096 * @cfg {String} fieldLabel
31097 * @cfg {Number} labelWidth default 4
31098 * @cfg {String} labelAlign (left|top) default left
31099 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
31100 * @cfg {Number} labellg set the width of label (1-12)
31101 * @cfg {Number} labelmd set the width of label (1-12)
31102 * @cfg {Number} labelsm set the width of label (1-12)
31103 * @cfg {Number} labelxs set the width of label (1-12)
31106 * Create a new DocumentManager
31107 * @param {Object} config The config object
31110 Roo.bootstrap.DocumentManager = function(config){
31111 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
31114 this.delegates = [];
31119 * Fire when initial the DocumentManager
31120 * @param {Roo.bootstrap.DocumentManager} this
31125 * inspect selected file
31126 * @param {Roo.bootstrap.DocumentManager} this
31127 * @param {File} file
31132 * Fire when xhr load exception
31133 * @param {Roo.bootstrap.DocumentManager} this
31134 * @param {XMLHttpRequest} xhr
31136 "exception" : true,
31138 * @event afterupload
31139 * Fire when xhr load exception
31140 * @param {Roo.bootstrap.DocumentManager} this
31141 * @param {XMLHttpRequest} xhr
31143 "afterupload" : true,
31146 * prepare the form data
31147 * @param {Roo.bootstrap.DocumentManager} this
31148 * @param {Object} formData
31153 * Fire when remove the file
31154 * @param {Roo.bootstrap.DocumentManager} this
31155 * @param {Object} file
31160 * Fire after refresh the file
31161 * @param {Roo.bootstrap.DocumentManager} this
31166 * Fire after click the image
31167 * @param {Roo.bootstrap.DocumentManager} this
31168 * @param {Object} file
31173 * Fire when upload a image and editable set to true
31174 * @param {Roo.bootstrap.DocumentManager} this
31175 * @param {Object} file
31179 * @event beforeselectfile
31180 * Fire before select file
31181 * @param {Roo.bootstrap.DocumentManager} this
31183 "beforeselectfile" : true,
31186 * Fire before process file
31187 * @param {Roo.bootstrap.DocumentManager} this
31188 * @param {Object} file
31192 * @event previewrendered
31193 * Fire when preview rendered
31194 * @param {Roo.bootstrap.DocumentManager} this
31195 * @param {Object} file
31197 "previewrendered" : true,
31200 "previewResize" : true
31205 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
31214 paramName : 'imageUpload',
31215 toolTipName : 'filename',
31218 labelAlign : 'left',
31228 getAutoCreate : function()
31230 var managerWidget = {
31232 cls : 'roo-document-manager',
31236 cls : 'roo-document-manager-selector',
31241 cls : 'roo-document-manager-uploader',
31245 cls : 'roo-document-manager-upload-btn',
31246 html : '<i class="fa fa-plus"></i>'
31257 cls : 'column col-md-12',
31262 if(this.fieldLabel.length){
31267 cls : 'column col-md-12',
31268 html : this.fieldLabel
31272 cls : 'column col-md-12',
31277 if(this.labelAlign == 'left'){
31282 html : this.fieldLabel
31291 if(this.labelWidth > 12){
31292 content[0].style = "width: " + this.labelWidth + 'px';
31295 if(this.labelWidth < 13 && this.labelmd == 0){
31296 this.labelmd = this.labelWidth;
31299 if(this.labellg > 0){
31300 content[0].cls += ' col-lg-' + this.labellg;
31301 content[1].cls += ' col-lg-' + (12 - this.labellg);
31304 if(this.labelmd > 0){
31305 content[0].cls += ' col-md-' + this.labelmd;
31306 content[1].cls += ' col-md-' + (12 - this.labelmd);
31309 if(this.labelsm > 0){
31310 content[0].cls += ' col-sm-' + this.labelsm;
31311 content[1].cls += ' col-sm-' + (12 - this.labelsm);
31314 if(this.labelxs > 0){
31315 content[0].cls += ' col-xs-' + this.labelxs;
31316 content[1].cls += ' col-xs-' + (12 - this.labelxs);
31324 cls : 'row clearfix',
31332 initEvents : function()
31334 this.managerEl = this.el.select('.roo-document-manager', true).first();
31335 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31337 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
31338 this.selectorEl.hide();
31341 this.selectorEl.attr('multiple', 'multiple');
31344 this.selectorEl.on('change', this.onFileSelected, this);
31346 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
31347 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31349 this.uploader.on('click', this.onUploaderClick, this);
31351 this.renderProgressDialog();
31355 window.addEventListener("resize", function() { _this.refresh(); } );
31357 this.fireEvent('initial', this);
31360 renderProgressDialog : function()
31364 this.progressDialog = new Roo.bootstrap.Modal({
31365 cls : 'roo-document-manager-progress-dialog',
31366 allow_close : false,
31377 btnclick : function() {
31378 _this.uploadCancel();
31384 this.progressDialog.render(Roo.get(document.body));
31386 this.progress = new Roo.bootstrap.Progress({
31387 cls : 'roo-document-manager-progress',
31392 this.progress.render(this.progressDialog.getChildContainer());
31394 this.progressBar = new Roo.bootstrap.ProgressBar({
31395 cls : 'roo-document-manager-progress-bar',
31398 aria_valuemax : 12,
31402 this.progressBar.render(this.progress.getChildContainer());
31405 onUploaderClick : function(e)
31407 e.preventDefault();
31409 if(this.fireEvent('beforeselectfile', this) != false){
31410 this.selectorEl.dom.click();
31415 onFileSelected : function(e)
31417 e.preventDefault();
31419 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
31423 Roo.each(this.selectorEl.dom.files, function(file){
31424 if(this.fireEvent('inspect', this, file) != false){
31425 this.files.push(file);
31435 this.selectorEl.dom.value = '';
31437 if(!this.files || !this.files.length){
31441 if(this.boxes > 0 && this.files.length > this.boxes){
31442 this.files = this.files.slice(0, this.boxes);
31445 this.uploader.show();
31447 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31448 this.uploader.hide();
31457 Roo.each(this.files, function(file){
31459 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31460 var f = this.renderPreview(file);
31465 if(file.type.indexOf('image') != -1){
31466 this.delegates.push(
31468 _this.process(file);
31469 }).createDelegate(this)
31477 _this.process(file);
31478 }).createDelegate(this)
31483 this.files = files;
31485 this.delegates = this.delegates.concat(docs);
31487 if(!this.delegates.length){
31492 this.progressBar.aria_valuemax = this.delegates.length;
31499 arrange : function()
31501 if(!this.delegates.length){
31502 this.progressDialog.hide();
31507 var delegate = this.delegates.shift();
31509 this.progressDialog.show();
31511 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
31513 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
31518 refresh : function()
31520 this.uploader.show();
31522 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31523 this.uploader.hide();
31526 Roo.isTouch ? this.closable(false) : this.closable(true);
31528 this.fireEvent('refresh', this);
31531 onRemove : function(e, el, o)
31533 e.preventDefault();
31535 this.fireEvent('remove', this, o);
31539 remove : function(o)
31543 Roo.each(this.files, function(file){
31544 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
31553 this.files = files;
31560 Roo.each(this.files, function(file){
31565 file.target.remove();
31574 onClick : function(e, el, o)
31576 e.preventDefault();
31578 this.fireEvent('click', this, o);
31582 closable : function(closable)
31584 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
31586 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31598 xhrOnLoad : function(xhr)
31600 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31604 if (xhr.readyState !== 4) {
31606 this.fireEvent('exception', this, xhr);
31610 var response = Roo.decode(xhr.responseText);
31612 if(!response.success){
31614 this.fireEvent('exception', this, xhr);
31618 var file = this.renderPreview(response.data);
31620 this.files.push(file);
31624 this.fireEvent('afterupload', this, xhr);
31628 xhrOnError : function(xhr)
31630 Roo.log('xhr on error');
31632 var response = Roo.decode(xhr.responseText);
31639 process : function(file)
31641 if(this.fireEvent('process', this, file) !== false){
31642 if(this.editable && file.type.indexOf('image') != -1){
31643 this.fireEvent('edit', this, file);
31647 this.uploadStart(file, false);
31654 uploadStart : function(file, crop)
31656 this.xhr = new XMLHttpRequest();
31658 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31663 file.xhr = this.xhr;
31665 this.managerEl.createChild({
31667 cls : 'roo-document-manager-loading',
31671 tooltip : file.name,
31672 cls : 'roo-document-manager-thumb',
31673 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31679 this.xhr.open(this.method, this.url, true);
31682 "Accept": "application/json",
31683 "Cache-Control": "no-cache",
31684 "X-Requested-With": "XMLHttpRequest"
31687 for (var headerName in headers) {
31688 var headerValue = headers[headerName];
31690 this.xhr.setRequestHeader(headerName, headerValue);
31696 this.xhr.onload = function()
31698 _this.xhrOnLoad(_this.xhr);
31701 this.xhr.onerror = function()
31703 _this.xhrOnError(_this.xhr);
31706 var formData = new FormData();
31708 formData.append('returnHTML', 'NO');
31711 formData.append('crop', crop);
31714 formData.append(this.paramName, file, file.name);
31721 if(this.fireEvent('prepare', this, formData, options) != false){
31723 if(options.manually){
31727 this.xhr.send(formData);
31731 this.uploadCancel();
31734 uploadCancel : function()
31740 this.delegates = [];
31742 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31749 renderPreview : function(file)
31751 if(typeof(file.target) != 'undefined' && file.target){
31755 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
31757 var previewEl = this.managerEl.createChild({
31759 cls : 'roo-document-manager-preview',
31763 tooltip : file[this.toolTipName],
31764 cls : 'roo-document-manager-thumb',
31765 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
31770 html : '<i class="fa fa-times-circle"></i>'
31775 var close = previewEl.select('button.close', true).first();
31777 close.on('click', this.onRemove, this, file);
31779 file.target = previewEl;
31781 var image = previewEl.select('img', true).first();
31785 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
31787 image.on('click', this.onClick, this, file);
31789 this.fireEvent('previewrendered', this, file);
31795 onPreviewLoad : function(file, image)
31797 if(typeof(file.target) == 'undefined' || !file.target){
31801 var width = image.dom.naturalWidth || image.dom.width;
31802 var height = image.dom.naturalHeight || image.dom.height;
31804 if(!this.previewResize) {
31808 if(width > height){
31809 file.target.addClass('wide');
31813 file.target.addClass('tall');
31818 uploadFromSource : function(file, crop)
31820 this.xhr = new XMLHttpRequest();
31822 this.managerEl.createChild({
31824 cls : 'roo-document-manager-loading',
31828 tooltip : file.name,
31829 cls : 'roo-document-manager-thumb',
31830 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31836 this.xhr.open(this.method, this.url, true);
31839 "Accept": "application/json",
31840 "Cache-Control": "no-cache",
31841 "X-Requested-With": "XMLHttpRequest"
31844 for (var headerName in headers) {
31845 var headerValue = headers[headerName];
31847 this.xhr.setRequestHeader(headerName, headerValue);
31853 this.xhr.onload = function()
31855 _this.xhrOnLoad(_this.xhr);
31858 this.xhr.onerror = function()
31860 _this.xhrOnError(_this.xhr);
31863 var formData = new FormData();
31865 formData.append('returnHTML', 'NO');
31867 formData.append('crop', crop);
31869 if(typeof(file.filename) != 'undefined'){
31870 formData.append('filename', file.filename);
31873 if(typeof(file.mimetype) != 'undefined'){
31874 formData.append('mimetype', file.mimetype);
31879 if(this.fireEvent('prepare', this, formData) != false){
31880 this.xhr.send(formData);
31890 * @class Roo.bootstrap.DocumentViewer
31891 * @extends Roo.bootstrap.Component
31892 * Bootstrap DocumentViewer class
31893 * @cfg {Boolean} showDownload (true|false) show download button (default true)
31894 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
31897 * Create a new DocumentViewer
31898 * @param {Object} config The config object
31901 Roo.bootstrap.DocumentViewer = function(config){
31902 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
31907 * Fire after initEvent
31908 * @param {Roo.bootstrap.DocumentViewer} this
31914 * @param {Roo.bootstrap.DocumentViewer} this
31919 * Fire after download button
31920 * @param {Roo.bootstrap.DocumentViewer} this
31925 * Fire after trash button
31926 * @param {Roo.bootstrap.DocumentViewer} this
31933 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31935 showDownload : true,
31939 getAutoCreate : function()
31943 cls : 'roo-document-viewer',
31947 cls : 'roo-document-viewer-body',
31951 cls : 'roo-document-viewer-thumb',
31955 cls : 'roo-document-viewer-image'
31963 cls : 'roo-document-viewer-footer',
31966 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31970 cls : 'btn-group roo-document-viewer-download',
31974 cls : 'btn btn-default',
31975 html : '<i class="fa fa-download"></i>'
31981 cls : 'btn-group roo-document-viewer-trash',
31985 cls : 'btn btn-default',
31986 html : '<i class="fa fa-trash"></i>'
31999 initEvents : function()
32001 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
32002 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32004 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
32005 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32007 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
32008 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32010 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
32011 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
32013 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
32014 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
32016 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
32017 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
32019 this.bodyEl.on('click', this.onClick, this);
32020 this.downloadBtn.on('click', this.onDownload, this);
32021 this.trashBtn.on('click', this.onTrash, this);
32023 this.downloadBtn.hide();
32024 this.trashBtn.hide();
32026 if(this.showDownload){
32027 this.downloadBtn.show();
32030 if(this.showTrash){
32031 this.trashBtn.show();
32034 if(!this.showDownload && !this.showTrash) {
32035 this.footerEl.hide();
32040 initial : function()
32042 this.fireEvent('initial', this);
32046 onClick : function(e)
32048 e.preventDefault();
32050 this.fireEvent('click', this);
32053 onDownload : function(e)
32055 e.preventDefault();
32057 this.fireEvent('download', this);
32060 onTrash : function(e)
32062 e.preventDefault();
32064 this.fireEvent('trash', this);
32076 * @class Roo.bootstrap.NavProgressBar
32077 * @extends Roo.bootstrap.Component
32078 * Bootstrap NavProgressBar class
32081 * Create a new nav progress bar
32082 * @param {Object} config The config object
32085 Roo.bootstrap.NavProgressBar = function(config){
32086 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
32088 this.bullets = this.bullets || [];
32090 // Roo.bootstrap.NavProgressBar.register(this);
32094 * Fires when the active item changes
32095 * @param {Roo.bootstrap.NavProgressBar} this
32096 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
32097 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
32104 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
32109 getAutoCreate : function()
32111 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
32115 cls : 'roo-navigation-bar-group',
32119 cls : 'roo-navigation-top-bar'
32123 cls : 'roo-navigation-bullets-bar',
32127 cls : 'roo-navigation-bar'
32134 cls : 'roo-navigation-bottom-bar'
32144 initEvents: function()
32149 onRender : function(ct, position)
32151 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32153 if(this.bullets.length){
32154 Roo.each(this.bullets, function(b){
32163 addItem : function(cfg)
32165 var item = new Roo.bootstrap.NavProgressItem(cfg);
32167 item.parentId = this.id;
32168 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
32171 var top = new Roo.bootstrap.Element({
32173 cls : 'roo-navigation-bar-text'
32176 var bottom = new Roo.bootstrap.Element({
32178 cls : 'roo-navigation-bar-text'
32181 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
32182 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
32184 var topText = new Roo.bootstrap.Element({
32186 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
32189 var bottomText = new Roo.bootstrap.Element({
32191 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
32194 topText.onRender(top.el, null);
32195 bottomText.onRender(bottom.el, null);
32198 item.bottomEl = bottom;
32201 this.barItems.push(item);
32206 getActive : function()
32208 var active = false;
32210 Roo.each(this.barItems, function(v){
32212 if (!v.isActive()) {
32224 setActiveItem : function(item)
32228 Roo.each(this.barItems, function(v){
32229 if (v.rid == item.rid) {
32233 if (v.isActive()) {
32234 v.setActive(false);
32239 item.setActive(true);
32241 this.fireEvent('changed', this, item, prev);
32244 getBarItem: function(rid)
32248 Roo.each(this.barItems, function(e) {
32249 if (e.rid != rid) {
32260 indexOfItem : function(item)
32264 Roo.each(this.barItems, function(v, i){
32266 if (v.rid != item.rid) {
32277 setActiveNext : function()
32279 var i = this.indexOfItem(this.getActive());
32281 if (i > this.barItems.length) {
32285 this.setActiveItem(this.barItems[i+1]);
32288 setActivePrev : function()
32290 var i = this.indexOfItem(this.getActive());
32296 this.setActiveItem(this.barItems[i-1]);
32299 format : function()
32301 if(!this.barItems.length){
32305 var width = 100 / this.barItems.length;
32307 Roo.each(this.barItems, function(i){
32308 i.el.setStyle('width', width + '%');
32309 i.topEl.el.setStyle('width', width + '%');
32310 i.bottomEl.el.setStyle('width', width + '%');
32319 * Nav Progress Item
32324 * @class Roo.bootstrap.NavProgressItem
32325 * @extends Roo.bootstrap.Component
32326 * Bootstrap NavProgressItem class
32327 * @cfg {String} rid the reference id
32328 * @cfg {Boolean} active (true|false) Is item active default false
32329 * @cfg {Boolean} disabled (true|false) Is item active default false
32330 * @cfg {String} html
32331 * @cfg {String} position (top|bottom) text position default bottom
32332 * @cfg {String} icon show icon instead of number
32335 * Create a new NavProgressItem
32336 * @param {Object} config The config object
32338 Roo.bootstrap.NavProgressItem = function(config){
32339 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
32344 * The raw click event for the entire grid.
32345 * @param {Roo.bootstrap.NavProgressItem} this
32346 * @param {Roo.EventObject} e
32353 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
32359 position : 'bottom',
32362 getAutoCreate : function()
32364 var iconCls = 'roo-navigation-bar-item-icon';
32366 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
32370 cls: 'roo-navigation-bar-item',
32380 cfg.cls += ' active';
32383 cfg.cls += ' disabled';
32389 disable : function()
32391 this.setDisabled(true);
32394 enable : function()
32396 this.setDisabled(false);
32399 initEvents: function()
32401 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
32403 this.iconEl.on('click', this.onClick, this);
32406 onClick : function(e)
32408 e.preventDefault();
32414 if(this.fireEvent('click', this, e) === false){
32418 this.parent().setActiveItem(this);
32421 isActive: function ()
32423 return this.active;
32426 setActive : function(state)
32428 if(this.active == state){
32432 this.active = state;
32435 this.el.addClass('active');
32439 this.el.removeClass('active');
32444 setDisabled : function(state)
32446 if(this.disabled == state){
32450 this.disabled = state;
32453 this.el.addClass('disabled');
32457 this.el.removeClass('disabled');
32460 tooltipEl : function()
32462 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
32475 * @class Roo.bootstrap.FieldLabel
32476 * @extends Roo.bootstrap.Component
32477 * Bootstrap FieldLabel class
32478 * @cfg {String} html contents of the element
32479 * @cfg {String} tag tag of the element default label
32480 * @cfg {String} cls class of the element
32481 * @cfg {String} target label target
32482 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
32483 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
32484 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
32485 * @cfg {String} iconTooltip default "This field is required"
32486 * @cfg {String} indicatorpos (left|right) default left
32489 * Create a new FieldLabel
32490 * @param {Object} config The config object
32493 Roo.bootstrap.FieldLabel = function(config){
32494 Roo.bootstrap.Element.superclass.constructor.call(this, config);
32499 * Fires after the field has been marked as invalid.
32500 * @param {Roo.form.FieldLabel} this
32501 * @param {String} msg The validation message
32506 * Fires after the field has been validated with no errors.
32507 * @param {Roo.form.FieldLabel} this
32513 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
32520 invalidClass : 'has-warning',
32521 validClass : 'has-success',
32522 iconTooltip : 'This field is required',
32523 indicatorpos : 'left',
32525 getAutoCreate : function(){
32528 if (!this.allowBlank) {
32534 cls : 'roo-bootstrap-field-label ' + this.cls,
32539 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
32540 tooltip : this.iconTooltip
32549 if(this.indicatorpos == 'right'){
32552 cls : 'roo-bootstrap-field-label ' + this.cls,
32561 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
32562 tooltip : this.iconTooltip
32571 initEvents: function()
32573 Roo.bootstrap.Element.superclass.initEvents.call(this);
32575 this.indicator = this.indicatorEl();
32577 if(this.indicator){
32578 this.indicator.removeClass('visible');
32579 this.indicator.addClass('invisible');
32582 Roo.bootstrap.FieldLabel.register(this);
32585 indicatorEl : function()
32587 var indicator = this.el.select('i.roo-required-indicator',true).first();
32598 * Mark this field as valid
32600 markValid : function()
32602 if(this.indicator){
32603 this.indicator.removeClass('visible');
32604 this.indicator.addClass('invisible');
32606 if (Roo.bootstrap.version == 3) {
32607 this.el.removeClass(this.invalidClass);
32608 this.el.addClass(this.validClass);
32610 this.el.removeClass('is-invalid');
32611 this.el.addClass('is-valid');
32615 this.fireEvent('valid', this);
32619 * Mark this field as invalid
32620 * @param {String} msg The validation message
32622 markInvalid : function(msg)
32624 if(this.indicator){
32625 this.indicator.removeClass('invisible');
32626 this.indicator.addClass('visible');
32628 if (Roo.bootstrap.version == 3) {
32629 this.el.removeClass(this.validClass);
32630 this.el.addClass(this.invalidClass);
32632 this.el.removeClass('is-valid');
32633 this.el.addClass('is-invalid');
32637 this.fireEvent('invalid', this, msg);
32643 Roo.apply(Roo.bootstrap.FieldLabel, {
32648 * register a FieldLabel Group
32649 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
32651 register : function(label)
32653 if(this.groups.hasOwnProperty(label.target)){
32657 this.groups[label.target] = label;
32661 * fetch a FieldLabel Group based on the target
32662 * @param {string} target
32663 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
32665 get: function(target) {
32666 if (typeof(this.groups[target]) == 'undefined') {
32670 return this.groups[target] ;
32679 * page DateSplitField.
32685 * @class Roo.bootstrap.DateSplitField
32686 * @extends Roo.bootstrap.Component
32687 * Bootstrap DateSplitField class
32688 * @cfg {string} fieldLabel - the label associated
32689 * @cfg {Number} labelWidth set the width of label (0-12)
32690 * @cfg {String} labelAlign (top|left)
32691 * @cfg {Boolean} dayAllowBlank (true|false) default false
32692 * @cfg {Boolean} monthAllowBlank (true|false) default false
32693 * @cfg {Boolean} yearAllowBlank (true|false) default false
32694 * @cfg {string} dayPlaceholder
32695 * @cfg {string} monthPlaceholder
32696 * @cfg {string} yearPlaceholder
32697 * @cfg {string} dayFormat default 'd'
32698 * @cfg {string} monthFormat default 'm'
32699 * @cfg {string} yearFormat default 'Y'
32700 * @cfg {Number} labellg set the width of label (1-12)
32701 * @cfg {Number} labelmd set the width of label (1-12)
32702 * @cfg {Number} labelsm set the width of label (1-12)
32703 * @cfg {Number} labelxs set the width of label (1-12)
32707 * Create a new DateSplitField
32708 * @param {Object} config The config object
32711 Roo.bootstrap.DateSplitField = function(config){
32712 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
32718 * getting the data of years
32719 * @param {Roo.bootstrap.DateSplitField} this
32720 * @param {Object} years
32725 * getting the data of days
32726 * @param {Roo.bootstrap.DateSplitField} this
32727 * @param {Object} days
32732 * Fires after the field has been marked as invalid.
32733 * @param {Roo.form.Field} this
32734 * @param {String} msg The validation message
32739 * Fires after the field has been validated with no errors.
32740 * @param {Roo.form.Field} this
32746 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
32749 labelAlign : 'top',
32751 dayAllowBlank : false,
32752 monthAllowBlank : false,
32753 yearAllowBlank : false,
32754 dayPlaceholder : '',
32755 monthPlaceholder : '',
32756 yearPlaceholder : '',
32760 isFormField : true,
32766 getAutoCreate : function()
32770 cls : 'row roo-date-split-field-group',
32775 cls : 'form-hidden-field roo-date-split-field-group-value',
32781 var labelCls = 'col-md-12';
32782 var contentCls = 'col-md-4';
32784 if(this.fieldLabel){
32788 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
32792 html : this.fieldLabel
32797 if(this.labelAlign == 'left'){
32799 if(this.labelWidth > 12){
32800 label.style = "width: " + this.labelWidth + 'px';
32803 if(this.labelWidth < 13 && this.labelmd == 0){
32804 this.labelmd = this.labelWidth;
32807 if(this.labellg > 0){
32808 labelCls = ' col-lg-' + this.labellg;
32809 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
32812 if(this.labelmd > 0){
32813 labelCls = ' col-md-' + this.labelmd;
32814 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
32817 if(this.labelsm > 0){
32818 labelCls = ' col-sm-' + this.labelsm;
32819 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
32822 if(this.labelxs > 0){
32823 labelCls = ' col-xs-' + this.labelxs;
32824 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
32828 label.cls += ' ' + labelCls;
32830 cfg.cn.push(label);
32833 Roo.each(['day', 'month', 'year'], function(t){
32836 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
32843 inputEl: function ()
32845 return this.el.select('.roo-date-split-field-group-value', true).first();
32848 onRender : function(ct, position)
32852 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32854 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
32856 this.dayField = new Roo.bootstrap.ComboBox({
32857 allowBlank : this.dayAllowBlank,
32858 alwaysQuery : true,
32859 displayField : 'value',
32862 forceSelection : true,
32864 placeholder : this.dayPlaceholder,
32865 selectOnFocus : true,
32866 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32867 triggerAction : 'all',
32869 valueField : 'value',
32870 store : new Roo.data.SimpleStore({
32871 data : (function() {
32873 _this.fireEvent('days', _this, days);
32876 fields : [ 'value' ]
32879 select : function (_self, record, index)
32881 _this.setValue(_this.getValue());
32886 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
32888 this.monthField = new Roo.bootstrap.MonthField({
32889 after : '<i class=\"fa fa-calendar\"></i>',
32890 allowBlank : this.monthAllowBlank,
32891 placeholder : this.monthPlaceholder,
32894 render : function (_self)
32896 this.el.select('span.input-group-addon', true).first().on('click', function(e){
32897 e.preventDefault();
32901 select : function (_self, oldvalue, newvalue)
32903 _this.setValue(_this.getValue());
32908 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
32910 this.yearField = new Roo.bootstrap.ComboBox({
32911 allowBlank : this.yearAllowBlank,
32912 alwaysQuery : true,
32913 displayField : 'value',
32916 forceSelection : true,
32918 placeholder : this.yearPlaceholder,
32919 selectOnFocus : true,
32920 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32921 triggerAction : 'all',
32923 valueField : 'value',
32924 store : new Roo.data.SimpleStore({
32925 data : (function() {
32927 _this.fireEvent('years', _this, years);
32930 fields : [ 'value' ]
32933 select : function (_self, record, index)
32935 _this.setValue(_this.getValue());
32940 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32943 setValue : function(v, format)
32945 this.inputEl.dom.value = v;
32947 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32949 var d = Date.parseDate(v, f);
32956 this.setDay(d.format(this.dayFormat));
32957 this.setMonth(d.format(this.monthFormat));
32958 this.setYear(d.format(this.yearFormat));
32965 setDay : function(v)
32967 this.dayField.setValue(v);
32968 this.inputEl.dom.value = this.getValue();
32973 setMonth : function(v)
32975 this.monthField.setValue(v, true);
32976 this.inputEl.dom.value = this.getValue();
32981 setYear : function(v)
32983 this.yearField.setValue(v);
32984 this.inputEl.dom.value = this.getValue();
32989 getDay : function()
32991 return this.dayField.getValue();
32994 getMonth : function()
32996 return this.monthField.getValue();
32999 getYear : function()
33001 return this.yearField.getValue();
33004 getValue : function()
33006 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
33008 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
33018 this.inputEl.dom.value = '';
33023 validate : function()
33025 var d = this.dayField.validate();
33026 var m = this.monthField.validate();
33027 var y = this.yearField.validate();
33032 (!this.dayAllowBlank && !d) ||
33033 (!this.monthAllowBlank && !m) ||
33034 (!this.yearAllowBlank && !y)
33039 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
33048 this.markInvalid();
33053 markValid : function()
33056 var label = this.el.select('label', true).first();
33057 var icon = this.el.select('i.fa-star', true).first();
33063 this.fireEvent('valid', this);
33067 * Mark this field as invalid
33068 * @param {String} msg The validation message
33070 markInvalid : function(msg)
33073 var label = this.el.select('label', true).first();
33074 var icon = this.el.select('i.fa-star', true).first();
33076 if(label && !icon){
33077 this.el.select('.roo-date-split-field-label', true).createChild({
33079 cls : 'text-danger fa fa-lg fa-star',
33080 tooltip : 'This field is required',
33081 style : 'margin-right:5px;'
33085 this.fireEvent('invalid', this, msg);
33088 clearInvalid : function()
33090 var label = this.el.select('label', true).first();
33091 var icon = this.el.select('i.fa-star', true).first();
33097 this.fireEvent('valid', this);
33100 getName: function()
33110 * http://masonry.desandro.com
33112 * The idea is to render all the bricks based on vertical width...
33114 * The original code extends 'outlayer' - we might need to use that....
33120 * @class Roo.bootstrap.LayoutMasonry
33121 * @extends Roo.bootstrap.Component
33122 * Bootstrap Layout Masonry class
33125 * Create a new Element
33126 * @param {Object} config The config object
33129 Roo.bootstrap.LayoutMasonry = function(config){
33131 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
33135 Roo.bootstrap.LayoutMasonry.register(this);
33141 * Fire after layout the items
33142 * @param {Roo.bootstrap.LayoutMasonry} this
33143 * @param {Roo.EventObject} e
33150 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
33153 * @cfg {Boolean} isLayoutInstant = no animation?
33155 isLayoutInstant : false, // needed?
33158 * @cfg {Number} boxWidth width of the columns
33163 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
33168 * @cfg {Number} padWidth padding below box..
33173 * @cfg {Number} gutter gutter width..
33178 * @cfg {Number} maxCols maximum number of columns
33184 * @cfg {Boolean} isAutoInitial defalut true
33186 isAutoInitial : true,
33191 * @cfg {Boolean} isHorizontal defalut false
33193 isHorizontal : false,
33195 currentSize : null,
33201 bricks: null, //CompositeElement
33205 _isLayoutInited : false,
33207 // isAlternative : false, // only use for vertical layout...
33210 * @cfg {Number} alternativePadWidth padding below box..
33212 alternativePadWidth : 50,
33214 selectedBrick : [],
33216 getAutoCreate : function(){
33218 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
33222 cls: 'blog-masonary-wrapper ' + this.cls,
33224 cls : 'mas-boxes masonary'
33231 getChildContainer: function( )
33233 if (this.boxesEl) {
33234 return this.boxesEl;
33237 this.boxesEl = this.el.select('.mas-boxes').first();
33239 return this.boxesEl;
33243 initEvents : function()
33247 if(this.isAutoInitial){
33248 Roo.log('hook children rendered');
33249 this.on('childrenrendered', function() {
33250 Roo.log('children rendered');
33256 initial : function()
33258 this.selectedBrick = [];
33260 this.currentSize = this.el.getBox(true);
33262 Roo.EventManager.onWindowResize(this.resize, this);
33264 if(!this.isAutoInitial){
33272 //this.layout.defer(500,this);
33276 resize : function()
33278 var cs = this.el.getBox(true);
33281 this.currentSize.width == cs.width &&
33282 this.currentSize.x == cs.x &&
33283 this.currentSize.height == cs.height &&
33284 this.currentSize.y == cs.y
33286 Roo.log("no change in with or X or Y");
33290 this.currentSize = cs;
33296 layout : function()
33298 this._resetLayout();
33300 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33302 this.layoutItems( isInstant );
33304 this._isLayoutInited = true;
33306 this.fireEvent('layout', this);
33310 _resetLayout : function()
33312 if(this.isHorizontal){
33313 this.horizontalMeasureColumns();
33317 this.verticalMeasureColumns();
33321 verticalMeasureColumns : function()
33323 this.getContainerWidth();
33325 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33326 // this.colWidth = Math.floor(this.containerWidth * 0.8);
33330 var boxWidth = this.boxWidth + this.padWidth;
33332 if(this.containerWidth < this.boxWidth){
33333 boxWidth = this.containerWidth
33336 var containerWidth = this.containerWidth;
33338 var cols = Math.floor(containerWidth / boxWidth);
33340 this.cols = Math.max( cols, 1 );
33342 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33344 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
33346 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
33348 this.colWidth = boxWidth + avail - this.padWidth;
33350 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
33351 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
33354 horizontalMeasureColumns : function()
33356 this.getContainerWidth();
33358 var boxWidth = this.boxWidth;
33360 if(this.containerWidth < boxWidth){
33361 boxWidth = this.containerWidth;
33364 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
33366 this.el.setHeight(boxWidth);
33370 getContainerWidth : function()
33372 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33375 layoutItems : function( isInstant )
33377 Roo.log(this.bricks);
33379 var items = Roo.apply([], this.bricks);
33381 if(this.isHorizontal){
33382 this._horizontalLayoutItems( items , isInstant );
33386 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33387 // this._verticalAlternativeLayoutItems( items , isInstant );
33391 this._verticalLayoutItems( items , isInstant );
33395 _verticalLayoutItems : function ( items , isInstant)
33397 if ( !items || !items.length ) {
33402 ['xs', 'xs', 'xs', 'tall'],
33403 ['xs', 'xs', 'tall'],
33404 ['xs', 'xs', 'sm'],
33405 ['xs', 'xs', 'xs'],
33411 ['sm', 'xs', 'xs'],
33415 ['tall', 'xs', 'xs', 'xs'],
33416 ['tall', 'xs', 'xs'],
33428 Roo.each(items, function(item, k){
33430 switch (item.size) {
33431 // these layouts take up a full box,
33442 boxes.push([item]);
33465 var filterPattern = function(box, length)
33473 var pattern = box.slice(0, length);
33477 Roo.each(pattern, function(i){
33478 format.push(i.size);
33481 Roo.each(standard, function(s){
33483 if(String(s) != String(format)){
33492 if(!match && length == 1){
33497 filterPattern(box, length - 1);
33501 queue.push(pattern);
33503 box = box.slice(length, box.length);
33505 filterPattern(box, 4);
33511 Roo.each(boxes, function(box, k){
33517 if(box.length == 1){
33522 filterPattern(box, 4);
33526 this._processVerticalLayoutQueue( queue, isInstant );
33530 // _verticalAlternativeLayoutItems : function( items , isInstant )
33532 // if ( !items || !items.length ) {
33536 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
33540 _horizontalLayoutItems : function ( items , isInstant)
33542 if ( !items || !items.length || items.length < 3) {
33548 var eItems = items.slice(0, 3);
33550 items = items.slice(3, items.length);
33553 ['xs', 'xs', 'xs', 'wide'],
33554 ['xs', 'xs', 'wide'],
33555 ['xs', 'xs', 'sm'],
33556 ['xs', 'xs', 'xs'],
33562 ['sm', 'xs', 'xs'],
33566 ['wide', 'xs', 'xs', 'xs'],
33567 ['wide', 'xs', 'xs'],
33580 Roo.each(items, function(item, k){
33582 switch (item.size) {
33593 boxes.push([item]);
33617 var filterPattern = function(box, length)
33625 var pattern = box.slice(0, length);
33629 Roo.each(pattern, function(i){
33630 format.push(i.size);
33633 Roo.each(standard, function(s){
33635 if(String(s) != String(format)){
33644 if(!match && length == 1){
33649 filterPattern(box, length - 1);
33653 queue.push(pattern);
33655 box = box.slice(length, box.length);
33657 filterPattern(box, 4);
33663 Roo.each(boxes, function(box, k){
33669 if(box.length == 1){
33674 filterPattern(box, 4);
33681 var pos = this.el.getBox(true);
33685 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33687 var hit_end = false;
33689 Roo.each(queue, function(box){
33693 Roo.each(box, function(b){
33695 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33705 Roo.each(box, function(b){
33707 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33710 mx = Math.max(mx, b.x);
33714 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
33718 Roo.each(box, function(b){
33720 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33734 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
33737 /** Sets position of item in DOM
33738 * @param {Element} item
33739 * @param {Number} x - horizontal position
33740 * @param {Number} y - vertical position
33741 * @param {Boolean} isInstant - disables transitions
33743 _processVerticalLayoutQueue : function( queue, isInstant )
33745 var pos = this.el.getBox(true);
33750 for (var i = 0; i < this.cols; i++){
33754 Roo.each(queue, function(box, k){
33756 var col = k % this.cols;
33758 Roo.each(box, function(b,kk){
33760 b.el.position('absolute');
33762 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33763 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33765 if(b.size == 'md-left' || b.size == 'md-right'){
33766 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33767 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33770 b.el.setWidth(width);
33771 b.el.setHeight(height);
33773 b.el.select('iframe',true).setSize(width,height);
33777 for (var i = 0; i < this.cols; i++){
33779 if(maxY[i] < maxY[col]){
33784 col = Math.min(col, i);
33788 x = pos.x + col * (this.colWidth + this.padWidth);
33792 var positions = [];
33794 switch (box.length){
33796 positions = this.getVerticalOneBoxColPositions(x, y, box);
33799 positions = this.getVerticalTwoBoxColPositions(x, y, box);
33802 positions = this.getVerticalThreeBoxColPositions(x, y, box);
33805 positions = this.getVerticalFourBoxColPositions(x, y, box);
33811 Roo.each(box, function(b,kk){
33813 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33815 var sz = b.el.getSize();
33817 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
33825 for (var i = 0; i < this.cols; i++){
33826 mY = Math.max(mY, maxY[i]);
33829 this.el.setHeight(mY - pos.y);
33833 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
33835 // var pos = this.el.getBox(true);
33838 // var maxX = pos.right;
33840 // var maxHeight = 0;
33842 // Roo.each(items, function(item, k){
33846 // item.el.position('absolute');
33848 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
33850 // item.el.setWidth(width);
33852 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
33854 // item.el.setHeight(height);
33857 // item.el.setXY([x, y], isInstant ? false : true);
33859 // item.el.setXY([maxX - width, y], isInstant ? false : true);
33862 // y = y + height + this.alternativePadWidth;
33864 // maxHeight = maxHeight + height + this.alternativePadWidth;
33868 // this.el.setHeight(maxHeight);
33872 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
33874 var pos = this.el.getBox(true);
33879 var maxX = pos.right;
33881 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
33883 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33885 Roo.each(queue, function(box, k){
33887 Roo.each(box, function(b, kk){
33889 b.el.position('absolute');
33891 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33892 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33894 if(b.size == 'md-left' || b.size == 'md-right'){
33895 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33896 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33899 b.el.setWidth(width);
33900 b.el.setHeight(height);
33908 var positions = [];
33910 switch (box.length){
33912 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
33915 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33918 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33921 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33927 Roo.each(box, function(b,kk){
33929 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33931 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33939 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33941 Roo.each(eItems, function(b,k){
33943 b.size = (k == 0) ? 'sm' : 'xs';
33944 b.x = (k == 0) ? 2 : 1;
33945 b.y = (k == 0) ? 2 : 1;
33947 b.el.position('absolute');
33949 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33951 b.el.setWidth(width);
33953 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33955 b.el.setHeight(height);
33959 var positions = [];
33962 x : maxX - this.unitWidth * 2 - this.gutter,
33967 x : maxX - this.unitWidth,
33968 y : minY + (this.unitWidth + this.gutter) * 2
33972 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33976 Roo.each(eItems, function(b,k){
33978 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33984 getVerticalOneBoxColPositions : function(x, y, box)
33988 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33990 if(box[0].size == 'md-left'){
33994 if(box[0].size == 'md-right'){
33999 x : x + (this.unitWidth + this.gutter) * rand,
34006 getVerticalTwoBoxColPositions : function(x, y, box)
34010 if(box[0].size == 'xs'){
34014 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
34018 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
34032 x : x + (this.unitWidth + this.gutter) * 2,
34033 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
34040 getVerticalThreeBoxColPositions : function(x, y, box)
34044 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34052 x : x + (this.unitWidth + this.gutter) * 1,
34057 x : x + (this.unitWidth + this.gutter) * 2,
34065 if(box[0].size == 'xs' && box[1].size == 'xs'){
34074 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
34078 x : x + (this.unitWidth + this.gutter) * 1,
34092 x : x + (this.unitWidth + this.gutter) * 2,
34097 x : x + (this.unitWidth + this.gutter) * 2,
34098 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
34105 getVerticalFourBoxColPositions : function(x, y, box)
34109 if(box[0].size == 'xs'){
34118 y : y + (this.unitHeight + this.gutter) * 1
34123 y : y + (this.unitHeight + this.gutter) * 2
34127 x : x + (this.unitWidth + this.gutter) * 1,
34141 x : x + (this.unitWidth + this.gutter) * 2,
34146 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
34147 y : y + (this.unitHeight + this.gutter) * 1
34151 x : x + (this.unitWidth + this.gutter) * 2,
34152 y : y + (this.unitWidth + this.gutter) * 2
34159 getHorizontalOneBoxColPositions : function(maxX, minY, box)
34163 if(box[0].size == 'md-left'){
34165 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34172 if(box[0].size == 'md-right'){
34174 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34175 y : minY + (this.unitWidth + this.gutter) * 1
34181 var rand = Math.floor(Math.random() * (4 - box[0].y));
34184 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34185 y : minY + (this.unitWidth + this.gutter) * rand
34192 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
34196 if(box[0].size == 'xs'){
34199 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34204 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34205 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
34213 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34218 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34219 y : minY + (this.unitWidth + this.gutter) * 2
34226 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
34230 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34233 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34238 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34239 y : minY + (this.unitWidth + this.gutter) * 1
34243 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34244 y : minY + (this.unitWidth + this.gutter) * 2
34251 if(box[0].size == 'xs' && box[1].size == 'xs'){
34254 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34259 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34264 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34265 y : minY + (this.unitWidth + this.gutter) * 1
34273 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34278 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34279 y : minY + (this.unitWidth + this.gutter) * 2
34283 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34284 y : minY + (this.unitWidth + this.gutter) * 2
34291 getHorizontalFourBoxColPositions : function(maxX, minY, box)
34295 if(box[0].size == 'xs'){
34298 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34303 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34308 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),
34313 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
34314 y : minY + (this.unitWidth + this.gutter) * 1
34322 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34327 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34328 y : minY + (this.unitWidth + this.gutter) * 2
34332 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34333 y : minY + (this.unitWidth + this.gutter) * 2
34337 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),
34338 y : minY + (this.unitWidth + this.gutter) * 2
34346 * remove a Masonry Brick
34347 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
34349 removeBrick : function(brick_id)
34355 for (var i = 0; i<this.bricks.length; i++) {
34356 if (this.bricks[i].id == brick_id) {
34357 this.bricks.splice(i,1);
34358 this.el.dom.removeChild(Roo.get(brick_id).dom);
34365 * adds a Masonry Brick
34366 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34368 addBrick : function(cfg)
34370 var cn = new Roo.bootstrap.MasonryBrick(cfg);
34371 //this.register(cn);
34372 cn.parentId = this.id;
34373 cn.render(this.el);
34378 * register a Masonry Brick
34379 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34382 register : function(brick)
34384 this.bricks.push(brick);
34385 brick.masonryId = this.id;
34389 * clear all the Masonry Brick
34391 clearAll : function()
34394 //this.getChildContainer().dom.innerHTML = "";
34395 this.el.dom.innerHTML = '';
34398 getSelected : function()
34400 if (!this.selectedBrick) {
34404 return this.selectedBrick;
34408 Roo.apply(Roo.bootstrap.LayoutMasonry, {
34412 * register a Masonry Layout
34413 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
34416 register : function(layout)
34418 this.groups[layout.id] = layout;
34421 * fetch a Masonry Layout based on the masonry layout ID
34422 * @param {string} the masonry layout to add
34423 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
34426 get: function(layout_id) {
34427 if (typeof(this.groups[layout_id]) == 'undefined') {
34430 return this.groups[layout_id] ;
34442 * http://masonry.desandro.com
34444 * The idea is to render all the bricks based on vertical width...
34446 * The original code extends 'outlayer' - we might need to use that....
34452 * @class Roo.bootstrap.LayoutMasonryAuto
34453 * @extends Roo.bootstrap.Component
34454 * Bootstrap Layout Masonry class
34457 * Create a new Element
34458 * @param {Object} config The config object
34461 Roo.bootstrap.LayoutMasonryAuto = function(config){
34462 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
34465 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
34468 * @cfg {Boolean} isFitWidth - resize the width..
34470 isFitWidth : false, // options..
34472 * @cfg {Boolean} isOriginLeft = left align?
34474 isOriginLeft : true,
34476 * @cfg {Boolean} isOriginTop = top align?
34478 isOriginTop : false,
34480 * @cfg {Boolean} isLayoutInstant = no animation?
34482 isLayoutInstant : false, // needed?
34484 * @cfg {Boolean} isResizingContainer = not sure if this is used..
34486 isResizingContainer : true,
34488 * @cfg {Number} columnWidth width of the columns
34494 * @cfg {Number} maxCols maximum number of columns
34499 * @cfg {Number} padHeight padding below box..
34505 * @cfg {Boolean} isAutoInitial defalut true
34508 isAutoInitial : true,
34514 initialColumnWidth : 0,
34515 currentSize : null,
34517 colYs : null, // array.
34524 bricks: null, //CompositeElement
34525 cols : 0, // array?
34526 // element : null, // wrapped now this.el
34527 _isLayoutInited : null,
34530 getAutoCreate : function(){
34534 cls: 'blog-masonary-wrapper ' + this.cls,
34536 cls : 'mas-boxes masonary'
34543 getChildContainer: function( )
34545 if (this.boxesEl) {
34546 return this.boxesEl;
34549 this.boxesEl = this.el.select('.mas-boxes').first();
34551 return this.boxesEl;
34555 initEvents : function()
34559 if(this.isAutoInitial){
34560 Roo.log('hook children rendered');
34561 this.on('childrenrendered', function() {
34562 Roo.log('children rendered');
34569 initial : function()
34571 this.reloadItems();
34573 this.currentSize = this.el.getBox(true);
34575 /// was window resize... - let's see if this works..
34576 Roo.EventManager.onWindowResize(this.resize, this);
34578 if(!this.isAutoInitial){
34583 this.layout.defer(500,this);
34586 reloadItems: function()
34588 this.bricks = this.el.select('.masonry-brick', true);
34590 this.bricks.each(function(b) {
34591 //Roo.log(b.getSize());
34592 if (!b.attr('originalwidth')) {
34593 b.attr('originalwidth', b.getSize().width);
34598 Roo.log(this.bricks.elements.length);
34601 resize : function()
34604 var cs = this.el.getBox(true);
34606 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
34607 Roo.log("no change in with or X");
34610 this.currentSize = cs;
34614 layout : function()
34617 this._resetLayout();
34618 //this._manageStamps();
34620 // don't animate first layout
34621 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
34622 this.layoutItems( isInstant );
34624 // flag for initalized
34625 this._isLayoutInited = true;
34628 layoutItems : function( isInstant )
34630 //var items = this._getItemsForLayout( this.items );
34631 // original code supports filtering layout items.. we just ignore it..
34633 this._layoutItems( this.bricks , isInstant );
34635 this._postLayout();
34637 _layoutItems : function ( items , isInstant)
34639 //this.fireEvent( 'layout', this, items );
34642 if ( !items || !items.elements.length ) {
34643 // no items, emit event with empty array
34648 items.each(function(item) {
34649 Roo.log("layout item");
34651 // get x/y object from method
34652 var position = this._getItemLayoutPosition( item );
34654 position.item = item;
34655 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
34656 queue.push( position );
34659 this._processLayoutQueue( queue );
34661 /** Sets position of item in DOM
34662 * @param {Element} item
34663 * @param {Number} x - horizontal position
34664 * @param {Number} y - vertical position
34665 * @param {Boolean} isInstant - disables transitions
34667 _processLayoutQueue : function( queue )
34669 for ( var i=0, len = queue.length; i < len; i++ ) {
34670 var obj = queue[i];
34671 obj.item.position('absolute');
34672 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
34678 * Any logic you want to do after each layout,
34679 * i.e. size the container
34681 _postLayout : function()
34683 this.resizeContainer();
34686 resizeContainer : function()
34688 if ( !this.isResizingContainer ) {
34691 var size = this._getContainerSize();
34693 this.el.setSize(size.width,size.height);
34694 this.boxesEl.setSize(size.width,size.height);
34700 _resetLayout : function()
34702 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
34703 this.colWidth = this.el.getWidth();
34704 //this.gutter = this.el.getWidth();
34706 this.measureColumns();
34712 this.colYs.push( 0 );
34718 measureColumns : function()
34720 this.getContainerWidth();
34721 // if columnWidth is 0, default to outerWidth of first item
34722 if ( !this.columnWidth ) {
34723 var firstItem = this.bricks.first();
34724 Roo.log(firstItem);
34725 this.columnWidth = this.containerWidth;
34726 if (firstItem && firstItem.attr('originalwidth') ) {
34727 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
34729 // columnWidth fall back to item of first element
34730 Roo.log("set column width?");
34731 this.initialColumnWidth = this.columnWidth ;
34733 // if first elem has no width, default to size of container
34738 if (this.initialColumnWidth) {
34739 this.columnWidth = this.initialColumnWidth;
34744 // column width is fixed at the top - however if container width get's smaller we should
34747 // this bit calcs how man columns..
34749 var columnWidth = this.columnWidth += this.gutter;
34751 // calculate columns
34752 var containerWidth = this.containerWidth + this.gutter;
34754 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
34755 // fix rounding errors, typically with gutters
34756 var excess = columnWidth - containerWidth % columnWidth;
34759 // if overshoot is less than a pixel, round up, otherwise floor it
34760 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
34761 cols = Math[ mathMethod ]( cols );
34762 this.cols = Math.max( cols, 1 );
34763 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
34765 // padding positioning..
34766 var totalColWidth = this.cols * this.columnWidth;
34767 var padavail = this.containerWidth - totalColWidth;
34768 // so for 2 columns - we need 3 'pads'
34770 var padNeeded = (1+this.cols) * this.padWidth;
34772 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
34774 this.columnWidth += padExtra
34775 //this.padWidth = Math.floor(padavail / ( this.cols));
34777 // adjust colum width so that padding is fixed??
34779 // we have 3 columns ... total = width * 3
34780 // we have X left over... that should be used by
34782 //if (this.expandC) {
34790 getContainerWidth : function()
34792 /* // container is parent if fit width
34793 var container = this.isFitWidth ? this.element.parentNode : this.element;
34794 // check that this.size and size are there
34795 // IE8 triggers resize on body size change, so they might not be
34797 var size = getSize( container ); //FIXME
34798 this.containerWidth = size && size.innerWidth; //FIXME
34801 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
34805 _getItemLayoutPosition : function( item ) // what is item?
34807 // we resize the item to our columnWidth..
34809 item.setWidth(this.columnWidth);
34810 item.autoBoxAdjust = false;
34812 var sz = item.getSize();
34814 // how many columns does this brick span
34815 var remainder = this.containerWidth % this.columnWidth;
34817 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
34818 // round if off by 1 pixel, otherwise use ceil
34819 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
34820 colSpan = Math.min( colSpan, this.cols );
34822 // normally this should be '1' as we dont' currently allow multi width columns..
34824 var colGroup = this._getColGroup( colSpan );
34825 // get the minimum Y value from the columns
34826 var minimumY = Math.min.apply( Math, colGroup );
34827 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34829 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
34831 // position the brick
34833 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
34834 y: this.currentSize.y + minimumY + this.padHeight
34838 // apply setHeight to necessary columns
34839 var setHeight = minimumY + sz.height + this.padHeight;
34840 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34842 var setSpan = this.cols + 1 - colGroup.length;
34843 for ( var i = 0; i < setSpan; i++ ) {
34844 this.colYs[ shortColIndex + i ] = setHeight ;
34851 * @param {Number} colSpan - number of columns the element spans
34852 * @returns {Array} colGroup
34854 _getColGroup : function( colSpan )
34856 if ( colSpan < 2 ) {
34857 // if brick spans only one column, use all the column Ys
34862 // how many different places could this brick fit horizontally
34863 var groupCount = this.cols + 1 - colSpan;
34864 // for each group potential horizontal position
34865 for ( var i = 0; i < groupCount; i++ ) {
34866 // make an array of colY values for that one group
34867 var groupColYs = this.colYs.slice( i, i + colSpan );
34868 // and get the max value of the array
34869 colGroup[i] = Math.max.apply( Math, groupColYs );
34874 _manageStamp : function( stamp )
34876 var stampSize = stamp.getSize();
34877 var offset = stamp.getBox();
34878 // get the columns that this stamp affects
34879 var firstX = this.isOriginLeft ? offset.x : offset.right;
34880 var lastX = firstX + stampSize.width;
34881 var firstCol = Math.floor( firstX / this.columnWidth );
34882 firstCol = Math.max( 0, firstCol );
34884 var lastCol = Math.floor( lastX / this.columnWidth );
34885 // lastCol should not go over if multiple of columnWidth #425
34886 lastCol -= lastX % this.columnWidth ? 0 : 1;
34887 lastCol = Math.min( this.cols - 1, lastCol );
34889 // set colYs to bottom of the stamp
34890 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
34893 for ( var i = firstCol; i <= lastCol; i++ ) {
34894 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
34899 _getContainerSize : function()
34901 this.maxY = Math.max.apply( Math, this.colYs );
34906 if ( this.isFitWidth ) {
34907 size.width = this._getContainerFitWidth();
34913 _getContainerFitWidth : function()
34915 var unusedCols = 0;
34916 // count unused columns
34919 if ( this.colYs[i] !== 0 ) {
34924 // fit container to columns that have been used
34925 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34928 needsResizeLayout : function()
34930 var previousWidth = this.containerWidth;
34931 this.getContainerWidth();
34932 return previousWidth !== this.containerWidth;
34947 * @class Roo.bootstrap.MasonryBrick
34948 * @extends Roo.bootstrap.Component
34949 * Bootstrap MasonryBrick class
34952 * Create a new MasonryBrick
34953 * @param {Object} config The config object
34956 Roo.bootstrap.MasonryBrick = function(config){
34958 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34960 Roo.bootstrap.MasonryBrick.register(this);
34966 * When a MasonryBrick is clcik
34967 * @param {Roo.bootstrap.MasonryBrick} this
34968 * @param {Roo.EventObject} e
34974 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34977 * @cfg {String} title
34981 * @cfg {String} html
34985 * @cfg {String} bgimage
34989 * @cfg {String} videourl
34993 * @cfg {String} cls
34997 * @cfg {String} href
35001 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
35006 * @cfg {String} placetitle (center|bottom)
35011 * @cfg {Boolean} isFitContainer defalut true
35013 isFitContainer : true,
35016 * @cfg {Boolean} preventDefault defalut false
35018 preventDefault : false,
35021 * @cfg {Boolean} inverse defalut false
35023 maskInverse : false,
35025 getAutoCreate : function()
35027 if(!this.isFitContainer){
35028 return this.getSplitAutoCreate();
35031 var cls = 'masonry-brick masonry-brick-full';
35033 if(this.href.length){
35034 cls += ' masonry-brick-link';
35037 if(this.bgimage.length){
35038 cls += ' masonry-brick-image';
35041 if(this.maskInverse){
35042 cls += ' mask-inverse';
35045 if(!this.html.length && !this.maskInverse && !this.videourl.length){
35046 cls += ' enable-mask';
35050 cls += ' masonry-' + this.size + '-brick';
35053 if(this.placetitle.length){
35055 switch (this.placetitle) {
35057 cls += ' masonry-center-title';
35060 cls += ' masonry-bottom-title';
35067 if(!this.html.length && !this.bgimage.length){
35068 cls += ' masonry-center-title';
35071 if(!this.html.length && this.bgimage.length){
35072 cls += ' masonry-bottom-title';
35077 cls += ' ' + this.cls;
35081 tag: (this.href.length) ? 'a' : 'div',
35086 cls: 'masonry-brick-mask'
35090 cls: 'masonry-brick-paragraph',
35096 if(this.href.length){
35097 cfg.href = this.href;
35100 var cn = cfg.cn[1].cn;
35102 if(this.title.length){
35105 cls: 'masonry-brick-title',
35110 if(this.html.length){
35113 cls: 'masonry-brick-text',
35118 if (!this.title.length && !this.html.length) {
35119 cfg.cn[1].cls += ' hide';
35122 if(this.bgimage.length){
35125 cls: 'masonry-brick-image-view',
35130 if(this.videourl.length){
35131 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35132 // youtube support only?
35135 cls: 'masonry-brick-image-view',
35138 allowfullscreen : true
35146 getSplitAutoCreate : function()
35148 var cls = 'masonry-brick masonry-brick-split';
35150 if(this.href.length){
35151 cls += ' masonry-brick-link';
35154 if(this.bgimage.length){
35155 cls += ' masonry-brick-image';
35159 cls += ' masonry-' + this.size + '-brick';
35162 switch (this.placetitle) {
35164 cls += ' masonry-center-title';
35167 cls += ' masonry-bottom-title';
35170 if(!this.bgimage.length){
35171 cls += ' masonry-center-title';
35174 if(this.bgimage.length){
35175 cls += ' masonry-bottom-title';
35181 cls += ' ' + this.cls;
35185 tag: (this.href.length) ? 'a' : 'div',
35190 cls: 'masonry-brick-split-head',
35194 cls: 'masonry-brick-paragraph',
35201 cls: 'masonry-brick-split-body',
35207 if(this.href.length){
35208 cfg.href = this.href;
35211 if(this.title.length){
35212 cfg.cn[0].cn[0].cn.push({
35214 cls: 'masonry-brick-title',
35219 if(this.html.length){
35220 cfg.cn[1].cn.push({
35222 cls: 'masonry-brick-text',
35227 if(this.bgimage.length){
35228 cfg.cn[0].cn.push({
35230 cls: 'masonry-brick-image-view',
35235 if(this.videourl.length){
35236 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35237 // youtube support only?
35238 cfg.cn[0].cn.cn.push({
35240 cls: 'masonry-brick-image-view',
35243 allowfullscreen : true
35250 initEvents: function()
35252 switch (this.size) {
35285 this.el.on('touchstart', this.onTouchStart, this);
35286 this.el.on('touchmove', this.onTouchMove, this);
35287 this.el.on('touchend', this.onTouchEnd, this);
35288 this.el.on('contextmenu', this.onContextMenu, this);
35290 this.el.on('mouseenter' ,this.enter, this);
35291 this.el.on('mouseleave', this.leave, this);
35292 this.el.on('click', this.onClick, this);
35295 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
35296 this.parent().bricks.push(this);
35301 onClick: function(e, el)
35303 var time = this.endTimer - this.startTimer;
35304 // Roo.log(e.preventDefault());
35307 e.preventDefault();
35312 if(!this.preventDefault){
35316 e.preventDefault();
35318 if (this.activeClass != '') {
35319 this.selectBrick();
35322 this.fireEvent('click', this, e);
35325 enter: function(e, el)
35327 e.preventDefault();
35329 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35333 if(this.bgimage.length && this.html.length){
35334 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35338 leave: function(e, el)
35340 e.preventDefault();
35342 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35346 if(this.bgimage.length && this.html.length){
35347 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35351 onTouchStart: function(e, el)
35353 // e.preventDefault();
35355 this.touchmoved = false;
35357 if(!this.isFitContainer){
35361 if(!this.bgimage.length || !this.html.length){
35365 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35367 this.timer = new Date().getTime();
35371 onTouchMove: function(e, el)
35373 this.touchmoved = true;
35376 onContextMenu : function(e,el)
35378 e.preventDefault();
35379 e.stopPropagation();
35383 onTouchEnd: function(e, el)
35385 // e.preventDefault();
35387 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
35394 if(!this.bgimage.length || !this.html.length){
35396 if(this.href.length){
35397 window.location.href = this.href;
35403 if(!this.isFitContainer){
35407 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35409 window.location.href = this.href;
35412 //selection on single brick only
35413 selectBrick : function() {
35415 if (!this.parentId) {
35419 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
35420 var index = m.selectedBrick.indexOf(this.id);
35423 m.selectedBrick.splice(index,1);
35424 this.el.removeClass(this.activeClass);
35428 for(var i = 0; i < m.selectedBrick.length; i++) {
35429 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
35430 b.el.removeClass(b.activeClass);
35433 m.selectedBrick = [];
35435 m.selectedBrick.push(this.id);
35436 this.el.addClass(this.activeClass);
35440 isSelected : function(){
35441 return this.el.hasClass(this.activeClass);
35446 Roo.apply(Roo.bootstrap.MasonryBrick, {
35449 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
35451 * register a Masonry Brick
35452 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
35455 register : function(brick)
35457 //this.groups[brick.id] = brick;
35458 this.groups.add(brick.id, brick);
35461 * fetch a masonry brick based on the masonry brick ID
35462 * @param {string} the masonry brick to add
35463 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
35466 get: function(brick_id)
35468 // if (typeof(this.groups[brick_id]) == 'undefined') {
35471 // return this.groups[brick_id] ;
35473 if(this.groups.key(brick_id)) {
35474 return this.groups.key(brick_id);
35492 * @class Roo.bootstrap.Brick
35493 * @extends Roo.bootstrap.Component
35494 * Bootstrap Brick class
35497 * Create a new Brick
35498 * @param {Object} config The config object
35501 Roo.bootstrap.Brick = function(config){
35502 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
35508 * When a Brick is click
35509 * @param {Roo.bootstrap.Brick} this
35510 * @param {Roo.EventObject} e
35516 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
35519 * @cfg {String} title
35523 * @cfg {String} html
35527 * @cfg {String} bgimage
35531 * @cfg {String} cls
35535 * @cfg {String} href
35539 * @cfg {String} video
35543 * @cfg {Boolean} square
35547 getAutoCreate : function()
35549 var cls = 'roo-brick';
35551 if(this.href.length){
35552 cls += ' roo-brick-link';
35555 if(this.bgimage.length){
35556 cls += ' roo-brick-image';
35559 if(!this.html.length && !this.bgimage.length){
35560 cls += ' roo-brick-center-title';
35563 if(!this.html.length && this.bgimage.length){
35564 cls += ' roo-brick-bottom-title';
35568 cls += ' ' + this.cls;
35572 tag: (this.href.length) ? 'a' : 'div',
35577 cls: 'roo-brick-paragraph',
35583 if(this.href.length){
35584 cfg.href = this.href;
35587 var cn = cfg.cn[0].cn;
35589 if(this.title.length){
35592 cls: 'roo-brick-title',
35597 if(this.html.length){
35600 cls: 'roo-brick-text',
35607 if(this.bgimage.length){
35610 cls: 'roo-brick-image-view',
35618 initEvents: function()
35620 if(this.title.length || this.html.length){
35621 this.el.on('mouseenter' ,this.enter, this);
35622 this.el.on('mouseleave', this.leave, this);
35625 Roo.EventManager.onWindowResize(this.resize, this);
35627 if(this.bgimage.length){
35628 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
35629 this.imageEl.on('load', this.onImageLoad, this);
35636 onImageLoad : function()
35641 resize : function()
35643 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
35645 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
35647 if(this.bgimage.length){
35648 var image = this.el.select('.roo-brick-image-view', true).first();
35650 image.setWidth(paragraph.getWidth());
35653 image.setHeight(paragraph.getWidth());
35656 this.el.setHeight(image.getHeight());
35657 paragraph.setHeight(image.getHeight());
35663 enter: function(e, el)
35665 e.preventDefault();
35667 if(this.bgimage.length){
35668 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
35669 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
35673 leave: function(e, el)
35675 e.preventDefault();
35677 if(this.bgimage.length){
35678 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
35679 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
35694 * @class Roo.bootstrap.NumberField
35695 * @extends Roo.bootstrap.Input
35696 * Bootstrap NumberField class
35702 * Create a new NumberField
35703 * @param {Object} config The config object
35706 Roo.bootstrap.NumberField = function(config){
35707 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
35710 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
35713 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
35715 allowDecimals : true,
35717 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
35719 decimalSeparator : ".",
35721 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
35723 decimalPrecision : 2,
35725 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
35727 allowNegative : true,
35730 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
35734 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
35736 minValue : Number.NEGATIVE_INFINITY,
35738 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
35740 maxValue : Number.MAX_VALUE,
35742 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
35744 minText : "The minimum value for this field is {0}",
35746 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
35748 maxText : "The maximum value for this field is {0}",
35750 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
35751 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
35753 nanText : "{0} is not a valid number",
35755 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
35757 thousandsDelimiter : false,
35759 * @cfg {String} valueAlign alignment of value
35761 valueAlign : "left",
35763 getAutoCreate : function()
35765 var hiddenInput = {
35769 cls: 'hidden-number-input'
35773 hiddenInput.name = this.name;
35778 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
35780 this.name = hiddenInput.name;
35782 if(cfg.cn.length > 0) {
35783 cfg.cn.push(hiddenInput);
35790 initEvents : function()
35792 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
35794 var allowed = "0123456789";
35796 if(this.allowDecimals){
35797 allowed += this.decimalSeparator;
35800 if(this.allowNegative){
35804 if(this.thousandsDelimiter) {
35808 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
35810 var keyPress = function(e){
35812 var k = e.getKey();
35814 var c = e.getCharCode();
35817 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
35818 allowed.indexOf(String.fromCharCode(c)) === -1
35824 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
35828 if(allowed.indexOf(String.fromCharCode(c)) === -1){
35833 this.el.on("keypress", keyPress, this);
35836 validateValue : function(value)
35839 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
35843 var num = this.parseValue(value);
35846 this.markInvalid(String.format(this.nanText, value));
35850 if(num < this.minValue){
35851 this.markInvalid(String.format(this.minText, this.minValue));
35855 if(num > this.maxValue){
35856 this.markInvalid(String.format(this.maxText, this.maxValue));
35863 getValue : function()
35865 var v = this.hiddenEl().getValue();
35867 return this.fixPrecision(this.parseValue(v));
35870 parseValue : function(value)
35872 if(this.thousandsDelimiter) {
35874 r = new RegExp(",", "g");
35875 value = value.replace(r, "");
35878 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
35879 return isNaN(value) ? '' : value;
35882 fixPrecision : function(value)
35884 if(this.thousandsDelimiter) {
35886 r = new RegExp(",", "g");
35887 value = value.replace(r, "");
35890 var nan = isNaN(value);
35892 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
35893 return nan ? '' : value;
35895 return parseFloat(value).toFixed(this.decimalPrecision);
35898 setValue : function(v)
35900 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
35906 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
35908 this.inputEl().dom.value = (v == '') ? '' :
35909 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
35911 if(!this.allowZero && v === '0') {
35912 this.hiddenEl().dom.value = '';
35913 this.inputEl().dom.value = '';
35920 decimalPrecisionFcn : function(v)
35922 return Math.floor(v);
35925 beforeBlur : function()
35927 var v = this.parseValue(this.getRawValue());
35929 if(v || v === 0 || v === ''){
35934 hiddenEl : function()
35936 return this.el.select('input.hidden-number-input',true).first();
35948 * @class Roo.bootstrap.DocumentSlider
35949 * @extends Roo.bootstrap.Component
35950 * Bootstrap DocumentSlider class
35953 * Create a new DocumentViewer
35954 * @param {Object} config The config object
35957 Roo.bootstrap.DocumentSlider = function(config){
35958 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35965 * Fire after initEvent
35966 * @param {Roo.bootstrap.DocumentSlider} this
35971 * Fire after update
35972 * @param {Roo.bootstrap.DocumentSlider} this
35978 * @param {Roo.bootstrap.DocumentSlider} this
35984 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35990 getAutoCreate : function()
35994 cls : 'roo-document-slider',
35998 cls : 'roo-document-slider-header',
36002 cls : 'roo-document-slider-header-title'
36008 cls : 'roo-document-slider-body',
36012 cls : 'roo-document-slider-prev',
36016 cls : 'fa fa-chevron-left'
36022 cls : 'roo-document-slider-thumb',
36026 cls : 'roo-document-slider-image'
36032 cls : 'roo-document-slider-next',
36036 cls : 'fa fa-chevron-right'
36048 initEvents : function()
36050 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
36051 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
36053 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
36054 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
36056 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
36057 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
36059 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
36060 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
36062 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
36063 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
36065 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
36066 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
36068 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
36069 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
36071 this.thumbEl.on('click', this.onClick, this);
36073 this.prevIndicator.on('click', this.prev, this);
36075 this.nextIndicator.on('click', this.next, this);
36079 initial : function()
36081 if(this.files.length){
36082 this.indicator = 1;
36086 this.fireEvent('initial', this);
36089 update : function()
36091 this.imageEl.attr('src', this.files[this.indicator - 1]);
36093 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
36095 this.prevIndicator.show();
36097 if(this.indicator == 1){
36098 this.prevIndicator.hide();
36101 this.nextIndicator.show();
36103 if(this.indicator == this.files.length){
36104 this.nextIndicator.hide();
36107 this.thumbEl.scrollTo('top');
36109 this.fireEvent('update', this);
36112 onClick : function(e)
36114 e.preventDefault();
36116 this.fireEvent('click', this);
36121 e.preventDefault();
36123 this.indicator = Math.max(1, this.indicator - 1);
36130 e.preventDefault();
36132 this.indicator = Math.min(this.files.length, this.indicator + 1);
36146 * @class Roo.bootstrap.RadioSet
36147 * @extends Roo.bootstrap.Input
36148 * Bootstrap RadioSet class
36149 * @cfg {String} indicatorpos (left|right) default left
36150 * @cfg {Boolean} inline (true|false) inline the element (default true)
36151 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
36153 * Create a new RadioSet
36154 * @param {Object} config The config object
36157 Roo.bootstrap.RadioSet = function(config){
36159 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
36163 Roo.bootstrap.RadioSet.register(this);
36168 * Fires when the element is checked or unchecked.
36169 * @param {Roo.bootstrap.RadioSet} this This radio
36170 * @param {Roo.bootstrap.Radio} item The checked item
36175 * Fires when the element is click.
36176 * @param {Roo.bootstrap.RadioSet} this This radio set
36177 * @param {Roo.bootstrap.Radio} item The checked item
36178 * @param {Roo.EventObject} e The event object
36185 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
36193 indicatorpos : 'left',
36195 getAutoCreate : function()
36199 cls : 'roo-radio-set-label',
36203 html : this.fieldLabel
36207 if (Roo.bootstrap.version == 3) {
36210 if(this.indicatorpos == 'left'){
36213 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
36214 tooltip : 'This field is required'
36219 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
36220 tooltip : 'This field is required'
36226 cls : 'roo-radio-set-items'
36229 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
36231 if (align === 'left' && this.fieldLabel.length) {
36234 cls : "roo-radio-set-right",
36240 if(this.labelWidth > 12){
36241 label.style = "width: " + this.labelWidth + 'px';
36244 if(this.labelWidth < 13 && this.labelmd == 0){
36245 this.labelmd = this.labelWidth;
36248 if(this.labellg > 0){
36249 label.cls += ' col-lg-' + this.labellg;
36250 items.cls += ' col-lg-' + (12 - this.labellg);
36253 if(this.labelmd > 0){
36254 label.cls += ' col-md-' + this.labelmd;
36255 items.cls += ' col-md-' + (12 - this.labelmd);
36258 if(this.labelsm > 0){
36259 label.cls += ' col-sm-' + this.labelsm;
36260 items.cls += ' col-sm-' + (12 - this.labelsm);
36263 if(this.labelxs > 0){
36264 label.cls += ' col-xs-' + this.labelxs;
36265 items.cls += ' col-xs-' + (12 - this.labelxs);
36271 cls : 'roo-radio-set',
36275 cls : 'roo-radio-set-input',
36278 value : this.value ? this.value : ''
36285 if(this.weight.length){
36286 cfg.cls += ' roo-radio-' + this.weight;
36290 cfg.cls += ' roo-radio-set-inline';
36294 ['xs','sm','md','lg'].map(function(size){
36295 if (settings[size]) {
36296 cfg.cls += ' col-' + size + '-' + settings[size];
36304 initEvents : function()
36306 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
36307 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
36309 if(!this.fieldLabel.length){
36310 this.labelEl.hide();
36313 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
36314 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
36316 this.indicator = this.indicatorEl();
36318 if(this.indicator){
36319 this.indicator.addClass('invisible');
36322 this.originalValue = this.getValue();
36326 inputEl: function ()
36328 return this.el.select('.roo-radio-set-input', true).first();
36331 getChildContainer : function()
36333 return this.itemsEl;
36336 register : function(item)
36338 this.radioes.push(item);
36342 validate : function()
36344 if(this.getVisibilityEl().hasClass('hidden')){
36350 Roo.each(this.radioes, function(i){
36359 if(this.allowBlank) {
36363 if(this.disabled || valid){
36368 this.markInvalid();
36373 markValid : function()
36375 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36376 this.indicatorEl().removeClass('visible');
36377 this.indicatorEl().addClass('invisible');
36381 if (Roo.bootstrap.version == 3) {
36382 this.el.removeClass([this.invalidClass, this.validClass]);
36383 this.el.addClass(this.validClass);
36385 this.el.removeClass(['is-invalid','is-valid']);
36386 this.el.addClass(['is-valid']);
36388 this.fireEvent('valid', this);
36391 markInvalid : function(msg)
36393 if(this.allowBlank || this.disabled){
36397 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36398 this.indicatorEl().removeClass('invisible');
36399 this.indicatorEl().addClass('visible');
36401 if (Roo.bootstrap.version == 3) {
36402 this.el.removeClass([this.invalidClass, this.validClass]);
36403 this.el.addClass(this.invalidClass);
36405 this.el.removeClass(['is-invalid','is-valid']);
36406 this.el.addClass(['is-invalid']);
36409 this.fireEvent('invalid', this, msg);
36413 setValue : function(v, suppressEvent)
36415 if(this.value === v){
36422 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
36425 Roo.each(this.radioes, function(i){
36427 i.el.removeClass('checked');
36430 Roo.each(this.radioes, function(i){
36432 if(i.value === v || i.value.toString() === v.toString()){
36434 i.el.addClass('checked');
36436 if(suppressEvent !== true){
36437 this.fireEvent('check', this, i);
36448 clearInvalid : function(){
36450 if(!this.el || this.preventMark){
36454 this.el.removeClass([this.invalidClass]);
36456 this.fireEvent('valid', this);
36461 Roo.apply(Roo.bootstrap.RadioSet, {
36465 register : function(set)
36467 this.groups[set.name] = set;
36470 get: function(name)
36472 if (typeof(this.groups[name]) == 'undefined') {
36476 return this.groups[name] ;
36482 * Ext JS Library 1.1.1
36483 * Copyright(c) 2006-2007, Ext JS, LLC.
36485 * Originally Released Under LGPL - original licence link has changed is not relivant.
36488 * <script type="text/javascript">
36493 * @class Roo.bootstrap.SplitBar
36494 * @extends Roo.util.Observable
36495 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
36499 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
36500 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
36501 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
36502 split.minSize = 100;
36503 split.maxSize = 600;
36504 split.animate = true;
36505 split.on('moved', splitterMoved);
36508 * Create a new SplitBar
36509 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
36510 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
36511 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36512 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
36513 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
36514 position of the SplitBar).
36516 Roo.bootstrap.SplitBar = function(cfg){
36521 // dragElement : elm
36522 // resizingElement: el,
36524 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
36525 // placement : Roo.bootstrap.SplitBar.LEFT ,
36526 // existingProxy ???
36529 this.el = Roo.get(cfg.dragElement, true);
36530 this.el.dom.unselectable = "on";
36532 this.resizingEl = Roo.get(cfg.resizingElement, true);
36536 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36537 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
36540 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
36543 * The minimum size of the resizing element. (Defaults to 0)
36549 * The maximum size of the resizing element. (Defaults to 2000)
36552 this.maxSize = 2000;
36555 * Whether to animate the transition to the new size
36558 this.animate = false;
36561 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
36564 this.useShim = false;
36569 if(!cfg.existingProxy){
36571 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
36573 this.proxy = Roo.get(cfg.existingProxy).dom;
36576 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
36579 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
36582 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
36585 this.dragSpecs = {};
36588 * @private The adapter to use to positon and resize elements
36590 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36591 this.adapter.init(this);
36593 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36595 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
36596 this.el.addClass("roo-splitbar-h");
36599 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
36600 this.el.addClass("roo-splitbar-v");
36606 * Fires when the splitter is moved (alias for {@link #event-moved})
36607 * @param {Roo.bootstrap.SplitBar} this
36608 * @param {Number} newSize the new width or height
36613 * Fires when the splitter is moved
36614 * @param {Roo.bootstrap.SplitBar} this
36615 * @param {Number} newSize the new width or height
36619 * @event beforeresize
36620 * Fires before the splitter is dragged
36621 * @param {Roo.bootstrap.SplitBar} this
36623 "beforeresize" : true,
36625 "beforeapply" : true
36628 Roo.util.Observable.call(this);
36631 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
36632 onStartProxyDrag : function(x, y){
36633 this.fireEvent("beforeresize", this);
36635 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
36637 o.enableDisplayMode("block");
36638 // all splitbars share the same overlay
36639 Roo.bootstrap.SplitBar.prototype.overlay = o;
36641 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36642 this.overlay.show();
36643 Roo.get(this.proxy).setDisplayed("block");
36644 var size = this.adapter.getElementSize(this);
36645 this.activeMinSize = this.getMinimumSize();;
36646 this.activeMaxSize = this.getMaximumSize();;
36647 var c1 = size - this.activeMinSize;
36648 var c2 = Math.max(this.activeMaxSize - size, 0);
36649 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36650 this.dd.resetConstraints();
36651 this.dd.setXConstraint(
36652 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
36653 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
36655 this.dd.setYConstraint(0, 0);
36657 this.dd.resetConstraints();
36658 this.dd.setXConstraint(0, 0);
36659 this.dd.setYConstraint(
36660 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
36661 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
36664 this.dragSpecs.startSize = size;
36665 this.dragSpecs.startPoint = [x, y];
36666 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
36670 * @private Called after the drag operation by the DDProxy
36672 onEndProxyDrag : function(e){
36673 Roo.get(this.proxy).setDisplayed(false);
36674 var endPoint = Roo.lib.Event.getXY(e);
36676 this.overlay.hide();
36679 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36680 newSize = this.dragSpecs.startSize +
36681 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
36682 endPoint[0] - this.dragSpecs.startPoint[0] :
36683 this.dragSpecs.startPoint[0] - endPoint[0]
36686 newSize = this.dragSpecs.startSize +
36687 (this.placement == Roo.bootstrap.SplitBar.TOP ?
36688 endPoint[1] - this.dragSpecs.startPoint[1] :
36689 this.dragSpecs.startPoint[1] - endPoint[1]
36692 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
36693 if(newSize != this.dragSpecs.startSize){
36694 if(this.fireEvent('beforeapply', this, newSize) !== false){
36695 this.adapter.setElementSize(this, newSize);
36696 this.fireEvent("moved", this, newSize);
36697 this.fireEvent("resize", this, newSize);
36703 * Get the adapter this SplitBar uses
36704 * @return The adapter object
36706 getAdapter : function(){
36707 return this.adapter;
36711 * Set the adapter this SplitBar uses
36712 * @param {Object} adapter A SplitBar adapter object
36714 setAdapter : function(adapter){
36715 this.adapter = adapter;
36716 this.adapter.init(this);
36720 * Gets the minimum size for the resizing element
36721 * @return {Number} The minimum size
36723 getMinimumSize : function(){
36724 return this.minSize;
36728 * Sets the minimum size for the resizing element
36729 * @param {Number} minSize The minimum size
36731 setMinimumSize : function(minSize){
36732 this.minSize = minSize;
36736 * Gets the maximum size for the resizing element
36737 * @return {Number} The maximum size
36739 getMaximumSize : function(){
36740 return this.maxSize;
36744 * Sets the maximum size for the resizing element
36745 * @param {Number} maxSize The maximum size
36747 setMaximumSize : function(maxSize){
36748 this.maxSize = maxSize;
36752 * Sets the initialize size for the resizing element
36753 * @param {Number} size The initial size
36755 setCurrentSize : function(size){
36756 var oldAnimate = this.animate;
36757 this.animate = false;
36758 this.adapter.setElementSize(this, size);
36759 this.animate = oldAnimate;
36763 * Destroy this splitbar.
36764 * @param {Boolean} removeEl True to remove the element
36766 destroy : function(removeEl){
36768 this.shim.remove();
36771 this.proxy.parentNode.removeChild(this.proxy);
36779 * @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.
36781 Roo.bootstrap.SplitBar.createProxy = function(dir){
36782 var proxy = new Roo.Element(document.createElement("div"));
36783 proxy.unselectable();
36784 var cls = 'roo-splitbar-proxy';
36785 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
36786 document.body.appendChild(proxy.dom);
36791 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
36792 * Default Adapter. It assumes the splitter and resizing element are not positioned
36793 * elements and only gets/sets the width of the element. Generally used for table based layouts.
36795 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
36798 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
36799 // do nothing for now
36800 init : function(s){
36804 * Called before drag operations to get the current size of the resizing element.
36805 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36807 getElementSize : function(s){
36808 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36809 return s.resizingEl.getWidth();
36811 return s.resizingEl.getHeight();
36816 * Called after drag operations to set the size of the resizing element.
36817 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36818 * @param {Number} newSize The new size to set
36819 * @param {Function} onComplete A function to be invoked when resizing is complete
36821 setElementSize : function(s, newSize, onComplete){
36822 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36824 s.resizingEl.setWidth(newSize);
36826 onComplete(s, newSize);
36829 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
36834 s.resizingEl.setHeight(newSize);
36836 onComplete(s, newSize);
36839 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
36846 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
36847 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
36848 * Adapter that moves the splitter element to align with the resized sizing element.
36849 * Used with an absolute positioned SplitBar.
36850 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
36851 * document.body, make sure you assign an id to the body element.
36853 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
36854 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36855 this.container = Roo.get(container);
36858 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
36859 init : function(s){
36860 this.basic.init(s);
36863 getElementSize : function(s){
36864 return this.basic.getElementSize(s);
36867 setElementSize : function(s, newSize, onComplete){
36868 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
36871 moveSplitter : function(s){
36872 var yes = Roo.bootstrap.SplitBar;
36873 switch(s.placement){
36875 s.el.setX(s.resizingEl.getRight());
36878 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
36881 s.el.setY(s.resizingEl.getBottom());
36884 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
36891 * Orientation constant - Create a vertical SplitBar
36895 Roo.bootstrap.SplitBar.VERTICAL = 1;
36898 * Orientation constant - Create a horizontal SplitBar
36902 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
36905 * Placement constant - The resizing element is to the left of the splitter element
36909 Roo.bootstrap.SplitBar.LEFT = 1;
36912 * Placement constant - The resizing element is to the right of the splitter element
36916 Roo.bootstrap.SplitBar.RIGHT = 2;
36919 * Placement constant - The resizing element is positioned above the splitter element
36923 Roo.bootstrap.SplitBar.TOP = 3;
36926 * Placement constant - The resizing element is positioned under splitter element
36930 Roo.bootstrap.SplitBar.BOTTOM = 4;
36931 Roo.namespace("Roo.bootstrap.layout");/*
36933 * Ext JS Library 1.1.1
36934 * Copyright(c) 2006-2007, Ext JS, LLC.
36936 * Originally Released Under LGPL - original licence link has changed is not relivant.
36939 * <script type="text/javascript">
36943 * @class Roo.bootstrap.layout.Manager
36944 * @extends Roo.bootstrap.Component
36945 * Base class for layout managers.
36947 Roo.bootstrap.layout.Manager = function(config)
36949 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36955 /** false to disable window resize monitoring @type Boolean */
36956 this.monitorWindowResize = true;
36961 * Fires when a layout is performed.
36962 * @param {Roo.LayoutManager} this
36966 * @event regionresized
36967 * Fires when the user resizes a region.
36968 * @param {Roo.LayoutRegion} region The resized region
36969 * @param {Number} newSize The new size (width for east/west, height for north/south)
36971 "regionresized" : true,
36973 * @event regioncollapsed
36974 * Fires when a region is collapsed.
36975 * @param {Roo.LayoutRegion} region The collapsed region
36977 "regioncollapsed" : true,
36979 * @event regionexpanded
36980 * Fires when a region is expanded.
36981 * @param {Roo.LayoutRegion} region The expanded region
36983 "regionexpanded" : true
36985 this.updating = false;
36988 this.el = Roo.get(config.el);
36994 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36999 monitorWindowResize : true,
37005 onRender : function(ct, position)
37008 this.el = Roo.get(ct);
37011 //this.fireEvent('render',this);
37015 initEvents: function()
37019 // ie scrollbar fix
37020 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
37021 document.body.scroll = "no";
37022 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
37023 this.el.position('relative');
37025 this.id = this.el.id;
37026 this.el.addClass("roo-layout-container");
37027 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
37028 if(this.el.dom != document.body ) {
37029 this.el.on('resize', this.layout,this);
37030 this.el.on('show', this.layout,this);
37036 * Returns true if this layout is currently being updated
37037 * @return {Boolean}
37039 isUpdating : function(){
37040 return this.updating;
37044 * Suspend the LayoutManager from doing auto-layouts while
37045 * making multiple add or remove calls
37047 beginUpdate : function(){
37048 this.updating = true;
37052 * Restore auto-layouts and optionally disable the manager from performing a layout
37053 * @param {Boolean} noLayout true to disable a layout update
37055 endUpdate : function(noLayout){
37056 this.updating = false;
37062 layout: function(){
37066 onRegionResized : function(region, newSize){
37067 this.fireEvent("regionresized", region, newSize);
37071 onRegionCollapsed : function(region){
37072 this.fireEvent("regioncollapsed", region);
37075 onRegionExpanded : function(region){
37076 this.fireEvent("regionexpanded", region);
37080 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
37081 * performs box-model adjustments.
37082 * @return {Object} The size as an object {width: (the width), height: (the height)}
37084 getViewSize : function()
37087 if(this.el.dom != document.body){
37088 size = this.el.getSize();
37090 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
37092 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
37093 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37098 * Returns the Element this layout is bound to.
37099 * @return {Roo.Element}
37101 getEl : function(){
37106 * Returns the specified region.
37107 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
37108 * @return {Roo.LayoutRegion}
37110 getRegion : function(target){
37111 return this.regions[target.toLowerCase()];
37114 onWindowResize : function(){
37115 if(this.monitorWindowResize){
37122 * Ext JS Library 1.1.1
37123 * Copyright(c) 2006-2007, Ext JS, LLC.
37125 * Originally Released Under LGPL - original licence link has changed is not relivant.
37128 * <script type="text/javascript">
37131 * @class Roo.bootstrap.layout.Border
37132 * @extends Roo.bootstrap.layout.Manager
37133 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
37134 * please see: examples/bootstrap/nested.html<br><br>
37136 <b>The container the layout is rendered into can be either the body element or any other element.
37137 If it is not the body element, the container needs to either be an absolute positioned element,
37138 or you will need to add "position:relative" to the css of the container. You will also need to specify
37139 the container size if it is not the body element.</b>
37142 * Create a new Border
37143 * @param {Object} config Configuration options
37145 Roo.bootstrap.layout.Border = function(config){
37146 config = config || {};
37147 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
37151 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37152 if(config[region]){
37153 config[region].region = region;
37154 this.addRegion(config[region]);
37160 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
37162 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
37164 parent : false, // this might point to a 'nest' or a ???
37167 * Creates and adds a new region if it doesn't already exist.
37168 * @param {String} target The target region key (north, south, east, west or center).
37169 * @param {Object} config The regions config object
37170 * @return {BorderLayoutRegion} The new region
37172 addRegion : function(config)
37174 if(!this.regions[config.region]){
37175 var r = this.factory(config);
37176 this.bindRegion(r);
37178 return this.regions[config.region];
37182 bindRegion : function(r){
37183 this.regions[r.config.region] = r;
37185 r.on("visibilitychange", this.layout, this);
37186 r.on("paneladded", this.layout, this);
37187 r.on("panelremoved", this.layout, this);
37188 r.on("invalidated", this.layout, this);
37189 r.on("resized", this.onRegionResized, this);
37190 r.on("collapsed", this.onRegionCollapsed, this);
37191 r.on("expanded", this.onRegionExpanded, this);
37195 * Performs a layout update.
37197 layout : function()
37199 if(this.updating) {
37203 // render all the rebions if they have not been done alreayd?
37204 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37205 if(this.regions[region] && !this.regions[region].bodyEl){
37206 this.regions[region].onRender(this.el)
37210 var size = this.getViewSize();
37211 var w = size.width;
37212 var h = size.height;
37217 //var x = 0, y = 0;
37219 var rs = this.regions;
37220 var north = rs["north"];
37221 var south = rs["south"];
37222 var west = rs["west"];
37223 var east = rs["east"];
37224 var center = rs["center"];
37225 //if(this.hideOnLayout){ // not supported anymore
37226 //c.el.setStyle("display", "none");
37228 if(north && north.isVisible()){
37229 var b = north.getBox();
37230 var m = north.getMargins();
37231 b.width = w - (m.left+m.right);
37234 centerY = b.height + b.y + m.bottom;
37235 centerH -= centerY;
37236 north.updateBox(this.safeBox(b));
37238 if(south && south.isVisible()){
37239 var b = south.getBox();
37240 var m = south.getMargins();
37241 b.width = w - (m.left+m.right);
37243 var totalHeight = (b.height + m.top + m.bottom);
37244 b.y = h - totalHeight + m.top;
37245 centerH -= totalHeight;
37246 south.updateBox(this.safeBox(b));
37248 if(west && west.isVisible()){
37249 var b = west.getBox();
37250 var m = west.getMargins();
37251 b.height = centerH - (m.top+m.bottom);
37253 b.y = centerY + m.top;
37254 var totalWidth = (b.width + m.left + m.right);
37255 centerX += totalWidth;
37256 centerW -= totalWidth;
37257 west.updateBox(this.safeBox(b));
37259 if(east && east.isVisible()){
37260 var b = east.getBox();
37261 var m = east.getMargins();
37262 b.height = centerH - (m.top+m.bottom);
37263 var totalWidth = (b.width + m.left + m.right);
37264 b.x = w - totalWidth + m.left;
37265 b.y = centerY + m.top;
37266 centerW -= totalWidth;
37267 east.updateBox(this.safeBox(b));
37270 var m = center.getMargins();
37272 x: centerX + m.left,
37273 y: centerY + m.top,
37274 width: centerW - (m.left+m.right),
37275 height: centerH - (m.top+m.bottom)
37277 //if(this.hideOnLayout){
37278 //center.el.setStyle("display", "block");
37280 center.updateBox(this.safeBox(centerBox));
37283 this.fireEvent("layout", this);
37287 safeBox : function(box){
37288 box.width = Math.max(0, box.width);
37289 box.height = Math.max(0, box.height);
37294 * Adds a ContentPanel (or subclass) to this layout.
37295 * @param {String} target The target region key (north, south, east, west or center).
37296 * @param {Roo.ContentPanel} panel The panel to add
37297 * @return {Roo.ContentPanel} The added panel
37299 add : function(target, panel){
37301 target = target.toLowerCase();
37302 return this.regions[target].add(panel);
37306 * Remove a ContentPanel (or subclass) to this layout.
37307 * @param {String} target The target region key (north, south, east, west or center).
37308 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
37309 * @return {Roo.ContentPanel} The removed panel
37311 remove : function(target, panel){
37312 target = target.toLowerCase();
37313 return this.regions[target].remove(panel);
37317 * Searches all regions for a panel with the specified id
37318 * @param {String} panelId
37319 * @return {Roo.ContentPanel} The panel or null if it wasn't found
37321 findPanel : function(panelId){
37322 var rs = this.regions;
37323 for(var target in rs){
37324 if(typeof rs[target] != "function"){
37325 var p = rs[target].getPanel(panelId);
37335 * Searches all regions for a panel with the specified id and activates (shows) it.
37336 * @param {String/ContentPanel} panelId The panels id or the panel itself
37337 * @return {Roo.ContentPanel} The shown panel or null
37339 showPanel : function(panelId) {
37340 var rs = this.regions;
37341 for(var target in rs){
37342 var r = rs[target];
37343 if(typeof r != "function"){
37344 if(r.hasPanel(panelId)){
37345 return r.showPanel(panelId);
37353 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
37354 * @param {Roo.state.Provider} provider (optional) An alternate state provider
37357 restoreState : function(provider){
37359 provider = Roo.state.Manager;
37361 var sm = new Roo.LayoutStateManager();
37362 sm.init(this, provider);
37368 * Adds a xtype elements to the layout.
37372 xtype : 'ContentPanel',
37379 xtype : 'NestedLayoutPanel',
37385 items : [ ... list of content panels or nested layout panels.. ]
37389 * @param {Object} cfg Xtype definition of item to add.
37391 addxtype : function(cfg)
37393 // basically accepts a pannel...
37394 // can accept a layout region..!?!?
37395 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
37398 // theory? children can only be panels??
37400 //if (!cfg.xtype.match(/Panel$/)) {
37405 if (typeof(cfg.region) == 'undefined') {
37406 Roo.log("Failed to add Panel, region was not set");
37410 var region = cfg.region;
37416 xitems = cfg.items;
37421 if ( region == 'center') {
37422 Roo.log("Center: " + cfg.title);
37428 case 'Content': // ContentPanel (el, cfg)
37429 case 'Scroll': // ContentPanel (el, cfg)
37431 cfg.autoCreate = cfg.autoCreate || true;
37432 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37434 // var el = this.el.createChild();
37435 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
37438 this.add(region, ret);
37442 case 'TreePanel': // our new panel!
37443 cfg.el = this.el.createChild();
37444 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37445 this.add(region, ret);
37450 // create a new Layout (which is a Border Layout...
37452 var clayout = cfg.layout;
37453 clayout.el = this.el.createChild();
37454 clayout.items = clayout.items || [];
37458 // replace this exitems with the clayout ones..
37459 xitems = clayout.items;
37461 // force background off if it's in center...
37462 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
37463 cfg.background = false;
37465 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
37468 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37469 //console.log('adding nested layout panel ' + cfg.toSource());
37470 this.add(region, ret);
37471 nb = {}; /// find first...
37476 // needs grid and region
37478 //var el = this.getRegion(region).el.createChild();
37480 *var el = this.el.createChild();
37481 // create the grid first...
37482 cfg.grid.container = el;
37483 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
37486 if (region == 'center' && this.active ) {
37487 cfg.background = false;
37490 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37492 this.add(region, ret);
37494 if (cfg.background) {
37495 // render grid on panel activation (if panel background)
37496 ret.on('activate', function(gp) {
37497 if (!gp.grid.rendered) {
37498 // gp.grid.render(el);
37502 // cfg.grid.render(el);
37508 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
37509 // it was the old xcomponent building that caused this before.
37510 // espeically if border is the top element in the tree.
37520 if (typeof(Roo[cfg.xtype]) != 'undefined') {
37522 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37523 this.add(region, ret);
37527 throw "Can not add '" + cfg.xtype + "' to Border";
37533 this.beginUpdate();
37537 Roo.each(xitems, function(i) {
37538 region = nb && i.region ? i.region : false;
37540 var add = ret.addxtype(i);
37543 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
37544 if (!i.background) {
37545 abn[region] = nb[region] ;
37552 // make the last non-background panel active..
37553 //if (nb) { Roo.log(abn); }
37556 for(var r in abn) {
37557 region = this.getRegion(r);
37559 // tried using nb[r], but it does not work..
37561 region.showPanel(abn[r]);
37572 factory : function(cfg)
37575 var validRegions = Roo.bootstrap.layout.Border.regions;
37577 var target = cfg.region;
37580 var r = Roo.bootstrap.layout;
37584 return new r.North(cfg);
37586 return new r.South(cfg);
37588 return new r.East(cfg);
37590 return new r.West(cfg);
37592 return new r.Center(cfg);
37594 throw 'Layout region "'+target+'" not supported.';
37601 * Ext JS Library 1.1.1
37602 * Copyright(c) 2006-2007, Ext JS, LLC.
37604 * Originally Released Under LGPL - original licence link has changed is not relivant.
37607 * <script type="text/javascript">
37611 * @class Roo.bootstrap.layout.Basic
37612 * @extends Roo.util.Observable
37613 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
37614 * and does not have a titlebar, tabs or any other features. All it does is size and position
37615 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
37616 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37617 * @cfg {string} region the region that it inhabits..
37618 * @cfg {bool} skipConfig skip config?
37622 Roo.bootstrap.layout.Basic = function(config){
37624 this.mgr = config.mgr;
37626 this.position = config.region;
37628 var skipConfig = config.skipConfig;
37632 * @scope Roo.BasicLayoutRegion
37636 * @event beforeremove
37637 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
37638 * @param {Roo.LayoutRegion} this
37639 * @param {Roo.ContentPanel} panel The panel
37640 * @param {Object} e The cancel event object
37642 "beforeremove" : true,
37644 * @event invalidated
37645 * Fires when the layout for this region is changed.
37646 * @param {Roo.LayoutRegion} this
37648 "invalidated" : true,
37650 * @event visibilitychange
37651 * Fires when this region is shown or hidden
37652 * @param {Roo.LayoutRegion} this
37653 * @param {Boolean} visibility true or false
37655 "visibilitychange" : true,
37657 * @event paneladded
37658 * Fires when a panel is added.
37659 * @param {Roo.LayoutRegion} this
37660 * @param {Roo.ContentPanel} panel The panel
37662 "paneladded" : true,
37664 * @event panelremoved
37665 * Fires when a panel is removed.
37666 * @param {Roo.LayoutRegion} this
37667 * @param {Roo.ContentPanel} panel The panel
37669 "panelremoved" : true,
37671 * @event beforecollapse
37672 * Fires when this region before collapse.
37673 * @param {Roo.LayoutRegion} this
37675 "beforecollapse" : true,
37678 * Fires when this region is collapsed.
37679 * @param {Roo.LayoutRegion} this
37681 "collapsed" : true,
37684 * Fires when this region is expanded.
37685 * @param {Roo.LayoutRegion} this
37690 * Fires when this region is slid into view.
37691 * @param {Roo.LayoutRegion} this
37693 "slideshow" : true,
37696 * Fires when this region slides out of view.
37697 * @param {Roo.LayoutRegion} this
37699 "slidehide" : true,
37701 * @event panelactivated
37702 * Fires when a panel is activated.
37703 * @param {Roo.LayoutRegion} this
37704 * @param {Roo.ContentPanel} panel The activated panel
37706 "panelactivated" : true,
37709 * Fires when the user resizes this region.
37710 * @param {Roo.LayoutRegion} this
37711 * @param {Number} newSize The new size (width for east/west, height for north/south)
37715 /** A collection of panels in this region. @type Roo.util.MixedCollection */
37716 this.panels = new Roo.util.MixedCollection();
37717 this.panels.getKey = this.getPanelId.createDelegate(this);
37719 this.activePanel = null;
37720 // ensure listeners are added...
37722 if (config.listeners || config.events) {
37723 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
37724 listeners : config.listeners || {},
37725 events : config.events || {}
37729 if(skipConfig !== true){
37730 this.applyConfig(config);
37734 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
37736 getPanelId : function(p){
37740 applyConfig : function(config){
37741 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37742 this.config = config;
37747 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
37748 * the width, for horizontal (north, south) the height.
37749 * @param {Number} newSize The new width or height
37751 resizeTo : function(newSize){
37752 var el = this.el ? this.el :
37753 (this.activePanel ? this.activePanel.getEl() : null);
37755 switch(this.position){
37758 el.setWidth(newSize);
37759 this.fireEvent("resized", this, newSize);
37763 el.setHeight(newSize);
37764 this.fireEvent("resized", this, newSize);
37770 getBox : function(){
37771 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
37774 getMargins : function(){
37775 return this.margins;
37778 updateBox : function(box){
37780 var el = this.activePanel.getEl();
37781 el.dom.style.left = box.x + "px";
37782 el.dom.style.top = box.y + "px";
37783 this.activePanel.setSize(box.width, box.height);
37787 * Returns the container element for this region.
37788 * @return {Roo.Element}
37790 getEl : function(){
37791 return this.activePanel;
37795 * Returns true if this region is currently visible.
37796 * @return {Boolean}
37798 isVisible : function(){
37799 return this.activePanel ? true : false;
37802 setActivePanel : function(panel){
37803 panel = this.getPanel(panel);
37804 if(this.activePanel && this.activePanel != panel){
37805 this.activePanel.setActiveState(false);
37806 this.activePanel.getEl().setLeftTop(-10000,-10000);
37808 this.activePanel = panel;
37809 panel.setActiveState(true);
37811 panel.setSize(this.box.width, this.box.height);
37813 this.fireEvent("panelactivated", this, panel);
37814 this.fireEvent("invalidated");
37818 * Show the specified panel.
37819 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
37820 * @return {Roo.ContentPanel} The shown panel or null
37822 showPanel : function(panel){
37823 panel = this.getPanel(panel);
37825 this.setActivePanel(panel);
37831 * Get the active panel for this region.
37832 * @return {Roo.ContentPanel} The active panel or null
37834 getActivePanel : function(){
37835 return this.activePanel;
37839 * Add the passed ContentPanel(s)
37840 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37841 * @return {Roo.ContentPanel} The panel added (if only one was added)
37843 add : function(panel){
37844 if(arguments.length > 1){
37845 for(var i = 0, len = arguments.length; i < len; i++) {
37846 this.add(arguments[i]);
37850 if(this.hasPanel(panel)){
37851 this.showPanel(panel);
37854 var el = panel.getEl();
37855 if(el.dom.parentNode != this.mgr.el.dom){
37856 this.mgr.el.dom.appendChild(el.dom);
37858 if(panel.setRegion){
37859 panel.setRegion(this);
37861 this.panels.add(panel);
37862 el.setStyle("position", "absolute");
37863 if(!panel.background){
37864 this.setActivePanel(panel);
37865 if(this.config.initialSize && this.panels.getCount()==1){
37866 this.resizeTo(this.config.initialSize);
37869 this.fireEvent("paneladded", this, panel);
37874 * Returns true if the panel is in this region.
37875 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37876 * @return {Boolean}
37878 hasPanel : function(panel){
37879 if(typeof panel == "object"){ // must be panel obj
37880 panel = panel.getId();
37882 return this.getPanel(panel) ? true : false;
37886 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37887 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37888 * @param {Boolean} preservePanel Overrides the config preservePanel option
37889 * @return {Roo.ContentPanel} The panel that was removed
37891 remove : function(panel, preservePanel){
37892 panel = this.getPanel(panel);
37897 this.fireEvent("beforeremove", this, panel, e);
37898 if(e.cancel === true){
37901 var panelId = panel.getId();
37902 this.panels.removeKey(panelId);
37907 * Returns the panel specified or null if it's not in this region.
37908 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37909 * @return {Roo.ContentPanel}
37911 getPanel : function(id){
37912 if(typeof id == "object"){ // must be panel obj
37915 return this.panels.get(id);
37919 * Returns this regions position (north/south/east/west/center).
37922 getPosition: function(){
37923 return this.position;
37927 * Ext JS Library 1.1.1
37928 * Copyright(c) 2006-2007, Ext JS, LLC.
37930 * Originally Released Under LGPL - original licence link has changed is not relivant.
37933 * <script type="text/javascript">
37937 * @class Roo.bootstrap.layout.Region
37938 * @extends Roo.bootstrap.layout.Basic
37939 * This class represents a region in a layout manager.
37941 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37942 * @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})
37943 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37944 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37945 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37946 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37947 * @cfg {String} title The title for the region (overrides panel titles)
37948 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37949 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37950 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37951 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37952 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37953 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37954 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37955 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37956 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37957 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37959 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37960 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37961 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37962 * @cfg {Number} width For East/West panels
37963 * @cfg {Number} height For North/South panels
37964 * @cfg {Boolean} split To show the splitter
37965 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37967 * @cfg {string} cls Extra CSS classes to add to region
37969 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37970 * @cfg {string} region the region that it inhabits..
37973 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37974 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37976 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37977 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37978 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37980 Roo.bootstrap.layout.Region = function(config)
37982 this.applyConfig(config);
37984 var mgr = config.mgr;
37985 var pos = config.region;
37986 config.skipConfig = true;
37987 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37990 this.onRender(mgr.el);
37993 this.visible = true;
37994 this.collapsed = false;
37995 this.unrendered_panels = [];
37998 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
38000 position: '', // set by wrapper (eg. north/south etc..)
38001 unrendered_panels : null, // unrendered panels.
38003 tabPosition : false,
38005 mgr: false, // points to 'Border'
38008 createBody : function(){
38009 /** This region's body element
38010 * @type Roo.Element */
38011 this.bodyEl = this.el.createChild({
38013 cls: "roo-layout-panel-body tab-content" // bootstrap added...
38017 onRender: function(ctr, pos)
38019 var dh = Roo.DomHelper;
38020 /** This region's container element
38021 * @type Roo.Element */
38022 this.el = dh.append(ctr.dom, {
38024 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
38026 /** This region's title element
38027 * @type Roo.Element */
38029 this.titleEl = dh.append(this.el.dom, {
38031 unselectable: "on",
38032 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
38034 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
38035 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
38039 this.titleEl.enableDisplayMode();
38040 /** This region's title text element
38041 * @type HTMLElement */
38042 this.titleTextEl = this.titleEl.dom.firstChild;
38043 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
38045 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
38046 this.closeBtn.enableDisplayMode();
38047 this.closeBtn.on("click", this.closeClicked, this);
38048 this.closeBtn.hide();
38050 this.createBody(this.config);
38051 if(this.config.hideWhenEmpty){
38053 this.on("paneladded", this.validateVisibility, this);
38054 this.on("panelremoved", this.validateVisibility, this);
38056 if(this.autoScroll){
38057 this.bodyEl.setStyle("overflow", "auto");
38059 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
38061 //if(c.titlebar !== false){
38062 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
38063 this.titleEl.hide();
38065 this.titleEl.show();
38066 if(this.config.title){
38067 this.titleTextEl.innerHTML = this.config.title;
38071 if(this.config.collapsed){
38072 this.collapse(true);
38074 if(this.config.hidden){
38078 if (this.unrendered_panels && this.unrendered_panels.length) {
38079 for (var i =0;i< this.unrendered_panels.length; i++) {
38080 this.add(this.unrendered_panels[i]);
38082 this.unrendered_panels = null;
38088 applyConfig : function(c)
38091 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
38092 var dh = Roo.DomHelper;
38093 if(c.titlebar !== false){
38094 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
38095 this.collapseBtn.on("click", this.collapse, this);
38096 this.collapseBtn.enableDisplayMode();
38098 if(c.showPin === true || this.showPin){
38099 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
38100 this.stickBtn.enableDisplayMode();
38101 this.stickBtn.on("click", this.expand, this);
38102 this.stickBtn.hide();
38107 /** This region's collapsed element
38108 * @type Roo.Element */
38111 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
38112 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
38115 if(c.floatable !== false){
38116 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
38117 this.collapsedEl.on("click", this.collapseClick, this);
38120 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
38121 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
38122 id: "message", unselectable: "on", style:{"float":"left"}});
38123 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
38125 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
38126 this.expandBtn.on("click", this.expand, this);
38130 if(this.collapseBtn){
38131 this.collapseBtn.setVisible(c.collapsible == true);
38134 this.cmargins = c.cmargins || this.cmargins ||
38135 (this.position == "west" || this.position == "east" ?
38136 {top: 0, left: 2, right:2, bottom: 0} :
38137 {top: 2, left: 0, right:0, bottom: 2});
38139 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
38142 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
38144 this.autoScroll = c.autoScroll || false;
38149 this.duration = c.duration || .30;
38150 this.slideDuration = c.slideDuration || .45;
38155 * Returns true if this region is currently visible.
38156 * @return {Boolean}
38158 isVisible : function(){
38159 return this.visible;
38163 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
38164 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
38166 //setCollapsedTitle : function(title){
38167 // title = title || " ";
38168 // if(this.collapsedTitleTextEl){
38169 // this.collapsedTitleTextEl.innerHTML = title;
38173 getBox : function(){
38175 // if(!this.collapsed){
38176 b = this.el.getBox(false, true);
38178 // b = this.collapsedEl.getBox(false, true);
38183 getMargins : function(){
38184 return this.margins;
38185 //return this.collapsed ? this.cmargins : this.margins;
38188 highlight : function(){
38189 this.el.addClass("x-layout-panel-dragover");
38192 unhighlight : function(){
38193 this.el.removeClass("x-layout-panel-dragover");
38196 updateBox : function(box)
38198 if (!this.bodyEl) {
38199 return; // not rendered yet..
38203 if(!this.collapsed){
38204 this.el.dom.style.left = box.x + "px";
38205 this.el.dom.style.top = box.y + "px";
38206 this.updateBody(box.width, box.height);
38208 this.collapsedEl.dom.style.left = box.x + "px";
38209 this.collapsedEl.dom.style.top = box.y + "px";
38210 this.collapsedEl.setSize(box.width, box.height);
38213 this.tabs.autoSizeTabs();
38217 updateBody : function(w, h)
38220 this.el.setWidth(w);
38221 w -= this.el.getBorderWidth("rl");
38222 if(this.config.adjustments){
38223 w += this.config.adjustments[0];
38226 if(h !== null && h > 0){
38227 this.el.setHeight(h);
38228 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
38229 h -= this.el.getBorderWidth("tb");
38230 if(this.config.adjustments){
38231 h += this.config.adjustments[1];
38233 this.bodyEl.setHeight(h);
38235 h = this.tabs.syncHeight(h);
38238 if(this.panelSize){
38239 w = w !== null ? w : this.panelSize.width;
38240 h = h !== null ? h : this.panelSize.height;
38242 if(this.activePanel){
38243 var el = this.activePanel.getEl();
38244 w = w !== null ? w : el.getWidth();
38245 h = h !== null ? h : el.getHeight();
38246 this.panelSize = {width: w, height: h};
38247 this.activePanel.setSize(w, h);
38249 if(Roo.isIE && this.tabs){
38250 this.tabs.el.repaint();
38255 * Returns the container element for this region.
38256 * @return {Roo.Element}
38258 getEl : function(){
38263 * Hides this region.
38266 //if(!this.collapsed){
38267 this.el.dom.style.left = "-2000px";
38270 // this.collapsedEl.dom.style.left = "-2000px";
38271 // this.collapsedEl.hide();
38273 this.visible = false;
38274 this.fireEvent("visibilitychange", this, false);
38278 * Shows this region if it was previously hidden.
38281 //if(!this.collapsed){
38284 // this.collapsedEl.show();
38286 this.visible = true;
38287 this.fireEvent("visibilitychange", this, true);
38290 closeClicked : function(){
38291 if(this.activePanel){
38292 this.remove(this.activePanel);
38296 collapseClick : function(e){
38298 e.stopPropagation();
38301 e.stopPropagation();
38307 * Collapses this region.
38308 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
38311 collapse : function(skipAnim, skipCheck = false){
38312 if(this.collapsed) {
38316 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
38318 this.collapsed = true;
38320 this.split.el.hide();
38322 if(this.config.animate && skipAnim !== true){
38323 this.fireEvent("invalidated", this);
38324 this.animateCollapse();
38326 this.el.setLocation(-20000,-20000);
38328 this.collapsedEl.show();
38329 this.fireEvent("collapsed", this);
38330 this.fireEvent("invalidated", this);
38336 animateCollapse : function(){
38341 * Expands this region if it was previously collapsed.
38342 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
38343 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
38346 expand : function(e, skipAnim){
38348 e.stopPropagation();
38350 if(!this.collapsed || this.el.hasActiveFx()) {
38354 this.afterSlideIn();
38357 this.collapsed = false;
38358 if(this.config.animate && skipAnim !== true){
38359 this.animateExpand();
38363 this.split.el.show();
38365 this.collapsedEl.setLocation(-2000,-2000);
38366 this.collapsedEl.hide();
38367 this.fireEvent("invalidated", this);
38368 this.fireEvent("expanded", this);
38372 animateExpand : function(){
38376 initTabs : function()
38378 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
38380 var ts = new Roo.bootstrap.panel.Tabs({
38381 el: this.bodyEl.dom,
38383 tabPosition: this.tabPosition ? this.tabPosition : 'top',
38384 disableTooltips: this.config.disableTabTips,
38385 toolbar : this.config.toolbar
38388 if(this.config.hideTabs){
38389 ts.stripWrap.setDisplayed(false);
38392 ts.resizeTabs = this.config.resizeTabs === true;
38393 ts.minTabWidth = this.config.minTabWidth || 40;
38394 ts.maxTabWidth = this.config.maxTabWidth || 250;
38395 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
38396 ts.monitorResize = false;
38397 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
38398 ts.bodyEl.addClass('roo-layout-tabs-body');
38399 this.panels.each(this.initPanelAsTab, this);
38402 initPanelAsTab : function(panel){
38403 var ti = this.tabs.addTab(
38407 this.config.closeOnTab && panel.isClosable(),
38410 if(panel.tabTip !== undefined){
38411 ti.setTooltip(panel.tabTip);
38413 ti.on("activate", function(){
38414 this.setActivePanel(panel);
38417 if(this.config.closeOnTab){
38418 ti.on("beforeclose", function(t, e){
38420 this.remove(panel);
38424 panel.tabItem = ti;
38429 updatePanelTitle : function(panel, title)
38431 if(this.activePanel == panel){
38432 this.updateTitle(title);
38435 var ti = this.tabs.getTab(panel.getEl().id);
38437 if(panel.tabTip !== undefined){
38438 ti.setTooltip(panel.tabTip);
38443 updateTitle : function(title){
38444 if(this.titleTextEl && !this.config.title){
38445 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
38449 setActivePanel : function(panel)
38451 panel = this.getPanel(panel);
38452 if(this.activePanel && this.activePanel != panel){
38453 if(this.activePanel.setActiveState(false) === false){
38457 this.activePanel = panel;
38458 panel.setActiveState(true);
38459 if(this.panelSize){
38460 panel.setSize(this.panelSize.width, this.panelSize.height);
38463 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
38465 this.updateTitle(panel.getTitle());
38467 this.fireEvent("invalidated", this);
38469 this.fireEvent("panelactivated", this, panel);
38473 * Shows the specified panel.
38474 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
38475 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
38477 showPanel : function(panel)
38479 panel = this.getPanel(panel);
38482 var tab = this.tabs.getTab(panel.getEl().id);
38483 if(tab.isHidden()){
38484 this.tabs.unhideTab(tab.id);
38488 this.setActivePanel(panel);
38495 * Get the active panel for this region.
38496 * @return {Roo.ContentPanel} The active panel or null
38498 getActivePanel : function(){
38499 return this.activePanel;
38502 validateVisibility : function(){
38503 if(this.panels.getCount() < 1){
38504 this.updateTitle(" ");
38505 this.closeBtn.hide();
38508 if(!this.isVisible()){
38515 * Adds the passed ContentPanel(s) to this region.
38516 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
38517 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
38519 add : function(panel)
38521 if(arguments.length > 1){
38522 for(var i = 0, len = arguments.length; i < len; i++) {
38523 this.add(arguments[i]);
38528 // if we have not been rendered yet, then we can not really do much of this..
38529 if (!this.bodyEl) {
38530 this.unrendered_panels.push(panel);
38537 if(this.hasPanel(panel)){
38538 this.showPanel(panel);
38541 panel.setRegion(this);
38542 this.panels.add(panel);
38543 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
38544 // sinle panel - no tab...?? would it not be better to render it with the tabs,
38545 // and hide them... ???
38546 this.bodyEl.dom.appendChild(panel.getEl().dom);
38547 if(panel.background !== true){
38548 this.setActivePanel(panel);
38550 this.fireEvent("paneladded", this, panel);
38557 this.initPanelAsTab(panel);
38561 if(panel.background !== true){
38562 this.tabs.activate(panel.getEl().id);
38564 this.fireEvent("paneladded", this, panel);
38569 * Hides the tab for the specified panel.
38570 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38572 hidePanel : function(panel){
38573 if(this.tabs && (panel = this.getPanel(panel))){
38574 this.tabs.hideTab(panel.getEl().id);
38579 * Unhides the tab for a previously hidden panel.
38580 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38582 unhidePanel : function(panel){
38583 if(this.tabs && (panel = this.getPanel(panel))){
38584 this.tabs.unhideTab(panel.getEl().id);
38588 clearPanels : function(){
38589 while(this.panels.getCount() > 0){
38590 this.remove(this.panels.first());
38595 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
38596 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38597 * @param {Boolean} preservePanel Overrides the config preservePanel option
38598 * @return {Roo.ContentPanel} The panel that was removed
38600 remove : function(panel, preservePanel)
38602 panel = this.getPanel(panel);
38607 this.fireEvent("beforeremove", this, panel, e);
38608 if(e.cancel === true){
38611 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
38612 var panelId = panel.getId();
38613 this.panels.removeKey(panelId);
38615 document.body.appendChild(panel.getEl().dom);
38618 this.tabs.removeTab(panel.getEl().id);
38619 }else if (!preservePanel){
38620 this.bodyEl.dom.removeChild(panel.getEl().dom);
38622 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
38623 var p = this.panels.first();
38624 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
38625 tempEl.appendChild(p.getEl().dom);
38626 this.bodyEl.update("");
38627 this.bodyEl.dom.appendChild(p.getEl().dom);
38629 this.updateTitle(p.getTitle());
38631 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
38632 this.setActivePanel(p);
38634 panel.setRegion(null);
38635 if(this.activePanel == panel){
38636 this.activePanel = null;
38638 if(this.config.autoDestroy !== false && preservePanel !== true){
38639 try{panel.destroy();}catch(e){}
38641 this.fireEvent("panelremoved", this, panel);
38646 * Returns the TabPanel component used by this region
38647 * @return {Roo.TabPanel}
38649 getTabs : function(){
38653 createTool : function(parentEl, className){
38654 var btn = Roo.DomHelper.append(parentEl, {
38656 cls: "x-layout-tools-button",
38659 cls: "roo-layout-tools-button-inner " + className,
38663 btn.addClassOnOver("roo-layout-tools-button-over");
38668 * Ext JS Library 1.1.1
38669 * Copyright(c) 2006-2007, Ext JS, LLC.
38671 * Originally Released Under LGPL - original licence link has changed is not relivant.
38674 * <script type="text/javascript">
38680 * @class Roo.SplitLayoutRegion
38681 * @extends Roo.LayoutRegion
38682 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
38684 Roo.bootstrap.layout.Split = function(config){
38685 this.cursor = config.cursor;
38686 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
38689 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
38691 splitTip : "Drag to resize.",
38692 collapsibleSplitTip : "Drag to resize. Double click to hide.",
38693 useSplitTips : false,
38695 applyConfig : function(config){
38696 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
38699 onRender : function(ctr,pos) {
38701 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
38702 if(!this.config.split){
38707 var splitEl = Roo.DomHelper.append(ctr.dom, {
38709 id: this.el.id + "-split",
38710 cls: "roo-layout-split roo-layout-split-"+this.position,
38713 /** The SplitBar for this region
38714 * @type Roo.SplitBar */
38715 // does not exist yet...
38716 Roo.log([this.position, this.orientation]);
38718 this.split = new Roo.bootstrap.SplitBar({
38719 dragElement : splitEl,
38720 resizingElement: this.el,
38721 orientation : this.orientation
38724 this.split.on("moved", this.onSplitMove, this);
38725 this.split.useShim = this.config.useShim === true;
38726 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
38727 if(this.useSplitTips){
38728 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
38730 //if(config.collapsible){
38731 // this.split.el.on("dblclick", this.collapse, this);
38734 if(typeof this.config.minSize != "undefined"){
38735 this.split.minSize = this.config.minSize;
38737 if(typeof this.config.maxSize != "undefined"){
38738 this.split.maxSize = this.config.maxSize;
38740 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
38741 this.hideSplitter();
38746 getHMaxSize : function(){
38747 var cmax = this.config.maxSize || 10000;
38748 var center = this.mgr.getRegion("center");
38749 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
38752 getVMaxSize : function(){
38753 var cmax = this.config.maxSize || 10000;
38754 var center = this.mgr.getRegion("center");
38755 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
38758 onSplitMove : function(split, newSize){
38759 this.fireEvent("resized", this, newSize);
38763 * Returns the {@link Roo.SplitBar} for this region.
38764 * @return {Roo.SplitBar}
38766 getSplitBar : function(){
38771 this.hideSplitter();
38772 Roo.bootstrap.layout.Split.superclass.hide.call(this);
38775 hideSplitter : function(){
38777 this.split.el.setLocation(-2000,-2000);
38778 this.split.el.hide();
38784 this.split.el.show();
38786 Roo.bootstrap.layout.Split.superclass.show.call(this);
38789 beforeSlide: function(){
38790 if(Roo.isGecko){// firefox overflow auto bug workaround
38791 this.bodyEl.clip();
38793 this.tabs.bodyEl.clip();
38795 if(this.activePanel){
38796 this.activePanel.getEl().clip();
38798 if(this.activePanel.beforeSlide){
38799 this.activePanel.beforeSlide();
38805 afterSlide : function(){
38806 if(Roo.isGecko){// firefox overflow auto bug workaround
38807 this.bodyEl.unclip();
38809 this.tabs.bodyEl.unclip();
38811 if(this.activePanel){
38812 this.activePanel.getEl().unclip();
38813 if(this.activePanel.afterSlide){
38814 this.activePanel.afterSlide();
38820 initAutoHide : function(){
38821 if(this.autoHide !== false){
38822 if(!this.autoHideHd){
38823 var st = new Roo.util.DelayedTask(this.slideIn, this);
38824 this.autoHideHd = {
38825 "mouseout": function(e){
38826 if(!e.within(this.el, true)){
38830 "mouseover" : function(e){
38836 this.el.on(this.autoHideHd);
38840 clearAutoHide : function(){
38841 if(this.autoHide !== false){
38842 this.el.un("mouseout", this.autoHideHd.mouseout);
38843 this.el.un("mouseover", this.autoHideHd.mouseover);
38847 clearMonitor : function(){
38848 Roo.get(document).un("click", this.slideInIf, this);
38851 // these names are backwards but not changed for compat
38852 slideOut : function(){
38853 if(this.isSlid || this.el.hasActiveFx()){
38856 this.isSlid = true;
38857 if(this.collapseBtn){
38858 this.collapseBtn.hide();
38860 this.closeBtnState = this.closeBtn.getStyle('display');
38861 this.closeBtn.hide();
38863 this.stickBtn.show();
38866 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
38867 this.beforeSlide();
38868 this.el.setStyle("z-index", 10001);
38869 this.el.slideIn(this.getSlideAnchor(), {
38870 callback: function(){
38872 this.initAutoHide();
38873 Roo.get(document).on("click", this.slideInIf, this);
38874 this.fireEvent("slideshow", this);
38881 afterSlideIn : function(){
38882 this.clearAutoHide();
38883 this.isSlid = false;
38884 this.clearMonitor();
38885 this.el.setStyle("z-index", "");
38886 if(this.collapseBtn){
38887 this.collapseBtn.show();
38889 this.closeBtn.setStyle('display', this.closeBtnState);
38891 this.stickBtn.hide();
38893 this.fireEvent("slidehide", this);
38896 slideIn : function(cb){
38897 if(!this.isSlid || this.el.hasActiveFx()){
38901 this.isSlid = false;
38902 this.beforeSlide();
38903 this.el.slideOut(this.getSlideAnchor(), {
38904 callback: function(){
38905 this.el.setLeftTop(-10000, -10000);
38907 this.afterSlideIn();
38915 slideInIf : function(e){
38916 if(!e.within(this.el)){
38921 animateCollapse : function(){
38922 this.beforeSlide();
38923 this.el.setStyle("z-index", 20000);
38924 var anchor = this.getSlideAnchor();
38925 this.el.slideOut(anchor, {
38926 callback : function(){
38927 this.el.setStyle("z-index", "");
38928 this.collapsedEl.slideIn(anchor, {duration:.3});
38930 this.el.setLocation(-10000,-10000);
38932 this.fireEvent("collapsed", this);
38939 animateExpand : function(){
38940 this.beforeSlide();
38941 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38942 this.el.setStyle("z-index", 20000);
38943 this.collapsedEl.hide({
38946 this.el.slideIn(this.getSlideAnchor(), {
38947 callback : function(){
38948 this.el.setStyle("z-index", "");
38951 this.split.el.show();
38953 this.fireEvent("invalidated", this);
38954 this.fireEvent("expanded", this);
38982 getAnchor : function(){
38983 return this.anchors[this.position];
38986 getCollapseAnchor : function(){
38987 return this.canchors[this.position];
38990 getSlideAnchor : function(){
38991 return this.sanchors[this.position];
38994 getAlignAdj : function(){
38995 var cm = this.cmargins;
38996 switch(this.position){
39012 getExpandAdj : function(){
39013 var c = this.collapsedEl, cm = this.cmargins;
39014 switch(this.position){
39016 return [-(cm.right+c.getWidth()+cm.left), 0];
39019 return [cm.right+c.getWidth()+cm.left, 0];
39022 return [0, -(cm.top+cm.bottom+c.getHeight())];
39025 return [0, cm.top+cm.bottom+c.getHeight()];
39031 * Ext JS Library 1.1.1
39032 * Copyright(c) 2006-2007, Ext JS, LLC.
39034 * Originally Released Under LGPL - original licence link has changed is not relivant.
39037 * <script type="text/javascript">
39040 * These classes are private internal classes
39042 Roo.bootstrap.layout.Center = function(config){
39043 config.region = "center";
39044 Roo.bootstrap.layout.Region.call(this, config);
39045 this.visible = true;
39046 this.minWidth = config.minWidth || 20;
39047 this.minHeight = config.minHeight || 20;
39050 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
39052 // center panel can't be hidden
39056 // center panel can't be hidden
39059 getMinWidth: function(){
39060 return this.minWidth;
39063 getMinHeight: function(){
39064 return this.minHeight;
39078 Roo.bootstrap.layout.North = function(config)
39080 config.region = 'north';
39081 config.cursor = 'n-resize';
39083 Roo.bootstrap.layout.Split.call(this, config);
39087 this.split.placement = Roo.bootstrap.SplitBar.TOP;
39088 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39089 this.split.el.addClass("roo-layout-split-v");
39091 var size = config.initialSize || config.height;
39092 if(typeof size != "undefined"){
39093 this.el.setHeight(size);
39096 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
39098 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39102 getBox : function(){
39103 if(this.collapsed){
39104 return this.collapsedEl.getBox();
39106 var box = this.el.getBox();
39108 box.height += this.split.el.getHeight();
39113 updateBox : function(box){
39114 if(this.split && !this.collapsed){
39115 box.height -= this.split.el.getHeight();
39116 this.split.el.setLeft(box.x);
39117 this.split.el.setTop(box.y+box.height);
39118 this.split.el.setWidth(box.width);
39120 if(this.collapsed){
39121 this.updateBody(box.width, null);
39123 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39131 Roo.bootstrap.layout.South = function(config){
39132 config.region = 'south';
39133 config.cursor = 's-resize';
39134 Roo.bootstrap.layout.Split.call(this, config);
39136 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
39137 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39138 this.split.el.addClass("roo-layout-split-v");
39140 var size = config.initialSize || config.height;
39141 if(typeof size != "undefined"){
39142 this.el.setHeight(size);
39146 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
39147 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39148 getBox : function(){
39149 if(this.collapsed){
39150 return this.collapsedEl.getBox();
39152 var box = this.el.getBox();
39154 var sh = this.split.el.getHeight();
39161 updateBox : function(box){
39162 if(this.split && !this.collapsed){
39163 var sh = this.split.el.getHeight();
39166 this.split.el.setLeft(box.x);
39167 this.split.el.setTop(box.y-sh);
39168 this.split.el.setWidth(box.width);
39170 if(this.collapsed){
39171 this.updateBody(box.width, null);
39173 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39177 Roo.bootstrap.layout.East = function(config){
39178 config.region = "east";
39179 config.cursor = "e-resize";
39180 Roo.bootstrap.layout.Split.call(this, config);
39182 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
39183 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39184 this.split.el.addClass("roo-layout-split-h");
39186 var size = config.initialSize || config.width;
39187 if(typeof size != "undefined"){
39188 this.el.setWidth(size);
39191 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
39192 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39193 getBox : function(){
39194 if(this.collapsed){
39195 return this.collapsedEl.getBox();
39197 var box = this.el.getBox();
39199 var sw = this.split.el.getWidth();
39206 updateBox : function(box){
39207 if(this.split && !this.collapsed){
39208 var sw = this.split.el.getWidth();
39210 this.split.el.setLeft(box.x);
39211 this.split.el.setTop(box.y);
39212 this.split.el.setHeight(box.height);
39215 if(this.collapsed){
39216 this.updateBody(null, box.height);
39218 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39222 Roo.bootstrap.layout.West = function(config){
39223 config.region = "west";
39224 config.cursor = "w-resize";
39226 Roo.bootstrap.layout.Split.call(this, config);
39228 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
39229 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39230 this.split.el.addClass("roo-layout-split-h");
39234 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
39235 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39237 onRender: function(ctr, pos)
39239 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
39240 var size = this.config.initialSize || this.config.width;
39241 if(typeof size != "undefined"){
39242 this.el.setWidth(size);
39246 getBox : function(){
39247 if(this.collapsed){
39248 return this.collapsedEl.getBox();
39250 var box = this.el.getBox();
39252 box.width += this.split.el.getWidth();
39257 updateBox : function(box){
39258 if(this.split && !this.collapsed){
39259 var sw = this.split.el.getWidth();
39261 this.split.el.setLeft(box.x+box.width);
39262 this.split.el.setTop(box.y);
39263 this.split.el.setHeight(box.height);
39265 if(this.collapsed){
39266 this.updateBody(null, box.height);
39268 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39270 });Roo.namespace("Roo.bootstrap.panel");/*
39272 * Ext JS Library 1.1.1
39273 * Copyright(c) 2006-2007, Ext JS, LLC.
39275 * Originally Released Under LGPL - original licence link has changed is not relivant.
39278 * <script type="text/javascript">
39281 * @class Roo.ContentPanel
39282 * @extends Roo.util.Observable
39283 * A basic ContentPanel element.
39284 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
39285 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
39286 * @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
39287 * @cfg {Boolean} closable True if the panel can be closed/removed
39288 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
39289 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
39290 * @cfg {Toolbar} toolbar A toolbar for this panel
39291 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
39292 * @cfg {String} title The title for this panel
39293 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
39294 * @cfg {String} url Calls {@link #setUrl} with this value
39295 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
39296 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
39297 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
39298 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
39299 * @cfg {Boolean} badges render the badges
39300 * @cfg {String} cls extra classes to use
39301 * @cfg {String} background (primary|secondary|success|info|warning|danger|light|dark)
39304 * Create a new ContentPanel.
39305 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
39306 * @param {String/Object} config A string to set only the title or a config object
39307 * @param {String} content (optional) Set the HTML content for this panel
39308 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
39310 Roo.bootstrap.panel.Content = function( config){
39312 this.tpl = config.tpl || false;
39314 var el = config.el;
39315 var content = config.content;
39317 if(config.autoCreate){ // xtype is available if this is called from factory
39320 this.el = Roo.get(el);
39321 if(!this.el && config && config.autoCreate){
39322 if(typeof config.autoCreate == "object"){
39323 if(!config.autoCreate.id){
39324 config.autoCreate.id = config.id||el;
39326 this.el = Roo.DomHelper.append(document.body,
39327 config.autoCreate, true);
39331 cls: (config.cls || '') +
39332 (config.background ? ' bg-' + config.background : '') +
39333 " roo-layout-inactive-content",
39337 elcfg.html = config.html;
39341 this.el = Roo.DomHelper.append(document.body, elcfg , true);
39344 this.closable = false;
39345 this.loaded = false;
39346 this.active = false;
39349 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
39351 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
39353 this.wrapEl = this.el; //this.el.wrap();
39355 if (config.toolbar.items) {
39356 ti = config.toolbar.items ;
39357 delete config.toolbar.items ;
39361 this.toolbar.render(this.wrapEl, 'before');
39362 for(var i =0;i < ti.length;i++) {
39363 // Roo.log(['add child', items[i]]);
39364 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39366 this.toolbar.items = nitems;
39367 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
39368 delete config.toolbar;
39372 // xtype created footer. - not sure if will work as we normally have to render first..
39373 if (this.footer && !this.footer.el && this.footer.xtype) {
39374 if (!this.wrapEl) {
39375 this.wrapEl = this.el.wrap();
39378 this.footer.container = this.wrapEl.createChild();
39380 this.footer = Roo.factory(this.footer, Roo);
39385 if(typeof config == "string"){
39386 this.title = config;
39388 Roo.apply(this, config);
39392 this.resizeEl = Roo.get(this.resizeEl, true);
39394 this.resizeEl = this.el;
39396 // handle view.xtype
39404 * Fires when this panel is activated.
39405 * @param {Roo.ContentPanel} this
39409 * @event deactivate
39410 * Fires when this panel is activated.
39411 * @param {Roo.ContentPanel} this
39413 "deactivate" : true,
39417 * Fires when this panel is resized if fitToFrame is true.
39418 * @param {Roo.ContentPanel} this
39419 * @param {Number} width The width after any component adjustments
39420 * @param {Number} height The height after any component adjustments
39426 * Fires when this tab is created
39427 * @param {Roo.ContentPanel} this
39438 if(this.autoScroll){
39439 this.resizeEl.setStyle("overflow", "auto");
39441 // fix randome scrolling
39442 //this.el.on('scroll', function() {
39443 // Roo.log('fix random scolling');
39444 // this.scrollTo('top',0);
39447 content = content || this.content;
39449 this.setContent(content);
39451 if(config && config.url){
39452 this.setUrl(this.url, this.params, this.loadOnce);
39457 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
39459 if (this.view && typeof(this.view.xtype) != 'undefined') {
39460 this.view.el = this.el.appendChild(document.createElement("div"));
39461 this.view = Roo.factory(this.view);
39462 this.view.render && this.view.render(false, '');
39466 this.fireEvent('render', this);
39469 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
39476 setRegion : function(region){
39477 this.region = region;
39478 this.setActiveClass(region && !this.background);
39482 setActiveClass: function(state)
39485 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
39486 this.el.setStyle('position','relative');
39488 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
39489 this.el.setStyle('position', 'absolute');
39494 * Returns the toolbar for this Panel if one was configured.
39495 * @return {Roo.Toolbar}
39497 getToolbar : function(){
39498 return this.toolbar;
39501 setActiveState : function(active)
39503 this.active = active;
39504 this.setActiveClass(active);
39506 if(this.fireEvent("deactivate", this) === false){
39511 this.fireEvent("activate", this);
39515 * Updates this panel's element
39516 * @param {String} content The new content
39517 * @param {Boolean} loadScripts (optional) true to look for and process scripts
39519 setContent : function(content, loadScripts){
39520 this.el.update(content, loadScripts);
39523 ignoreResize : function(w, h){
39524 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
39527 this.lastSize = {width: w, height: h};
39532 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
39533 * @return {Roo.UpdateManager} The UpdateManager
39535 getUpdateManager : function(){
39536 return this.el.getUpdateManager();
39539 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
39540 * @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:
39543 url: "your-url.php",
39544 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
39545 callback: yourFunction,
39546 scope: yourObject, //(optional scope)
39549 text: "Loading...",
39554 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
39555 * 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.
39556 * @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}
39557 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
39558 * @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.
39559 * @return {Roo.ContentPanel} this
39562 var um = this.el.getUpdateManager();
39563 um.update.apply(um, arguments);
39569 * 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.
39570 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
39571 * @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)
39572 * @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)
39573 * @return {Roo.UpdateManager} The UpdateManager
39575 setUrl : function(url, params, loadOnce){
39576 if(this.refreshDelegate){
39577 this.removeListener("activate", this.refreshDelegate);
39579 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39580 this.on("activate", this.refreshDelegate);
39581 return this.el.getUpdateManager();
39584 _handleRefresh : function(url, params, loadOnce){
39585 if(!loadOnce || !this.loaded){
39586 var updater = this.el.getUpdateManager();
39587 updater.update(url, params, this._setLoaded.createDelegate(this));
39591 _setLoaded : function(){
39592 this.loaded = true;
39596 * Returns this panel's id
39599 getId : function(){
39604 * Returns this panel's element - used by regiosn to add.
39605 * @return {Roo.Element}
39607 getEl : function(){
39608 return this.wrapEl || this.el;
39613 adjustForComponents : function(width, height)
39615 //Roo.log('adjustForComponents ');
39616 if(this.resizeEl != this.el){
39617 width -= this.el.getFrameWidth('lr');
39618 height -= this.el.getFrameWidth('tb');
39621 var te = this.toolbar.getEl();
39622 te.setWidth(width);
39623 height -= te.getHeight();
39626 var te = this.footer.getEl();
39627 te.setWidth(width);
39628 height -= te.getHeight();
39632 if(this.adjustments){
39633 width += this.adjustments[0];
39634 height += this.adjustments[1];
39636 return {"width": width, "height": height};
39639 setSize : function(width, height){
39640 if(this.fitToFrame && !this.ignoreResize(width, height)){
39641 if(this.fitContainer && this.resizeEl != this.el){
39642 this.el.setSize(width, height);
39644 var size = this.adjustForComponents(width, height);
39645 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
39646 this.fireEvent('resize', this, size.width, size.height);
39651 * Returns this panel's title
39654 getTitle : function(){
39656 if (typeof(this.title) != 'object') {
39661 for (var k in this.title) {
39662 if (!this.title.hasOwnProperty(k)) {
39666 if (k.indexOf('-') >= 0) {
39667 var s = k.split('-');
39668 for (var i = 0; i<s.length; i++) {
39669 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
39672 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
39679 * Set this panel's title
39680 * @param {String} title
39682 setTitle : function(title){
39683 this.title = title;
39685 this.region.updatePanelTitle(this, title);
39690 * Returns true is this panel was configured to be closable
39691 * @return {Boolean}
39693 isClosable : function(){
39694 return this.closable;
39697 beforeSlide : function(){
39699 this.resizeEl.clip();
39702 afterSlide : function(){
39704 this.resizeEl.unclip();
39708 * Force a content refresh from the URL specified in the {@link #setUrl} method.
39709 * Will fail silently if the {@link #setUrl} method has not been called.
39710 * This does not activate the panel, just updates its content.
39712 refresh : function(){
39713 if(this.refreshDelegate){
39714 this.loaded = false;
39715 this.refreshDelegate();
39720 * Destroys this panel
39722 destroy : function(){
39723 this.el.removeAllListeners();
39724 var tempEl = document.createElement("span");
39725 tempEl.appendChild(this.el.dom);
39726 tempEl.innerHTML = "";
39732 * form - if the content panel contains a form - this is a reference to it.
39733 * @type {Roo.form.Form}
39737 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
39738 * This contains a reference to it.
39744 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
39754 * @param {Object} cfg Xtype definition of item to add.
39758 getChildContainer: function () {
39759 return this.getEl();
39764 var ret = new Roo.factory(cfg);
39769 if (cfg.xtype.match(/^Form$/)) {
39772 //if (this.footer) {
39773 // el = this.footer.container.insertSibling(false, 'before');
39775 el = this.el.createChild();
39778 this.form = new Roo.form.Form(cfg);
39781 if ( this.form.allItems.length) {
39782 this.form.render(el.dom);
39786 // should only have one of theses..
39787 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
39788 // views.. should not be just added - used named prop 'view''
39790 cfg.el = this.el.appendChild(document.createElement("div"));
39793 var ret = new Roo.factory(cfg);
39795 ret.render && ret.render(false, ''); // render blank..
39805 * @class Roo.bootstrap.panel.Grid
39806 * @extends Roo.bootstrap.panel.Content
39808 * Create a new GridPanel.
39809 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
39810 * @param {Object} config A the config object
39816 Roo.bootstrap.panel.Grid = function(config)
39820 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
39821 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
39823 config.el = this.wrapper;
39824 //this.el = this.wrapper;
39826 if (config.container) {
39827 // ctor'ed from a Border/panel.grid
39830 this.wrapper.setStyle("overflow", "hidden");
39831 this.wrapper.addClass('roo-grid-container');
39836 if(config.toolbar){
39837 var tool_el = this.wrapper.createChild();
39838 this.toolbar = Roo.factory(config.toolbar);
39840 if (config.toolbar.items) {
39841 ti = config.toolbar.items ;
39842 delete config.toolbar.items ;
39846 this.toolbar.render(tool_el);
39847 for(var i =0;i < ti.length;i++) {
39848 // Roo.log(['add child', items[i]]);
39849 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39851 this.toolbar.items = nitems;
39853 delete config.toolbar;
39856 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
39857 config.grid.scrollBody = true;;
39858 config.grid.monitorWindowResize = false; // turn off autosizing
39859 config.grid.autoHeight = false;
39860 config.grid.autoWidth = false;
39862 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
39864 if (config.background) {
39865 // render grid on panel activation (if panel background)
39866 this.on('activate', function(gp) {
39867 if (!gp.grid.rendered) {
39868 gp.grid.render(this.wrapper);
39869 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39874 this.grid.render(this.wrapper);
39875 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39878 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
39879 // ??? needed ??? config.el = this.wrapper;
39884 // xtype created footer. - not sure if will work as we normally have to render first..
39885 if (this.footer && !this.footer.el && this.footer.xtype) {
39887 var ctr = this.grid.getView().getFooterPanel(true);
39888 this.footer.dataSource = this.grid.dataSource;
39889 this.footer = Roo.factory(this.footer, Roo);
39890 this.footer.render(ctr);
39900 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
39901 getId : function(){
39902 return this.grid.id;
39906 * Returns the grid for this panel
39907 * @return {Roo.bootstrap.Table}
39909 getGrid : function(){
39913 setSize : function(width, height){
39914 if(!this.ignoreResize(width, height)){
39915 var grid = this.grid;
39916 var size = this.adjustForComponents(width, height);
39917 // tfoot is not a footer?
39920 var gridel = grid.getGridEl();
39921 gridel.setSize(size.width, size.height);
39923 var tbd = grid.getGridEl().select('tbody', true).first();
39924 var thd = grid.getGridEl().select('thead',true).first();
39925 var tbf= grid.getGridEl().select('tfoot', true).first();
39928 size.height -= thd.getHeight();
39931 size.height -= thd.getHeight();
39934 tbd.setSize(size.width, size.height );
39935 // this is for the account management tab -seems to work there.
39936 var thd = grid.getGridEl().select('thead',true).first();
39938 // tbd.setSize(size.width, size.height - thd.getHeight());
39947 beforeSlide : function(){
39948 this.grid.getView().scroller.clip();
39951 afterSlide : function(){
39952 this.grid.getView().scroller.unclip();
39955 destroy : function(){
39956 this.grid.destroy();
39958 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39963 * @class Roo.bootstrap.panel.Nest
39964 * @extends Roo.bootstrap.panel.Content
39966 * Create a new Panel, that can contain a layout.Border.
39969 * @param {Roo.BorderLayout} layout The layout for this panel
39970 * @param {String/Object} config A string to set only the title or a config object
39972 Roo.bootstrap.panel.Nest = function(config)
39974 // construct with only one argument..
39975 /* FIXME - implement nicer consturctors
39976 if (layout.layout) {
39978 layout = config.layout;
39979 delete config.layout;
39981 if (layout.xtype && !layout.getEl) {
39982 // then layout needs constructing..
39983 layout = Roo.factory(layout, Roo);
39987 config.el = config.layout.getEl();
39989 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39991 config.layout.monitorWindowResize = false; // turn off autosizing
39992 this.layout = config.layout;
39993 this.layout.getEl().addClass("roo-layout-nested-layout");
39994 this.layout.parent = this;
40001 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
40003 setSize : function(width, height){
40004 if(!this.ignoreResize(width, height)){
40005 var size = this.adjustForComponents(width, height);
40006 var el = this.layout.getEl();
40007 if (size.height < 1) {
40008 el.setWidth(size.width);
40010 el.setSize(size.width, size.height);
40012 var touch = el.dom.offsetWidth;
40013 this.layout.layout();
40014 // ie requires a double layout on the first pass
40015 if(Roo.isIE && !this.initialized){
40016 this.initialized = true;
40017 this.layout.layout();
40022 // activate all subpanels if not currently active..
40024 setActiveState : function(active){
40025 this.active = active;
40026 this.setActiveClass(active);
40029 this.fireEvent("deactivate", this);
40033 this.fireEvent("activate", this);
40034 // not sure if this should happen before or after..
40035 if (!this.layout) {
40036 return; // should not happen..
40039 for (var r in this.layout.regions) {
40040 reg = this.layout.getRegion(r);
40041 if (reg.getActivePanel()) {
40042 //reg.showPanel(reg.getActivePanel()); // force it to activate..
40043 reg.setActivePanel(reg.getActivePanel());
40046 if (!reg.panels.length) {
40049 reg.showPanel(reg.getPanel(0));
40058 * Returns the nested BorderLayout for this panel
40059 * @return {Roo.BorderLayout}
40061 getLayout : function(){
40062 return this.layout;
40066 * Adds a xtype elements to the layout of the nested panel
40070 xtype : 'ContentPanel',
40077 xtype : 'NestedLayoutPanel',
40083 items : [ ... list of content panels or nested layout panels.. ]
40087 * @param {Object} cfg Xtype definition of item to add.
40089 addxtype : function(cfg) {
40090 return this.layout.addxtype(cfg);
40095 * Ext JS Library 1.1.1
40096 * Copyright(c) 2006-2007, Ext JS, LLC.
40098 * Originally Released Under LGPL - original licence link has changed is not relivant.
40101 * <script type="text/javascript">
40104 * @class Roo.TabPanel
40105 * @extends Roo.util.Observable
40106 * A lightweight tab container.
40110 // basic tabs 1, built from existing content
40111 var tabs = new Roo.TabPanel("tabs1");
40112 tabs.addTab("script", "View Script");
40113 tabs.addTab("markup", "View Markup");
40114 tabs.activate("script");
40116 // more advanced tabs, built from javascript
40117 var jtabs = new Roo.TabPanel("jtabs");
40118 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
40120 // set up the UpdateManager
40121 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
40122 var updater = tab2.getUpdateManager();
40123 updater.setDefaultUrl("ajax1.htm");
40124 tab2.on('activate', updater.refresh, updater, true);
40126 // Use setUrl for Ajax loading
40127 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
40128 tab3.setUrl("ajax2.htm", null, true);
40131 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
40134 jtabs.activate("jtabs-1");
40137 * Create a new TabPanel.
40138 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
40139 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
40141 Roo.bootstrap.panel.Tabs = function(config){
40143 * The container element for this TabPanel.
40144 * @type Roo.Element
40146 this.el = Roo.get(config.el);
40149 if(typeof config == "boolean"){
40150 this.tabPosition = config ? "bottom" : "top";
40152 Roo.apply(this, config);
40156 if(this.tabPosition == "bottom"){
40157 // if tabs are at the bottom = create the body first.
40158 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40159 this.el.addClass("roo-tabs-bottom");
40161 // next create the tabs holders
40163 if (this.tabPosition == "west"){
40165 var reg = this.region; // fake it..
40167 if (!reg.mgr.parent) {
40170 reg = reg.mgr.parent.region;
40172 Roo.log("got nest?");
40174 if (reg.mgr.getRegion('west')) {
40175 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
40176 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
40177 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40178 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40179 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40187 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
40188 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40189 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40190 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40195 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
40198 // finally - if tabs are at the top, then create the body last..
40199 if(this.tabPosition != "bottom"){
40200 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
40201 * @type Roo.Element
40203 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40204 this.el.addClass("roo-tabs-top");
40208 this.bodyEl.setStyle("position", "relative");
40210 this.active = null;
40211 this.activateDelegate = this.activate.createDelegate(this);
40216 * Fires when the active tab changes
40217 * @param {Roo.TabPanel} this
40218 * @param {Roo.TabPanelItem} activePanel The new active tab
40222 * @event beforetabchange
40223 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
40224 * @param {Roo.TabPanel} this
40225 * @param {Object} e Set cancel to true on this object to cancel the tab change
40226 * @param {Roo.TabPanelItem} tab The tab being changed to
40228 "beforetabchange" : true
40231 Roo.EventManager.onWindowResize(this.onResize, this);
40232 this.cpad = this.el.getPadding("lr");
40233 this.hiddenCount = 0;
40236 // toolbar on the tabbar support...
40237 if (this.toolbar) {
40238 alert("no toolbar support yet");
40239 this.toolbar = false;
40241 var tcfg = this.toolbar;
40242 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
40243 this.toolbar = new Roo.Toolbar(tcfg);
40244 if (Roo.isSafari) {
40245 var tbl = tcfg.container.child('table', true);
40246 tbl.setAttribute('width', '100%');
40254 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
40257 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
40259 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
40261 tabPosition : "top",
40263 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
40265 currentTabWidth : 0,
40267 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
40271 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
40275 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
40277 preferredTabWidth : 175,
40279 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
40281 resizeTabs : false,
40283 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
40285 monitorResize : true,
40287 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
40289 toolbar : false, // set by caller..
40291 region : false, /// set by caller
40293 disableTooltips : true, // not used yet...
40296 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
40297 * @param {String} id The id of the div to use <b>or create</b>
40298 * @param {String} text The text for the tab
40299 * @param {String} content (optional) Content to put in the TabPanelItem body
40300 * @param {Boolean} closable (optional) True to create a close icon on the tab
40301 * @return {Roo.TabPanelItem} The created TabPanelItem
40303 addTab : function(id, text, content, closable, tpl)
40305 var item = new Roo.bootstrap.panel.TabItem({
40309 closable : closable,
40312 this.addTabItem(item);
40314 item.setContent(content);
40320 * Returns the {@link Roo.TabPanelItem} with the specified id/index
40321 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
40322 * @return {Roo.TabPanelItem}
40324 getTab : function(id){
40325 return this.items[id];
40329 * Hides the {@link Roo.TabPanelItem} with the specified id/index
40330 * @param {String/Number} id The id or index of the TabPanelItem to hide.
40332 hideTab : function(id){
40333 var t = this.items[id];
40336 this.hiddenCount++;
40337 this.autoSizeTabs();
40342 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
40343 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
40345 unhideTab : function(id){
40346 var t = this.items[id];
40348 t.setHidden(false);
40349 this.hiddenCount--;
40350 this.autoSizeTabs();
40355 * Adds an existing {@link Roo.TabPanelItem}.
40356 * @param {Roo.TabPanelItem} item The TabPanelItem to add
40358 addTabItem : function(item)
40360 this.items[item.id] = item;
40361 this.items.push(item);
40362 this.autoSizeTabs();
40363 // if(this.resizeTabs){
40364 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
40365 // this.autoSizeTabs();
40367 // item.autoSize();
40372 * Removes a {@link Roo.TabPanelItem}.
40373 * @param {String/Number} id The id or index of the TabPanelItem to remove.
40375 removeTab : function(id){
40376 var items = this.items;
40377 var tab = items[id];
40378 if(!tab) { return; }
40379 var index = items.indexOf(tab);
40380 if(this.active == tab && items.length > 1){
40381 var newTab = this.getNextAvailable(index);
40386 this.stripEl.dom.removeChild(tab.pnode.dom);
40387 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
40388 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
40390 items.splice(index, 1);
40391 delete this.items[tab.id];
40392 tab.fireEvent("close", tab);
40393 tab.purgeListeners();
40394 this.autoSizeTabs();
40397 getNextAvailable : function(start){
40398 var items = this.items;
40400 // look for a next tab that will slide over to
40401 // replace the one being removed
40402 while(index < items.length){
40403 var item = items[++index];
40404 if(item && !item.isHidden()){
40408 // if one isn't found select the previous tab (on the left)
40411 var item = items[--index];
40412 if(item && !item.isHidden()){
40420 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
40421 * @param {String/Number} id The id or index of the TabPanelItem to disable.
40423 disableTab : function(id){
40424 var tab = this.items[id];
40425 if(tab && this.active != tab){
40431 * Enables a {@link Roo.TabPanelItem} that is disabled.
40432 * @param {String/Number} id The id or index of the TabPanelItem to enable.
40434 enableTab : function(id){
40435 var tab = this.items[id];
40440 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
40441 * @param {String/Number} id The id or index of the TabPanelItem to activate.
40442 * @return {Roo.TabPanelItem} The TabPanelItem.
40444 activate : function(id)
40446 //Roo.log('activite:' + id);
40448 var tab = this.items[id];
40452 if(tab == this.active || tab.disabled){
40456 this.fireEvent("beforetabchange", this, e, tab);
40457 if(e.cancel !== true && !tab.disabled){
40459 this.active.hide();
40461 this.active = this.items[id];
40462 this.active.show();
40463 this.fireEvent("tabchange", this, this.active);
40469 * Gets the active {@link Roo.TabPanelItem}.
40470 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
40472 getActiveTab : function(){
40473 return this.active;
40477 * Updates the tab body element to fit the height of the container element
40478 * for overflow scrolling
40479 * @param {Number} targetHeight (optional) Override the starting height from the elements height
40481 syncHeight : function(targetHeight){
40482 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
40483 var bm = this.bodyEl.getMargins();
40484 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
40485 this.bodyEl.setHeight(newHeight);
40489 onResize : function(){
40490 if(this.monitorResize){
40491 this.autoSizeTabs();
40496 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
40498 beginUpdate : function(){
40499 this.updating = true;
40503 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
40505 endUpdate : function(){
40506 this.updating = false;
40507 this.autoSizeTabs();
40511 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
40513 autoSizeTabs : function()
40515 var count = this.items.length;
40516 var vcount = count - this.hiddenCount;
40519 this.stripEl.hide();
40521 this.stripEl.show();
40524 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
40529 var w = Math.max(this.el.getWidth() - this.cpad, 10);
40530 var availWidth = Math.floor(w / vcount);
40531 var b = this.stripBody;
40532 if(b.getWidth() > w){
40533 var tabs = this.items;
40534 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
40535 if(availWidth < this.minTabWidth){
40536 /*if(!this.sleft){ // incomplete scrolling code
40537 this.createScrollButtons();
40540 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
40543 if(this.currentTabWidth < this.preferredTabWidth){
40544 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
40550 * Returns the number of tabs in this TabPanel.
40553 getCount : function(){
40554 return this.items.length;
40558 * Resizes all the tabs to the passed width
40559 * @param {Number} The new width
40561 setTabWidth : function(width){
40562 this.currentTabWidth = width;
40563 for(var i = 0, len = this.items.length; i < len; i++) {
40564 if(!this.items[i].isHidden()) {
40565 this.items[i].setWidth(width);
40571 * Destroys this TabPanel
40572 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
40574 destroy : function(removeEl){
40575 Roo.EventManager.removeResizeListener(this.onResize, this);
40576 for(var i = 0, len = this.items.length; i < len; i++){
40577 this.items[i].purgeListeners();
40579 if(removeEl === true){
40580 this.el.update("");
40585 createStrip : function(container)
40587 var strip = document.createElement("nav");
40588 strip.className = Roo.bootstrap.version == 4 ?
40589 "navbar-light bg-light" :
40590 "navbar navbar-default"; //"x-tabs-wrap";
40591 container.appendChild(strip);
40595 createStripList : function(strip)
40597 // div wrapper for retard IE
40598 // returns the "tr" element.
40599 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
40600 //'<div class="x-tabs-strip-wrap">'+
40601 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
40602 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
40603 return strip.firstChild; //.firstChild.firstChild.firstChild;
40605 createBody : function(container)
40607 var body = document.createElement("div");
40608 Roo.id(body, "tab-body");
40609 //Roo.fly(body).addClass("x-tabs-body");
40610 Roo.fly(body).addClass("tab-content");
40611 container.appendChild(body);
40614 createItemBody :function(bodyEl, id){
40615 var body = Roo.getDom(id);
40617 body = document.createElement("div");
40620 //Roo.fly(body).addClass("x-tabs-item-body");
40621 Roo.fly(body).addClass("tab-pane");
40622 bodyEl.insertBefore(body, bodyEl.firstChild);
40626 createStripElements : function(stripEl, text, closable, tpl)
40628 var td = document.createElement("li"); // was td..
40629 td.className = 'nav-item';
40631 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
40634 stripEl.appendChild(td);
40636 td.className = "x-tabs-closable";
40637 if(!this.closeTpl){
40638 this.closeTpl = new Roo.Template(
40639 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40640 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
40641 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
40644 var el = this.closeTpl.overwrite(td, {"text": text});
40645 var close = el.getElementsByTagName("div")[0];
40646 var inner = el.getElementsByTagName("em")[0];
40647 return {"el": el, "close": close, "inner": inner};
40650 // not sure what this is..
40651 // if(!this.tabTpl){
40652 //this.tabTpl = new Roo.Template(
40653 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40654 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
40656 // this.tabTpl = new Roo.Template(
40657 // '<a href="#">' +
40658 // '<span unselectable="on"' +
40659 // (this.disableTooltips ? '' : ' title="{text}"') +
40660 // ' >{text}</span></a>'
40666 var template = tpl || this.tabTpl || false;
40669 template = new Roo.Template(
40670 Roo.bootstrap.version == 4 ?
40672 '<a class="nav-link" href="#" unselectable="on"' +
40673 (this.disableTooltips ? '' : ' title="{text}"') +
40676 '<a class="nav-link" href="#">' +
40677 '<span unselectable="on"' +
40678 (this.disableTooltips ? '' : ' title="{text}"') +
40679 ' >{text}</span></a>'
40684 switch (typeof(template)) {
40688 template = new Roo.Template(template);
40694 var el = template.overwrite(td, {"text": text});
40696 var inner = el.getElementsByTagName("span")[0];
40698 return {"el": el, "inner": inner};
40706 * @class Roo.TabPanelItem
40707 * @extends Roo.util.Observable
40708 * Represents an individual item (tab plus body) in a TabPanel.
40709 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
40710 * @param {String} id The id of this TabPanelItem
40711 * @param {String} text The text for the tab of this TabPanelItem
40712 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
40714 Roo.bootstrap.panel.TabItem = function(config){
40716 * The {@link Roo.TabPanel} this TabPanelItem belongs to
40717 * @type Roo.TabPanel
40719 this.tabPanel = config.panel;
40721 * The id for this TabPanelItem
40724 this.id = config.id;
40726 this.disabled = false;
40728 this.text = config.text;
40730 this.loaded = false;
40731 this.closable = config.closable;
40734 * The body element for this TabPanelItem.
40735 * @type Roo.Element
40737 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
40738 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
40739 this.bodyEl.setStyle("display", "block");
40740 this.bodyEl.setStyle("zoom", "1");
40741 //this.hideAction();
40743 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
40745 this.el = Roo.get(els.el);
40746 this.inner = Roo.get(els.inner, true);
40747 this.textEl = Roo.bootstrap.version == 4 ?
40748 this.el : Roo.get(this.el.dom.firstChild, true);
40750 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
40751 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
40754 // this.el.on("mousedown", this.onTabMouseDown, this);
40755 this.el.on("click", this.onTabClick, this);
40757 if(config.closable){
40758 var c = Roo.get(els.close, true);
40759 c.dom.title = this.closeText;
40760 c.addClassOnOver("close-over");
40761 c.on("click", this.closeClick, this);
40767 * Fires when this tab becomes the active tab.
40768 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40769 * @param {Roo.TabPanelItem} this
40773 * @event beforeclose
40774 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
40775 * @param {Roo.TabPanelItem} this
40776 * @param {Object} e Set cancel to true on this object to cancel the close.
40778 "beforeclose": true,
40781 * Fires when this tab is closed.
40782 * @param {Roo.TabPanelItem} this
40786 * @event deactivate
40787 * Fires when this tab is no longer the active tab.
40788 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40789 * @param {Roo.TabPanelItem} this
40791 "deactivate" : true
40793 this.hidden = false;
40795 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
40798 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
40800 purgeListeners : function(){
40801 Roo.util.Observable.prototype.purgeListeners.call(this);
40802 this.el.removeAllListeners();
40805 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
40808 this.status_node.addClass("active");
40811 this.tabPanel.stripWrap.repaint();
40813 this.fireEvent("activate", this.tabPanel, this);
40817 * Returns true if this tab is the active tab.
40818 * @return {Boolean}
40820 isActive : function(){
40821 return this.tabPanel.getActiveTab() == this;
40825 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
40828 this.status_node.removeClass("active");
40830 this.fireEvent("deactivate", this.tabPanel, this);
40833 hideAction : function(){
40834 this.bodyEl.hide();
40835 this.bodyEl.setStyle("position", "absolute");
40836 this.bodyEl.setLeft("-20000px");
40837 this.bodyEl.setTop("-20000px");
40840 showAction : function(){
40841 this.bodyEl.setStyle("position", "relative");
40842 this.bodyEl.setTop("");
40843 this.bodyEl.setLeft("");
40844 this.bodyEl.show();
40848 * Set the tooltip for the tab.
40849 * @param {String} tooltip The tab's tooltip
40851 setTooltip : function(text){
40852 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
40853 this.textEl.dom.qtip = text;
40854 this.textEl.dom.removeAttribute('title');
40856 this.textEl.dom.title = text;
40860 onTabClick : function(e){
40861 e.preventDefault();
40862 this.tabPanel.activate(this.id);
40865 onTabMouseDown : function(e){
40866 e.preventDefault();
40867 this.tabPanel.activate(this.id);
40870 getWidth : function(){
40871 return this.inner.getWidth();
40874 setWidth : function(width){
40875 var iwidth = width - this.linode.getPadding("lr");
40876 this.inner.setWidth(iwidth);
40877 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
40878 this.linode.setWidth(width);
40882 * Show or hide the tab
40883 * @param {Boolean} hidden True to hide or false to show.
40885 setHidden : function(hidden){
40886 this.hidden = hidden;
40887 this.linode.setStyle("display", hidden ? "none" : "");
40891 * Returns true if this tab is "hidden"
40892 * @return {Boolean}
40894 isHidden : function(){
40895 return this.hidden;
40899 * Returns the text for this tab
40902 getText : function(){
40906 autoSize : function(){
40907 //this.el.beginMeasure();
40908 this.textEl.setWidth(1);
40910 * #2804 [new] Tabs in Roojs
40911 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
40913 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
40914 //this.el.endMeasure();
40918 * Sets the text for the tab (Note: this also sets the tooltip text)
40919 * @param {String} text The tab's text and tooltip
40921 setText : function(text){
40923 this.textEl.update(text);
40924 this.setTooltip(text);
40925 //if(!this.tabPanel.resizeTabs){
40926 // this.autoSize();
40930 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
40932 activate : function(){
40933 this.tabPanel.activate(this.id);
40937 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
40939 disable : function(){
40940 if(this.tabPanel.active != this){
40941 this.disabled = true;
40942 this.status_node.addClass("disabled");
40947 * Enables this TabPanelItem if it was previously disabled.
40949 enable : function(){
40950 this.disabled = false;
40951 this.status_node.removeClass("disabled");
40955 * Sets the content for this TabPanelItem.
40956 * @param {String} content The content
40957 * @param {Boolean} loadScripts true to look for and load scripts
40959 setContent : function(content, loadScripts){
40960 this.bodyEl.update(content, loadScripts);
40964 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40965 * @return {Roo.UpdateManager} The UpdateManager
40967 getUpdateManager : function(){
40968 return this.bodyEl.getUpdateManager();
40972 * Set a URL to be used to load the content for this TabPanelItem.
40973 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40974 * @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)
40975 * @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)
40976 * @return {Roo.UpdateManager} The UpdateManager
40978 setUrl : function(url, params, loadOnce){
40979 if(this.refreshDelegate){
40980 this.un('activate', this.refreshDelegate);
40982 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40983 this.on("activate", this.refreshDelegate);
40984 return this.bodyEl.getUpdateManager();
40988 _handleRefresh : function(url, params, loadOnce){
40989 if(!loadOnce || !this.loaded){
40990 var updater = this.bodyEl.getUpdateManager();
40991 updater.update(url, params, this._setLoaded.createDelegate(this));
40996 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40997 * Will fail silently if the setUrl method has not been called.
40998 * This does not activate the panel, just updates its content.
41000 refresh : function(){
41001 if(this.refreshDelegate){
41002 this.loaded = false;
41003 this.refreshDelegate();
41008 _setLoaded : function(){
41009 this.loaded = true;
41013 closeClick : function(e){
41016 this.fireEvent("beforeclose", this, o);
41017 if(o.cancel !== true){
41018 this.tabPanel.removeTab(this.id);
41022 * The text displayed in the tooltip for the close icon.
41025 closeText : "Close this tab"
41028 * This script refer to:
41029 * Title: International Telephone Input
41030 * Author: Jack O'Connor
41031 * Code version: v12.1.12
41032 * Availability: https://github.com/jackocnr/intl-tel-input.git
41035 Roo.bootstrap.PhoneInputData = function() {
41038 "Afghanistan (افغانستان)",
41043 "Albania (Shqipëri)",
41048 "Algeria (الجزائر)",
41073 "Antigua and Barbuda",
41083 "Armenia (Հայաստան)",
41099 "Austria (Österreich)",
41104 "Azerbaijan (Azərbaycan)",
41114 "Bahrain (البحرين)",
41119 "Bangladesh (বাংলাদেশ)",
41129 "Belarus (Беларусь)",
41134 "Belgium (België)",
41164 "Bosnia and Herzegovina (Босна и Херцеговина)",
41179 "British Indian Ocean Territory",
41184 "British Virgin Islands",
41194 "Bulgaria (България)",
41204 "Burundi (Uburundi)",
41209 "Cambodia (កម្ពុជា)",
41214 "Cameroon (Cameroun)",
41223 ["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"]
41226 "Cape Verde (Kabu Verdi)",
41231 "Caribbean Netherlands",
41242 "Central African Republic (République centrafricaine)",
41262 "Christmas Island",
41268 "Cocos (Keeling) Islands",
41279 "Comoros (جزر القمر)",
41284 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
41289 "Congo (Republic) (Congo-Brazzaville)",
41309 "Croatia (Hrvatska)",
41330 "Czech Republic (Česká republika)",
41335 "Denmark (Danmark)",
41350 "Dominican Republic (República Dominicana)",
41354 ["809", "829", "849"]
41372 "Equatorial Guinea (Guinea Ecuatorial)",
41392 "Falkland Islands (Islas Malvinas)",
41397 "Faroe Islands (Føroyar)",
41418 "French Guiana (Guyane française)",
41423 "French Polynesia (Polynésie française)",
41438 "Georgia (საქართველო)",
41443 "Germany (Deutschland)",
41463 "Greenland (Kalaallit Nunaat)",
41500 "Guinea-Bissau (Guiné Bissau)",
41525 "Hungary (Magyarország)",
41530 "Iceland (Ísland)",
41550 "Iraq (العراق)",
41566 "Israel (ישראל)",
41593 "Jordan (الأردن)",
41598 "Kazakhstan (Казахстан)",
41619 "Kuwait (الكويت)",
41624 "Kyrgyzstan (Кыргызстан)",
41634 "Latvia (Latvija)",
41639 "Lebanon (لبنان)",
41654 "Libya (ليبيا)",
41664 "Lithuania (Lietuva)",
41679 "Macedonia (FYROM) (Македонија)",
41684 "Madagascar (Madagasikara)",
41714 "Marshall Islands",
41724 "Mauritania (موريتانيا)",
41729 "Mauritius (Moris)",
41750 "Moldova (Republica Moldova)",
41760 "Mongolia (Монгол)",
41765 "Montenegro (Crna Gora)",
41775 "Morocco (المغرب)",
41781 "Mozambique (Moçambique)",
41786 "Myanmar (Burma) (မြန်မာ)",
41791 "Namibia (Namibië)",
41806 "Netherlands (Nederland)",
41811 "New Caledonia (Nouvelle-Calédonie)",
41846 "North Korea (조선 민주주의 인민 공화국)",
41851 "Northern Mariana Islands",
41867 "Pakistan (پاکستان)",
41877 "Palestine (فلسطين)",
41887 "Papua New Guinea",
41929 "Réunion (La Réunion)",
41935 "Romania (România)",
41951 "Saint Barthélemy",
41962 "Saint Kitts and Nevis",
41972 "Saint Martin (Saint-Martin (partie française))",
41978 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41983 "Saint Vincent and the Grenadines",
41998 "São Tomé and Príncipe (São Tomé e Príncipe)",
42003 "Saudi Arabia (المملكة العربية السعودية)",
42008 "Senegal (Sénégal)",
42038 "Slovakia (Slovensko)",
42043 "Slovenia (Slovenija)",
42053 "Somalia (Soomaaliya)",
42063 "South Korea (대한민국)",
42068 "South Sudan (جنوب السودان)",
42078 "Sri Lanka (ශ්රී ලංකාව)",
42083 "Sudan (السودان)",
42093 "Svalbard and Jan Mayen",
42104 "Sweden (Sverige)",
42109 "Switzerland (Schweiz)",
42114 "Syria (سوريا)",
42159 "Trinidad and Tobago",
42164 "Tunisia (تونس)",
42169 "Turkey (Türkiye)",
42179 "Turks and Caicos Islands",
42189 "U.S. Virgin Islands",
42199 "Ukraine (Україна)",
42204 "United Arab Emirates (الإمارات العربية المتحدة)",
42226 "Uzbekistan (Oʻzbekiston)",
42236 "Vatican City (Città del Vaticano)",
42247 "Vietnam (Việt Nam)",
42252 "Wallis and Futuna (Wallis-et-Futuna)",
42257 "Western Sahara (الصحراء الغربية)",
42263 "Yemen (اليمن)",
42287 * This script refer to:
42288 * Title: International Telephone Input
42289 * Author: Jack O'Connor
42290 * Code version: v12.1.12
42291 * Availability: https://github.com/jackocnr/intl-tel-input.git
42295 * @class Roo.bootstrap.PhoneInput
42296 * @extends Roo.bootstrap.TriggerField
42297 * An input with International dial-code selection
42299 * @cfg {String} defaultDialCode default '+852'
42300 * @cfg {Array} preferedCountries default []
42303 * Create a new PhoneInput.
42304 * @param {Object} config Configuration options
42307 Roo.bootstrap.PhoneInput = function(config) {
42308 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
42311 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
42313 listWidth: undefined,
42315 selectedClass: 'active',
42317 invalidClass : "has-warning",
42319 validClass: 'has-success',
42321 allowed: '0123456789',
42326 * @cfg {String} defaultDialCode The default dial code when initializing the input
42328 defaultDialCode: '+852',
42331 * @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
42333 preferedCountries: false,
42335 getAutoCreate : function()
42337 var data = Roo.bootstrap.PhoneInputData();
42338 var align = this.labelAlign || this.parentLabelAlign();
42341 this.allCountries = [];
42342 this.dialCodeMapping = [];
42344 for (var i = 0; i < data.length; i++) {
42346 this.allCountries[i] = {
42350 priority: c[3] || 0,
42351 areaCodes: c[4] || null
42353 this.dialCodeMapping[c[2]] = {
42356 priority: c[3] || 0,
42357 areaCodes: c[4] || null
42369 // type: 'number', -- do not use number - we get the flaky up/down arrows.
42370 maxlength: this.max_length,
42371 cls : 'form-control tel-input',
42372 autocomplete: 'new-password'
42375 var hiddenInput = {
42378 cls: 'hidden-tel-input'
42382 hiddenInput.name = this.name;
42385 if (this.disabled) {
42386 input.disabled = true;
42389 var flag_container = {
42406 cls: this.hasFeedback ? 'has-feedback' : '',
42412 cls: 'dial-code-holder',
42419 cls: 'roo-select2-container input-group',
42426 if (this.fieldLabel.length) {
42429 tooltip: 'This field is required'
42435 cls: 'control-label',
42441 html: this.fieldLabel
42444 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42450 if(this.indicatorpos == 'right') {
42451 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42458 if(align == 'left') {
42466 if(this.labelWidth > 12){
42467 label.style = "width: " + this.labelWidth + 'px';
42469 if(this.labelWidth < 13 && this.labelmd == 0){
42470 this.labelmd = this.labelWidth;
42472 if(this.labellg > 0){
42473 label.cls += ' col-lg-' + this.labellg;
42474 input.cls += ' col-lg-' + (12 - this.labellg);
42476 if(this.labelmd > 0){
42477 label.cls += ' col-md-' + this.labelmd;
42478 container.cls += ' col-md-' + (12 - this.labelmd);
42480 if(this.labelsm > 0){
42481 label.cls += ' col-sm-' + this.labelsm;
42482 container.cls += ' col-sm-' + (12 - this.labelsm);
42484 if(this.labelxs > 0){
42485 label.cls += ' col-xs-' + this.labelxs;
42486 container.cls += ' col-xs-' + (12 - this.labelxs);
42496 var settings = this;
42498 ['xs','sm','md','lg'].map(function(size){
42499 if (settings[size]) {
42500 cfg.cls += ' col-' + size + '-' + settings[size];
42504 this.store = new Roo.data.Store({
42505 proxy : new Roo.data.MemoryProxy({}),
42506 reader : new Roo.data.JsonReader({
42517 'name' : 'dialCode',
42521 'name' : 'priority',
42525 'name' : 'areaCodes',
42532 if(!this.preferedCountries) {
42533 this.preferedCountries = [
42540 var p = this.preferedCountries.reverse();
42543 for (var i = 0; i < p.length; i++) {
42544 for (var j = 0; j < this.allCountries.length; j++) {
42545 if(this.allCountries[j].iso2 == p[i]) {
42546 var t = this.allCountries[j];
42547 this.allCountries.splice(j,1);
42548 this.allCountries.unshift(t);
42554 this.store.proxy.data = {
42556 data: this.allCountries
42562 initEvents : function()
42565 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
42567 this.indicator = this.indicatorEl();
42568 this.flag = this.flagEl();
42569 this.dialCodeHolder = this.dialCodeHolderEl();
42571 this.trigger = this.el.select('div.flag-box',true).first();
42572 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
42577 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42578 _this.list.setWidth(lw);
42581 this.list.on('mouseover', this.onViewOver, this);
42582 this.list.on('mousemove', this.onViewMove, this);
42583 this.inputEl().on("keyup", this.onKeyUp, this);
42584 this.inputEl().on("keypress", this.onKeyPress, this);
42586 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
42588 this.view = new Roo.View(this.list, this.tpl, {
42589 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42592 this.view.on('click', this.onViewClick, this);
42593 this.setValue(this.defaultDialCode);
42596 onTriggerClick : function(e)
42598 Roo.log('trigger click');
42603 if(this.isExpanded()){
42605 this.hasFocus = false;
42607 this.store.load({});
42608 this.hasFocus = true;
42613 isExpanded : function()
42615 return this.list.isVisible();
42618 collapse : function()
42620 if(!this.isExpanded()){
42624 Roo.get(document).un('mousedown', this.collapseIf, this);
42625 Roo.get(document).un('mousewheel', this.collapseIf, this);
42626 this.fireEvent('collapse', this);
42630 expand : function()
42634 if(this.isExpanded() || !this.hasFocus){
42638 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
42639 this.list.setWidth(lw);
42642 this.restrictHeight();
42644 Roo.get(document).on('mousedown', this.collapseIf, this);
42645 Roo.get(document).on('mousewheel', this.collapseIf, this);
42647 this.fireEvent('expand', this);
42650 restrictHeight : function()
42652 this.list.alignTo(this.inputEl(), this.listAlign);
42653 this.list.alignTo(this.inputEl(), this.listAlign);
42656 onViewOver : function(e, t)
42658 if(this.inKeyMode){
42661 var item = this.view.findItemFromChild(t);
42664 var index = this.view.indexOf(item);
42665 this.select(index, false);
42670 onViewClick : function(view, doFocus, el, e)
42672 var index = this.view.getSelectedIndexes()[0];
42674 var r = this.store.getAt(index);
42677 this.onSelect(r, index);
42679 if(doFocus !== false && !this.blockFocus){
42680 this.inputEl().focus();
42684 onViewMove : function(e, t)
42686 this.inKeyMode = false;
42689 select : function(index, scrollIntoView)
42691 this.selectedIndex = index;
42692 this.view.select(index);
42693 if(scrollIntoView !== false){
42694 var el = this.view.getNode(index);
42696 this.list.scrollChildIntoView(el, false);
42701 createList : function()
42703 this.list = Roo.get(document.body).createChild({
42705 cls: 'typeahead typeahead-long dropdown-menu tel-list',
42706 style: 'display:none'
42709 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
42712 collapseIf : function(e)
42714 var in_combo = e.within(this.el);
42715 var in_list = e.within(this.list);
42716 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
42718 if (in_combo || in_list || is_list) {
42724 onSelect : function(record, index)
42726 if(this.fireEvent('beforeselect', this, record, index) !== false){
42728 this.setFlagClass(record.data.iso2);
42729 this.setDialCode(record.data.dialCode);
42730 this.hasFocus = false;
42732 this.fireEvent('select', this, record, index);
42736 flagEl : function()
42738 var flag = this.el.select('div.flag',true).first();
42745 dialCodeHolderEl : function()
42747 var d = this.el.select('input.dial-code-holder',true).first();
42754 setDialCode : function(v)
42756 this.dialCodeHolder.dom.value = '+'+v;
42759 setFlagClass : function(n)
42761 this.flag.dom.className = 'flag '+n;
42764 getValue : function()
42766 var v = this.inputEl().getValue();
42767 if(this.dialCodeHolder) {
42768 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
42773 setValue : function(v)
42775 var d = this.getDialCode(v);
42777 //invalid dial code
42778 if(v.length == 0 || !d || d.length == 0) {
42780 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
42781 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42787 this.setFlagClass(this.dialCodeMapping[d].iso2);
42788 this.setDialCode(d);
42789 this.inputEl().dom.value = v.replace('+'+d,'');
42790 this.hiddenEl().dom.value = this.getValue();
42795 getDialCode : function(v)
42799 if (v.length == 0) {
42800 return this.dialCodeHolder.dom.value;
42804 if (v.charAt(0) != "+") {
42807 var numericChars = "";
42808 for (var i = 1; i < v.length; i++) {
42809 var c = v.charAt(i);
42812 if (this.dialCodeMapping[numericChars]) {
42813 dialCode = v.substr(1, i);
42815 if (numericChars.length == 4) {
42825 this.setValue(this.defaultDialCode);
42829 hiddenEl : function()
42831 return this.el.select('input.hidden-tel-input',true).first();
42834 // after setting val
42835 onKeyUp : function(e){
42836 this.setValue(this.getValue());
42839 onKeyPress : function(e){
42840 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
42847 * @class Roo.bootstrap.MoneyField
42848 * @extends Roo.bootstrap.ComboBox
42849 * Bootstrap MoneyField class
42852 * Create a new MoneyField.
42853 * @param {Object} config Configuration options
42856 Roo.bootstrap.MoneyField = function(config) {
42858 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
42862 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
42865 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
42867 allowDecimals : true,
42869 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
42871 decimalSeparator : ".",
42873 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
42875 decimalPrecision : 0,
42877 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
42879 allowNegative : true,
42881 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
42885 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
42887 minValue : Number.NEGATIVE_INFINITY,
42889 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
42891 maxValue : Number.MAX_VALUE,
42893 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
42895 minText : "The minimum value for this field is {0}",
42897 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
42899 maxText : "The maximum value for this field is {0}",
42901 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
42902 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
42904 nanText : "{0} is not a valid number",
42906 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
42910 * @cfg {String} defaults currency of the MoneyField
42911 * value should be in lkey
42913 defaultCurrency : false,
42915 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
42917 thousandsDelimiter : false,
42919 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
42930 getAutoCreate : function()
42932 var align = this.labelAlign || this.parentLabelAlign();
42944 cls : 'form-control roo-money-amount-input',
42945 autocomplete: 'new-password'
42948 var hiddenInput = {
42952 cls: 'hidden-number-input'
42955 if(this.max_length) {
42956 input.maxlength = this.max_length;
42960 hiddenInput.name = this.name;
42963 if (this.disabled) {
42964 input.disabled = true;
42967 var clg = 12 - this.inputlg;
42968 var cmd = 12 - this.inputmd;
42969 var csm = 12 - this.inputsm;
42970 var cxs = 12 - this.inputxs;
42974 cls : 'row roo-money-field',
42978 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42982 cls: 'roo-select2-container input-group',
42986 cls : 'form-control roo-money-currency-input',
42987 autocomplete: 'new-password',
42989 name : this.currencyName
42993 cls : 'input-group-addon',
43007 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
43011 cls: this.hasFeedback ? 'has-feedback' : '',
43022 if (this.fieldLabel.length) {
43025 tooltip: 'This field is required'
43031 cls: 'control-label',
43037 html: this.fieldLabel
43040 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
43046 if(this.indicatorpos == 'right') {
43047 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
43054 if(align == 'left') {
43062 if(this.labelWidth > 12){
43063 label.style = "width: " + this.labelWidth + 'px';
43065 if(this.labelWidth < 13 && this.labelmd == 0){
43066 this.labelmd = this.labelWidth;
43068 if(this.labellg > 0){
43069 label.cls += ' col-lg-' + this.labellg;
43070 input.cls += ' col-lg-' + (12 - this.labellg);
43072 if(this.labelmd > 0){
43073 label.cls += ' col-md-' + this.labelmd;
43074 container.cls += ' col-md-' + (12 - this.labelmd);
43076 if(this.labelsm > 0){
43077 label.cls += ' col-sm-' + this.labelsm;
43078 container.cls += ' col-sm-' + (12 - this.labelsm);
43080 if(this.labelxs > 0){
43081 label.cls += ' col-xs-' + this.labelxs;
43082 container.cls += ' col-xs-' + (12 - this.labelxs);
43093 var settings = this;
43095 ['xs','sm','md','lg'].map(function(size){
43096 if (settings[size]) {
43097 cfg.cls += ' col-' + size + '-' + settings[size];
43104 initEvents : function()
43106 this.indicator = this.indicatorEl();
43108 this.initCurrencyEvent();
43110 this.initNumberEvent();
43113 initCurrencyEvent : function()
43116 throw "can not find store for combo";
43119 this.store = Roo.factory(this.store, Roo.data);
43120 this.store.parent = this;
43124 this.triggerEl = this.el.select('.input-group-addon', true).first();
43126 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
43131 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
43132 _this.list.setWidth(lw);
43135 this.list.on('mouseover', this.onViewOver, this);
43136 this.list.on('mousemove', this.onViewMove, this);
43137 this.list.on('scroll', this.onViewScroll, this);
43140 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
43143 this.view = new Roo.View(this.list, this.tpl, {
43144 singleSelect:true, store: this.store, selectedClass: this.selectedClass
43147 this.view.on('click', this.onViewClick, this);
43149 this.store.on('beforeload', this.onBeforeLoad, this);
43150 this.store.on('load', this.onLoad, this);
43151 this.store.on('loadexception', this.onLoadException, this);
43153 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
43154 "up" : function(e){
43155 this.inKeyMode = true;
43159 "down" : function(e){
43160 if(!this.isExpanded()){
43161 this.onTriggerClick();
43163 this.inKeyMode = true;
43168 "enter" : function(e){
43171 if(this.fireEvent("specialkey", this, e)){
43172 this.onViewClick(false);
43178 "esc" : function(e){
43182 "tab" : function(e){
43185 if(this.fireEvent("specialkey", this, e)){
43186 this.onViewClick(false);
43194 doRelay : function(foo, bar, hname){
43195 if(hname == 'down' || this.scope.isExpanded()){
43196 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43204 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
43208 initNumberEvent : function(e)
43210 this.inputEl().on("keydown" , this.fireKey, this);
43211 this.inputEl().on("focus", this.onFocus, this);
43212 this.inputEl().on("blur", this.onBlur, this);
43214 this.inputEl().relayEvent('keyup', this);
43216 if(this.indicator){
43217 this.indicator.addClass('invisible');
43220 this.originalValue = this.getValue();
43222 if(this.validationEvent == 'keyup'){
43223 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
43224 this.inputEl().on('keyup', this.filterValidation, this);
43226 else if(this.validationEvent !== false){
43227 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
43230 if(this.selectOnFocus){
43231 this.on("focus", this.preFocus, this);
43234 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
43235 this.inputEl().on("keypress", this.filterKeys, this);
43237 this.inputEl().relayEvent('keypress', this);
43240 var allowed = "0123456789";
43242 if(this.allowDecimals){
43243 allowed += this.decimalSeparator;
43246 if(this.allowNegative){
43250 if(this.thousandsDelimiter) {
43254 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
43256 var keyPress = function(e){
43258 var k = e.getKey();
43260 var c = e.getCharCode();
43263 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
43264 allowed.indexOf(String.fromCharCode(c)) === -1
43270 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
43274 if(allowed.indexOf(String.fromCharCode(c)) === -1){
43279 this.inputEl().on("keypress", keyPress, this);
43283 onTriggerClick : function(e)
43290 this.loadNext = false;
43292 if(this.isExpanded()){
43297 this.hasFocus = true;
43299 if(this.triggerAction == 'all') {
43300 this.doQuery(this.allQuery, true);
43304 this.doQuery(this.getRawValue());
43307 getCurrency : function()
43309 var v = this.currencyEl().getValue();
43314 restrictHeight : function()
43316 this.list.alignTo(this.currencyEl(), this.listAlign);
43317 this.list.alignTo(this.currencyEl(), this.listAlign);
43320 onViewClick : function(view, doFocus, el, e)
43322 var index = this.view.getSelectedIndexes()[0];
43324 var r = this.store.getAt(index);
43327 this.onSelect(r, index);
43331 onSelect : function(record, index){
43333 if(this.fireEvent('beforeselect', this, record, index) !== false){
43335 this.setFromCurrencyData(index > -1 ? record.data : false);
43339 this.fireEvent('select', this, record, index);
43343 setFromCurrencyData : function(o)
43347 this.lastCurrency = o;
43349 if (this.currencyField) {
43350 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
43352 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
43355 this.lastSelectionText = currency;
43357 //setting default currency
43358 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
43359 this.setCurrency(this.defaultCurrency);
43363 this.setCurrency(currency);
43366 setFromData : function(o)
43370 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
43372 this.setFromCurrencyData(c);
43377 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
43379 Roo.log('no value set for '+ (this.name ? this.name : this.id));
43382 this.setValue(value);
43386 setCurrency : function(v)
43388 this.currencyValue = v;
43391 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
43396 setValue : function(v)
43398 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
43404 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
43406 this.inputEl().dom.value = (v == '') ? '' :
43407 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
43409 if(!this.allowZero && v === '0') {
43410 this.hiddenEl().dom.value = '';
43411 this.inputEl().dom.value = '';
43418 getRawValue : function()
43420 var v = this.inputEl().getValue();
43425 getValue : function()
43427 return this.fixPrecision(this.parseValue(this.getRawValue()));
43430 parseValue : function(value)
43432 if(this.thousandsDelimiter) {
43434 r = new RegExp(",", "g");
43435 value = value.replace(r, "");
43438 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
43439 return isNaN(value) ? '' : value;
43443 fixPrecision : function(value)
43445 if(this.thousandsDelimiter) {
43447 r = new RegExp(",", "g");
43448 value = value.replace(r, "");
43451 var nan = isNaN(value);
43453 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
43454 return nan ? '' : value;
43456 return parseFloat(value).toFixed(this.decimalPrecision);
43459 decimalPrecisionFcn : function(v)
43461 return Math.floor(v);
43464 validateValue : function(value)
43466 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
43470 var num = this.parseValue(value);
43473 this.markInvalid(String.format(this.nanText, value));
43477 if(num < this.minValue){
43478 this.markInvalid(String.format(this.minText, this.minValue));
43482 if(num > this.maxValue){
43483 this.markInvalid(String.format(this.maxText, this.maxValue));
43490 validate : function()
43492 if(this.disabled || this.allowBlank){
43497 var currency = this.getCurrency();
43499 if(this.validateValue(this.getRawValue()) && currency.length){
43504 this.markInvalid();
43508 getName: function()
43513 beforeBlur : function()
43519 var v = this.parseValue(this.getRawValue());
43526 onBlur : function()
43530 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43531 //this.el.removeClass(this.focusClass);
43534 this.hasFocus = false;
43536 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
43540 var v = this.getValue();
43542 if(String(v) !== String(this.startValue)){
43543 this.fireEvent('change', this, v, this.startValue);
43546 this.fireEvent("blur", this);
43549 inputEl : function()
43551 return this.el.select('.roo-money-amount-input', true).first();
43554 currencyEl : function()
43556 return this.el.select('.roo-money-currency-input', true).first();
43559 hiddenEl : function()
43561 return this.el.select('input.hidden-number-input',true).first();
43565 * @class Roo.bootstrap.BezierSignature
43566 * @extends Roo.bootstrap.Component
43567 * Bootstrap BezierSignature class
43568 * This script refer to:
43569 * Title: Signature Pad
43571 * Availability: https://github.com/szimek/signature_pad
43574 * Create a new BezierSignature
43575 * @param {Object} config The config object
43578 Roo.bootstrap.BezierSignature = function(config){
43579 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
43585 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
43592 mouse_btn_down: true,
43595 * @cfg {int} canvas height
43597 canvas_height: '200px',
43600 * @cfg {float|function} Radius of a single dot.
43605 * @cfg {float} Minimum width of a line. Defaults to 0.5.
43610 * @cfg {float} Maximum width of a line. Defaults to 2.5.
43615 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
43620 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
43625 * @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.
43627 bg_color: 'rgba(0, 0, 0, 0)',
43630 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
43632 dot_color: 'black',
43635 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
43637 velocity_filter_weight: 0.7,
43640 * @cfg {function} Callback when stroke begin.
43645 * @cfg {function} Callback when stroke end.
43649 getAutoCreate : function()
43651 var cls = 'roo-signature column';
43654 cls += ' ' + this.cls;
43664 for(var i = 0; i < col_sizes.length; i++) {
43665 if(this[col_sizes[i]]) {
43666 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
43676 cls: 'roo-signature-body',
43680 cls: 'roo-signature-body-canvas',
43681 height: this.canvas_height,
43682 width: this.canvas_width
43689 style: 'display: none'
43697 initEvents: function()
43699 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
43701 var canvas = this.canvasEl();
43703 // mouse && touch event swapping...
43704 canvas.dom.style.touchAction = 'none';
43705 canvas.dom.style.msTouchAction = 'none';
43707 this.mouse_btn_down = false;
43708 canvas.on('mousedown', this._handleMouseDown, this);
43709 canvas.on('mousemove', this._handleMouseMove, this);
43710 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
43712 if (window.PointerEvent) {
43713 canvas.on('pointerdown', this._handleMouseDown, this);
43714 canvas.on('pointermove', this._handleMouseMove, this);
43715 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
43718 if ('ontouchstart' in window) {
43719 canvas.on('touchstart', this._handleTouchStart, this);
43720 canvas.on('touchmove', this._handleTouchMove, this);
43721 canvas.on('touchend', this._handleTouchEnd, this);
43724 Roo.EventManager.onWindowResize(this.resize, this, true);
43726 // file input event
43727 this.fileEl().on('change', this.uploadImage, this);
43734 resize: function(){
43736 var canvas = this.canvasEl().dom;
43737 var ctx = this.canvasElCtx();
43738 var img_data = false;
43740 if(canvas.width > 0) {
43741 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
43743 // setting canvas width will clean img data
43746 var style = window.getComputedStyle ?
43747 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
43749 var padding_left = parseInt(style.paddingLeft) || 0;
43750 var padding_right = parseInt(style.paddingRight) || 0;
43752 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
43755 ctx.putImageData(img_data, 0, 0);
43759 _handleMouseDown: function(e)
43761 if (e.browserEvent.which === 1) {
43762 this.mouse_btn_down = true;
43763 this.strokeBegin(e);
43767 _handleMouseMove: function (e)
43769 if (this.mouse_btn_down) {
43770 this.strokeMoveUpdate(e);
43774 _handleMouseUp: function (e)
43776 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
43777 this.mouse_btn_down = false;
43782 _handleTouchStart: function (e) {
43784 e.preventDefault();
43785 if (e.browserEvent.targetTouches.length === 1) {
43786 // var touch = e.browserEvent.changedTouches[0];
43787 // this.strokeBegin(touch);
43789 this.strokeBegin(e); // assume e catching the correct xy...
43793 _handleTouchMove: function (e) {
43794 e.preventDefault();
43795 // var touch = event.targetTouches[0];
43796 // _this._strokeMoveUpdate(touch);
43797 this.strokeMoveUpdate(e);
43800 _handleTouchEnd: function (e) {
43801 var wasCanvasTouched = e.target === this.canvasEl().dom;
43802 if (wasCanvasTouched) {
43803 e.preventDefault();
43804 // var touch = event.changedTouches[0];
43805 // _this._strokeEnd(touch);
43810 reset: function () {
43811 this._lastPoints = [];
43812 this._lastVelocity = 0;
43813 this._lastWidth = (this.min_width + this.max_width) / 2;
43814 this.canvasElCtx().fillStyle = this.dot_color;
43817 strokeMoveUpdate: function(e)
43819 this.strokeUpdate(e);
43821 if (this.throttle) {
43822 this.throttleStroke(this.strokeUpdate, this.throttle);
43825 this.strokeUpdate(e);
43829 strokeBegin: function(e)
43831 var newPointGroup = {
43832 color: this.dot_color,
43836 if (typeof this.onBegin === 'function') {
43840 this.curve_data.push(newPointGroup);
43842 this.strokeUpdate(e);
43845 strokeUpdate: function(e)
43847 var rect = this.canvasEl().dom.getBoundingClientRect();
43848 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
43849 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
43850 var lastPoints = lastPointGroup.points;
43851 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
43852 var isLastPointTooClose = lastPoint
43853 ? point.distanceTo(lastPoint) <= this.min_distance
43855 var color = lastPointGroup.color;
43856 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
43857 var curve = this.addPoint(point);
43859 this.drawDot({color: color, point: point});
43862 this.drawCurve({color: color, curve: curve});
43872 strokeEnd: function(e)
43874 this.strokeUpdate(e);
43875 if (typeof this.onEnd === 'function') {
43880 addPoint: function (point) {
43881 var _lastPoints = this._lastPoints;
43882 _lastPoints.push(point);
43883 if (_lastPoints.length > 2) {
43884 if (_lastPoints.length === 3) {
43885 _lastPoints.unshift(_lastPoints[0]);
43887 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
43888 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
43889 _lastPoints.shift();
43895 calculateCurveWidths: function (startPoint, endPoint) {
43896 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
43897 (1 - this.velocity_filter_weight) * this._lastVelocity;
43899 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
43902 start: this._lastWidth
43905 this._lastVelocity = velocity;
43906 this._lastWidth = newWidth;
43910 drawDot: function (_a) {
43911 var color = _a.color, point = _a.point;
43912 var ctx = this.canvasElCtx();
43913 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
43915 this.drawCurveSegment(point.x, point.y, width);
43917 ctx.fillStyle = color;
43921 drawCurve: function (_a) {
43922 var color = _a.color, curve = _a.curve;
43923 var ctx = this.canvasElCtx();
43924 var widthDelta = curve.endWidth - curve.startWidth;
43925 var drawSteps = Math.floor(curve.length()) * 2;
43927 ctx.fillStyle = color;
43928 for (var i = 0; i < drawSteps; i += 1) {
43929 var t = i / drawSteps;
43935 var x = uuu * curve.startPoint.x;
43936 x += 3 * uu * t * curve.control1.x;
43937 x += 3 * u * tt * curve.control2.x;
43938 x += ttt * curve.endPoint.x;
43939 var y = uuu * curve.startPoint.y;
43940 y += 3 * uu * t * curve.control1.y;
43941 y += 3 * u * tt * curve.control2.y;
43942 y += ttt * curve.endPoint.y;
43943 var width = curve.startWidth + ttt * widthDelta;
43944 this.drawCurveSegment(x, y, width);
43950 drawCurveSegment: function (x, y, width) {
43951 var ctx = this.canvasElCtx();
43953 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43954 this.is_empty = false;
43959 var ctx = this.canvasElCtx();
43960 var canvas = this.canvasEl().dom;
43961 ctx.fillStyle = this.bg_color;
43962 ctx.clearRect(0, 0, canvas.width, canvas.height);
43963 ctx.fillRect(0, 0, canvas.width, canvas.height);
43964 this.curve_data = [];
43966 this.is_empty = true;
43971 return this.el.select('input',true).first();
43974 canvasEl: function()
43976 return this.el.select('canvas',true).first();
43979 canvasElCtx: function()
43981 return this.el.select('canvas',true).first().dom.getContext('2d');
43984 getImage: function(type)
43986 if(this.is_empty) {
43991 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43994 drawFromImage: function(img_src)
43996 var img = new Image();
43998 img.onload = function(){
43999 this.canvasElCtx().drawImage(img, 0, 0);
44004 this.is_empty = false;
44007 selectImage: function()
44009 this.fileEl().dom.click();
44012 uploadImage: function(e)
44014 var reader = new FileReader();
44016 reader.onload = function(e){
44017 var img = new Image();
44018 img.onload = function(){
44020 this.canvasElCtx().drawImage(img, 0, 0);
44022 img.src = e.target.result;
44025 reader.readAsDataURL(e.target.files[0]);
44028 // Bezier Point Constructor
44029 Point: (function () {
44030 function Point(x, y, time) {
44033 this.time = time || Date.now();
44035 Point.prototype.distanceTo = function (start) {
44036 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
44038 Point.prototype.equals = function (other) {
44039 return this.x === other.x && this.y === other.y && this.time === other.time;
44041 Point.prototype.velocityFrom = function (start) {
44042 return this.time !== start.time
44043 ? this.distanceTo(start) / (this.time - start.time)
44050 // Bezier Constructor
44051 Bezier: (function () {
44052 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
44053 this.startPoint = startPoint;
44054 this.control2 = control2;
44055 this.control1 = control1;
44056 this.endPoint = endPoint;
44057 this.startWidth = startWidth;
44058 this.endWidth = endWidth;
44060 Bezier.fromPoints = function (points, widths, scope) {
44061 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
44062 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
44063 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
44065 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
44066 var dx1 = s1.x - s2.x;
44067 var dy1 = s1.y - s2.y;
44068 var dx2 = s2.x - s3.x;
44069 var dy2 = s2.y - s3.y;
44070 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
44071 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
44072 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
44073 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
44074 var dxm = m1.x - m2.x;
44075 var dym = m1.y - m2.y;
44076 var k = l2 / (l1 + l2);
44077 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
44078 var tx = s2.x - cm.x;
44079 var ty = s2.y - cm.y;
44081 c1: new scope.Point(m1.x + tx, m1.y + ty),
44082 c2: new scope.Point(m2.x + tx, m2.y + ty)
44085 Bezier.prototype.length = function () {
44090 for (var i = 0; i <= steps; i += 1) {
44092 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
44093 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
44095 var xdiff = cx - px;
44096 var ydiff = cy - py;
44097 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
44104 Bezier.prototype.point = function (t, start, c1, c2, end) {
44105 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
44106 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
44107 + (3.0 * c2 * (1.0 - t) * t * t)
44108 + (end * t * t * t);
44113 throttleStroke: function(fn, wait) {
44114 if (wait === void 0) { wait = 250; }
44116 var timeout = null;
44120 var later = function () {
44121 previous = Date.now();
44123 result = fn.apply(storedContext, storedArgs);
44125 storedContext = null;
44129 return function wrapper() {
44131 for (var _i = 0; _i < arguments.length; _i++) {
44132 args[_i] = arguments[_i];
44134 var now = Date.now();
44135 var remaining = wait - (now - previous);
44136 storedContext = this;
44138 if (remaining <= 0 || remaining > wait) {
44140 clearTimeout(timeout);
44144 result = fn.apply(storedContext, storedArgs);
44146 storedContext = null;
44150 else if (!timeout) {
44151 timeout = window.setTimeout(later, remaining);