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.bootstrap.breadcrumb.Nav = function(config){
6625 Roo.bootstrap.breadcrumb.Nav.superclass.constructor.call(this, config);
6630 Roo.extend(Roo.bootstrap.breadcrumb.Nav, Roo.bootstrap.Component, {
6632 getAutoCreate : function()
6649 initEvents: function()
6651 this.olEl = this.el.select('ol',true).first();
6653 getChildContainer : function()
6669 * @class Roo.bootstrap.breadcrumb.Nav
6670 * @extends Roo.bootstrap.Component
6671 * Bootstrap Breadcrumb Nav Class
6673 * @children Roo.bootstrap.breadcrumb.Component
6674 * @cfg {String} html the content of the link.
6675 * @cfg {String} href where it links to if '#' is used the link will be handled by onClick.
6676 * @cfg {Boolean} active is it active
6680 * Create a new breadcrumb.Nav
6681 * @param {Object} config The config object
6684 Roo.bootstrap.breadcrumb.Item = function(config){
6685 Roo.bootstrap.breadcrumb.Item.superclass.constructor.call(this, config);
6690 * The img click event for the img.
6691 * @param {Roo.EventObject} e
6698 Roo.extend(Roo.bootstrap.breadcrumb.Item, Roo.bootstrap.Component, {
6703 getAutoCreate : function()
6708 cls : 'breadcrumb-item' + (this.active ? ' active' : '')
6710 if (this.href !== false) {
6717 cfg.html = this.html;
6723 initEvents: function()
6726 this.el.select('a', true).first().onClick(this.onClick, this)
6730 onClick : function(e)
6733 this.fireEvent('click',this, e);
6746 * @class Roo.bootstrap.Row
6747 * @extends Roo.bootstrap.Component
6748 * Bootstrap Row class (contains columns...)
6752 * @param {Object} config The config object
6755 Roo.bootstrap.Row = function(config){
6756 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6759 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6761 getAutoCreate : function(){
6780 * @class Roo.bootstrap.Pagination
6781 * @extends Roo.bootstrap.Component
6782 * Bootstrap Pagination class
6783 * @cfg {String} size xs | sm | md | lg
6784 * @cfg {Boolean} inverse false | true
6787 * Create a new Pagination
6788 * @param {Object} config The config object
6791 Roo.bootstrap.Pagination = function(config){
6792 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6795 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6801 getAutoCreate : function(){
6807 cfg.cls += ' inverse';
6813 cfg.cls += " " + this.cls;
6831 * @class Roo.bootstrap.PaginationItem
6832 * @extends Roo.bootstrap.Component
6833 * Bootstrap PaginationItem class
6834 * @cfg {String} html text
6835 * @cfg {String} href the link
6836 * @cfg {Boolean} preventDefault (true | false) default true
6837 * @cfg {Boolean} active (true | false) default false
6838 * @cfg {Boolean} disabled default false
6842 * Create a new PaginationItem
6843 * @param {Object} config The config object
6847 Roo.bootstrap.PaginationItem = function(config){
6848 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6853 * The raw click event for the entire grid.
6854 * @param {Roo.EventObject} e
6860 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6864 preventDefault: true,
6869 getAutoCreate : function(){
6875 href : this.href ? this.href : '#',
6876 html : this.html ? this.html : ''
6886 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6890 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6896 initEvents: function() {
6898 this.el.on('click', this.onClick, this);
6901 onClick : function(e)
6903 Roo.log('PaginationItem on click ');
6904 if(this.preventDefault){
6912 this.fireEvent('click', this, e);
6928 * @class Roo.bootstrap.Slider
6929 * @extends Roo.bootstrap.Component
6930 * Bootstrap Slider class
6933 * Create a new Slider
6934 * @param {Object} config The config object
6937 Roo.bootstrap.Slider = function(config){
6938 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6941 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6943 getAutoCreate : function(){
6947 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6951 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6963 * Ext JS Library 1.1.1
6964 * Copyright(c) 2006-2007, Ext JS, LLC.
6966 * Originally Released Under LGPL - original licence link has changed is not relivant.
6969 * <script type="text/javascript">
6974 * @class Roo.grid.ColumnModel
6975 * @extends Roo.util.Observable
6976 * This is the default implementation of a ColumnModel used by the Grid. It defines
6977 * the columns in the grid.
6980 var colModel = new Roo.grid.ColumnModel([
6981 {header: "Ticker", width: 60, sortable: true, locked: true},
6982 {header: "Company Name", width: 150, sortable: true},
6983 {header: "Market Cap.", width: 100, sortable: true},
6984 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6985 {header: "Employees", width: 100, sortable: true, resizable: false}
6990 * The config options listed for this class are options which may appear in each
6991 * individual column definition.
6992 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
6994 * @param {Object} config An Array of column config objects. See this class's
6995 * config objects for details.
6997 Roo.grid.ColumnModel = function(config){
6999 * The config passed into the constructor
7001 this.config = config;
7004 // if no id, create one
7005 // if the column does not have a dataIndex mapping,
7006 // map it to the order it is in the config
7007 for(var i = 0, len = config.length; i < len; i++){
7009 if(typeof c.dataIndex == "undefined"){
7012 if(typeof c.renderer == "string"){
7013 c.renderer = Roo.util.Format[c.renderer];
7015 if(typeof c.id == "undefined"){
7018 if(c.editor && c.editor.xtype){
7019 c.editor = Roo.factory(c.editor, Roo.grid);
7021 if(c.editor && c.editor.isFormField){
7022 c.editor = new Roo.grid.GridEditor(c.editor);
7024 this.lookup[c.id] = c;
7028 * The width of columns which have no width specified (defaults to 100)
7031 this.defaultWidth = 100;
7034 * Default sortable of columns which have no sortable specified (defaults to false)
7037 this.defaultSortable = false;
7041 * @event widthchange
7042 * Fires when the width of a column changes.
7043 * @param {ColumnModel} this
7044 * @param {Number} columnIndex The column index
7045 * @param {Number} newWidth The new width
7047 "widthchange": true,
7049 * @event headerchange
7050 * Fires when the text of a header changes.
7051 * @param {ColumnModel} this
7052 * @param {Number} columnIndex The column index
7053 * @param {Number} newText The new header text
7055 "headerchange": true,
7057 * @event hiddenchange
7058 * Fires when a column is hidden or "unhidden".
7059 * @param {ColumnModel} this
7060 * @param {Number} columnIndex The column index
7061 * @param {Boolean} hidden true if hidden, false otherwise
7063 "hiddenchange": true,
7065 * @event columnmoved
7066 * Fires when a column is moved.
7067 * @param {ColumnModel} this
7068 * @param {Number} oldIndex
7069 * @param {Number} newIndex
7071 "columnmoved" : true,
7073 * @event columlockchange
7074 * Fires when a column's locked state is changed
7075 * @param {ColumnModel} this
7076 * @param {Number} colIndex
7077 * @param {Boolean} locked true if locked
7079 "columnlockchange" : true
7081 Roo.grid.ColumnModel.superclass.constructor.call(this);
7083 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
7085 * @cfg {String} header The header text to display in the Grid view.
7088 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
7089 * {@link Roo.data.Record} definition from which to draw the column's value. If not
7090 * specified, the column's index is used as an index into the Record's data Array.
7093 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
7094 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
7097 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
7098 * Defaults to the value of the {@link #defaultSortable} property.
7099 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
7102 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
7105 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
7108 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
7111 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
7114 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
7115 * given the cell's data value. See {@link #setRenderer}. If not specified, the
7116 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
7117 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
7120 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
7123 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
7126 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
7129 * @cfg {String} cursor (Optional)
7132 * @cfg {String} tooltip (Optional)
7135 * @cfg {Number} xs (Optional)
7138 * @cfg {Number} sm (Optional)
7141 * @cfg {Number} md (Optional)
7144 * @cfg {Number} lg (Optional)
7147 * Returns the id of the column at the specified index.
7148 * @param {Number} index The column index
7149 * @return {String} the id
7151 getColumnId : function(index){
7152 return this.config[index].id;
7156 * Returns the column for a specified id.
7157 * @param {String} id The column id
7158 * @return {Object} the column
7160 getColumnById : function(id){
7161 return this.lookup[id];
7166 * Returns the column for a specified dataIndex.
7167 * @param {String} dataIndex The column dataIndex
7168 * @return {Object|Boolean} the column or false if not found
7170 getColumnByDataIndex: function(dataIndex){
7171 var index = this.findColumnIndex(dataIndex);
7172 return index > -1 ? this.config[index] : false;
7176 * Returns the index for a specified column id.
7177 * @param {String} id The column id
7178 * @return {Number} the index, or -1 if not found
7180 getIndexById : function(id){
7181 for(var i = 0, len = this.config.length; i < len; i++){
7182 if(this.config[i].id == id){
7190 * Returns the index for a specified column dataIndex.
7191 * @param {String} dataIndex The column dataIndex
7192 * @return {Number} the index, or -1 if not found
7195 findColumnIndex : function(dataIndex){
7196 for(var i = 0, len = this.config.length; i < len; i++){
7197 if(this.config[i].dataIndex == dataIndex){
7205 moveColumn : function(oldIndex, newIndex){
7206 var c = this.config[oldIndex];
7207 this.config.splice(oldIndex, 1);
7208 this.config.splice(newIndex, 0, c);
7209 this.dataMap = null;
7210 this.fireEvent("columnmoved", this, oldIndex, newIndex);
7213 isLocked : function(colIndex){
7214 return this.config[colIndex].locked === true;
7217 setLocked : function(colIndex, value, suppressEvent){
7218 if(this.isLocked(colIndex) == value){
7221 this.config[colIndex].locked = value;
7223 this.fireEvent("columnlockchange", this, colIndex, value);
7227 getTotalLockedWidth : function(){
7229 for(var i = 0; i < this.config.length; i++){
7230 if(this.isLocked(i) && !this.isHidden(i)){
7231 this.totalWidth += this.getColumnWidth(i);
7237 getLockedCount : function(){
7238 for(var i = 0, len = this.config.length; i < len; i++){
7239 if(!this.isLocked(i)){
7244 return this.config.length;
7248 * Returns the number of columns.
7251 getColumnCount : function(visibleOnly){
7252 if(visibleOnly === true){
7254 for(var i = 0, len = this.config.length; i < len; i++){
7255 if(!this.isHidden(i)){
7261 return this.config.length;
7265 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
7266 * @param {Function} fn
7267 * @param {Object} scope (optional)
7268 * @return {Array} result
7270 getColumnsBy : function(fn, scope){
7272 for(var i = 0, len = this.config.length; i < len; i++){
7273 var c = this.config[i];
7274 if(fn.call(scope||this, c, i) === true){
7282 * Returns true if the specified column is sortable.
7283 * @param {Number} col The column index
7286 isSortable : function(col){
7287 if(typeof this.config[col].sortable == "undefined"){
7288 return this.defaultSortable;
7290 return this.config[col].sortable;
7294 * Returns the rendering (formatting) function defined for the column.
7295 * @param {Number} col The column index.
7296 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
7298 getRenderer : function(col){
7299 if(!this.config[col].renderer){
7300 return Roo.grid.ColumnModel.defaultRenderer;
7302 return this.config[col].renderer;
7306 * Sets the rendering (formatting) function for a column.
7307 * @param {Number} col The column index
7308 * @param {Function} fn The function to use to process the cell's raw data
7309 * to return HTML markup for the grid view. The render function is called with
7310 * the following parameters:<ul>
7311 * <li>Data value.</li>
7312 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
7313 * <li>css A CSS style string to apply to the table cell.</li>
7314 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
7315 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
7316 * <li>Row index</li>
7317 * <li>Column index</li>
7318 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
7320 setRenderer : function(col, fn){
7321 this.config[col].renderer = fn;
7325 * Returns the width for the specified column.
7326 * @param {Number} col The column index
7329 getColumnWidth : function(col){
7330 return this.config[col].width * 1 || this.defaultWidth;
7334 * Sets the width for a column.
7335 * @param {Number} col The column index
7336 * @param {Number} width The new width
7338 setColumnWidth : function(col, width, suppressEvent){
7339 this.config[col].width = width;
7340 this.totalWidth = null;
7342 this.fireEvent("widthchange", this, col, width);
7347 * Returns the total width of all columns.
7348 * @param {Boolean} includeHidden True to include hidden column widths
7351 getTotalWidth : function(includeHidden){
7352 if(!this.totalWidth){
7353 this.totalWidth = 0;
7354 for(var i = 0, len = this.config.length; i < len; i++){
7355 if(includeHidden || !this.isHidden(i)){
7356 this.totalWidth += this.getColumnWidth(i);
7360 return this.totalWidth;
7364 * Returns the header for the specified column.
7365 * @param {Number} col The column index
7368 getColumnHeader : function(col){
7369 return this.config[col].header;
7373 * Sets the header for a column.
7374 * @param {Number} col The column index
7375 * @param {String} header The new header
7377 setColumnHeader : function(col, header){
7378 this.config[col].header = header;
7379 this.fireEvent("headerchange", this, col, header);
7383 * Returns the tooltip for the specified column.
7384 * @param {Number} col The column index
7387 getColumnTooltip : function(col){
7388 return this.config[col].tooltip;
7391 * Sets the tooltip for a column.
7392 * @param {Number} col The column index
7393 * @param {String} tooltip The new tooltip
7395 setColumnTooltip : function(col, tooltip){
7396 this.config[col].tooltip = tooltip;
7400 * Returns the dataIndex for the specified column.
7401 * @param {Number} col The column index
7404 getDataIndex : function(col){
7405 return this.config[col].dataIndex;
7409 * Sets the dataIndex for a column.
7410 * @param {Number} col The column index
7411 * @param {Number} dataIndex The new dataIndex
7413 setDataIndex : function(col, dataIndex){
7414 this.config[col].dataIndex = dataIndex;
7420 * Returns true if the cell is editable.
7421 * @param {Number} colIndex The column index
7422 * @param {Number} rowIndex The row index - this is nto actually used..?
7425 isCellEditable : function(colIndex, rowIndex){
7426 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
7430 * Returns the editor defined for the cell/column.
7431 * return false or null to disable editing.
7432 * @param {Number} colIndex The column index
7433 * @param {Number} rowIndex The row index
7436 getCellEditor : function(colIndex, rowIndex){
7437 return this.config[colIndex].editor;
7441 * Sets if a column is editable.
7442 * @param {Number} col The column index
7443 * @param {Boolean} editable True if the column is editable
7445 setEditable : function(col, editable){
7446 this.config[col].editable = editable;
7451 * Returns true if the column is hidden.
7452 * @param {Number} colIndex The column index
7455 isHidden : function(colIndex){
7456 return this.config[colIndex].hidden;
7461 * Returns true if the column width cannot be changed
7463 isFixed : function(colIndex){
7464 return this.config[colIndex].fixed;
7468 * Returns true if the column can be resized
7471 isResizable : function(colIndex){
7472 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7475 * Sets if a column is hidden.
7476 * @param {Number} colIndex The column index
7477 * @param {Boolean} hidden True if the column is hidden
7479 setHidden : function(colIndex, hidden){
7480 this.config[colIndex].hidden = hidden;
7481 this.totalWidth = null;
7482 this.fireEvent("hiddenchange", this, colIndex, hidden);
7486 * Sets the editor for a column.
7487 * @param {Number} col The column index
7488 * @param {Object} editor The editor object
7490 setEditor : function(col, editor){
7491 this.config[col].editor = editor;
7495 Roo.grid.ColumnModel.defaultRenderer = function(value)
7497 if(typeof value == "object") {
7500 if(typeof value == "string" && value.length < 1){
7504 return String.format("{0}", value);
7507 // Alias for backwards compatibility
7508 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7511 * Ext JS Library 1.1.1
7512 * Copyright(c) 2006-2007, Ext JS, LLC.
7514 * Originally Released Under LGPL - original licence link has changed is not relivant.
7517 * <script type="text/javascript">
7521 * @class Roo.LoadMask
7522 * A simple utility class for generically masking elements while loading data. If the element being masked has
7523 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7524 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7525 * element's UpdateManager load indicator and will be destroyed after the initial load.
7527 * Create a new LoadMask
7528 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7529 * @param {Object} config The config object
7531 Roo.LoadMask = function(el, config){
7532 this.el = Roo.get(el);
7533 Roo.apply(this, config);
7535 this.store.on('beforeload', this.onBeforeLoad, this);
7536 this.store.on('load', this.onLoad, this);
7537 this.store.on('loadexception', this.onLoadException, this);
7538 this.removeMask = false;
7540 var um = this.el.getUpdateManager();
7541 um.showLoadIndicator = false; // disable the default indicator
7542 um.on('beforeupdate', this.onBeforeLoad, this);
7543 um.on('update', this.onLoad, this);
7544 um.on('failure', this.onLoad, this);
7545 this.removeMask = true;
7549 Roo.LoadMask.prototype = {
7551 * @cfg {Boolean} removeMask
7552 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7553 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7557 * The text to display in a centered loading message box (defaults to 'Loading...')
7561 * @cfg {String} msgCls
7562 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7564 msgCls : 'x-mask-loading',
7567 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7573 * Disables the mask to prevent it from being displayed
7575 disable : function(){
7576 this.disabled = true;
7580 * Enables the mask so that it can be displayed
7582 enable : function(){
7583 this.disabled = false;
7586 onLoadException : function()
7590 if (typeof(arguments[3]) != 'undefined') {
7591 Roo.MessageBox.alert("Error loading",arguments[3]);
7595 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7596 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7603 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7608 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7612 onBeforeLoad : function(){
7614 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7619 destroy : function(){
7621 this.store.un('beforeload', this.onBeforeLoad, this);
7622 this.store.un('load', this.onLoad, this);
7623 this.store.un('loadexception', this.onLoadException, this);
7625 var um = this.el.getUpdateManager();
7626 um.un('beforeupdate', this.onBeforeLoad, this);
7627 um.un('update', this.onLoad, this);
7628 um.un('failure', this.onLoad, this);
7639 * @class Roo.bootstrap.Table
7640 * @extends Roo.bootstrap.Component
7641 * Bootstrap Table class
7642 * @cfg {String} cls table class
7643 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7644 * @cfg {String} bgcolor Specifies the background color for a table
7645 * @cfg {Number} border Specifies whether the table cells should have borders or not
7646 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7647 * @cfg {Number} cellspacing Specifies the space between cells
7648 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7649 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7650 * @cfg {String} sortable Specifies that the table should be sortable
7651 * @cfg {String} summary Specifies a summary of the content of a table
7652 * @cfg {Number} width Specifies the width of a table
7653 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7655 * @cfg {boolean} striped Should the rows be alternative striped
7656 * @cfg {boolean} bordered Add borders to the table
7657 * @cfg {boolean} hover Add hover highlighting
7658 * @cfg {boolean} condensed Format condensed
7659 * @cfg {boolean} responsive Format condensed
7660 * @cfg {Boolean} loadMask (true|false) default false
7661 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7662 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7663 * @cfg {Boolean} rowSelection (true|false) default false
7664 * @cfg {Boolean} cellSelection (true|false) default false
7665 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7666 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7667 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7668 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7672 * Create a new Table
7673 * @param {Object} config The config object
7676 Roo.bootstrap.Table = function(config){
7677 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7682 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7683 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7684 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7685 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7687 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7689 this.sm.grid = this;
7690 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7691 this.sm = this.selModel;
7692 this.sm.xmodule = this.xmodule || false;
7695 if (this.cm && typeof(this.cm.config) == 'undefined') {
7696 this.colModel = new Roo.grid.ColumnModel(this.cm);
7697 this.cm = this.colModel;
7698 this.cm.xmodule = this.xmodule || false;
7701 this.store= Roo.factory(this.store, Roo.data);
7702 this.ds = this.store;
7703 this.ds.xmodule = this.xmodule || false;
7706 if (this.footer && this.store) {
7707 this.footer.dataSource = this.ds;
7708 this.footer = Roo.factory(this.footer);
7715 * Fires when a cell is clicked
7716 * @param {Roo.bootstrap.Table} this
7717 * @param {Roo.Element} el
7718 * @param {Number} rowIndex
7719 * @param {Number} columnIndex
7720 * @param {Roo.EventObject} e
7724 * @event celldblclick
7725 * Fires when a cell is double clicked
7726 * @param {Roo.bootstrap.Table} this
7727 * @param {Roo.Element} el
7728 * @param {Number} rowIndex
7729 * @param {Number} columnIndex
7730 * @param {Roo.EventObject} e
7732 "celldblclick" : true,
7735 * Fires when a row is clicked
7736 * @param {Roo.bootstrap.Table} this
7737 * @param {Roo.Element} el
7738 * @param {Number} rowIndex
7739 * @param {Roo.EventObject} e
7743 * @event rowdblclick
7744 * Fires when a row is double clicked
7745 * @param {Roo.bootstrap.Table} this
7746 * @param {Roo.Element} el
7747 * @param {Number} rowIndex
7748 * @param {Roo.EventObject} e
7750 "rowdblclick" : true,
7753 * Fires when a mouseover occur
7754 * @param {Roo.bootstrap.Table} this
7755 * @param {Roo.Element} el
7756 * @param {Number} rowIndex
7757 * @param {Number} columnIndex
7758 * @param {Roo.EventObject} e
7763 * Fires when a mouseout occur
7764 * @param {Roo.bootstrap.Table} this
7765 * @param {Roo.Element} el
7766 * @param {Number} rowIndex
7767 * @param {Number} columnIndex
7768 * @param {Roo.EventObject} e
7773 * Fires when a row is rendered, so you can change add a style to it.
7774 * @param {Roo.bootstrap.Table} this
7775 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7779 * @event rowsrendered
7780 * Fires when all the rows have been rendered
7781 * @param {Roo.bootstrap.Table} this
7783 'rowsrendered' : true,
7785 * @event contextmenu
7786 * The raw contextmenu event for the entire grid.
7787 * @param {Roo.EventObject} e
7789 "contextmenu" : true,
7791 * @event rowcontextmenu
7792 * Fires when a row is right clicked
7793 * @param {Roo.bootstrap.Table} this
7794 * @param {Number} rowIndex
7795 * @param {Roo.EventObject} e
7797 "rowcontextmenu" : true,
7799 * @event cellcontextmenu
7800 * Fires when a cell is right clicked
7801 * @param {Roo.bootstrap.Table} this
7802 * @param {Number} rowIndex
7803 * @param {Number} cellIndex
7804 * @param {Roo.EventObject} e
7806 "cellcontextmenu" : true,
7808 * @event headercontextmenu
7809 * Fires when a header is right clicked
7810 * @param {Roo.bootstrap.Table} this
7811 * @param {Number} columnIndex
7812 * @param {Roo.EventObject} e
7814 "headercontextmenu" : true
7818 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7844 rowSelection : false,
7845 cellSelection : false,
7848 // Roo.Element - the tbody
7850 // Roo.Element - thead element
7853 container: false, // used by gridpanel...
7859 auto_hide_footer : false,
7861 getAutoCreate : function()
7863 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7870 if (this.scrollBody) {
7871 cfg.cls += ' table-body-fixed';
7874 cfg.cls += ' table-striped';
7878 cfg.cls += ' table-hover';
7880 if (this.bordered) {
7881 cfg.cls += ' table-bordered';
7883 if (this.condensed) {
7884 cfg.cls += ' table-condensed';
7886 if (this.responsive) {
7887 cfg.cls += ' table-responsive';
7891 cfg.cls+= ' ' +this.cls;
7894 // this lot should be simplifed...
7907 ].forEach(function(k) {
7915 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7918 if(this.store || this.cm){
7919 if(this.headerShow){
7920 cfg.cn.push(this.renderHeader());
7923 cfg.cn.push(this.renderBody());
7925 if(this.footerShow){
7926 cfg.cn.push(this.renderFooter());
7928 // where does this come from?
7929 //cfg.cls+= ' TableGrid';
7932 return { cn : [ cfg ] };
7935 initEvents : function()
7937 if(!this.store || !this.cm){
7940 if (this.selModel) {
7941 this.selModel.initEvents();
7945 //Roo.log('initEvents with ds!!!!');
7947 this.mainBody = this.el.select('tbody', true).first();
7948 this.mainHead = this.el.select('thead', true).first();
7949 this.mainFoot = this.el.select('tfoot', true).first();
7955 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7956 e.on('click', _this.sort, _this);
7959 this.mainBody.on("click", this.onClick, this);
7960 this.mainBody.on("dblclick", this.onDblClick, this);
7962 // why is this done????? = it breaks dialogs??
7963 //this.parent().el.setStyle('position', 'relative');
7967 this.footer.parentId = this.id;
7968 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7971 this.el.select('tfoot tr td').first().addClass('hide');
7976 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7979 this.store.on('load', this.onLoad, this);
7980 this.store.on('beforeload', this.onBeforeLoad, this);
7981 this.store.on('update', this.onUpdate, this);
7982 this.store.on('add', this.onAdd, this);
7983 this.store.on("clear", this.clear, this);
7985 this.el.on("contextmenu", this.onContextMenu, this);
7987 this.mainBody.on('scroll', this.onBodyScroll, this);
7989 this.cm.on("headerchange", this.onHeaderChange, this);
7991 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
7995 onContextMenu : function(e, t)
7997 this.processEvent("contextmenu", e);
8000 processEvent : function(name, e)
8002 if (name != 'touchstart' ) {
8003 this.fireEvent(name, e);
8006 var t = e.getTarget();
8008 var cell = Roo.get(t);
8014 if(cell.findParent('tfoot', false, true)){
8018 if(cell.findParent('thead', false, true)){
8020 if(e.getTarget().nodeName.toLowerCase() != 'th'){
8021 cell = Roo.get(t).findParent('th', false, true);
8023 Roo.log("failed to find th in thead?");
8024 Roo.log(e.getTarget());
8029 var cellIndex = cell.dom.cellIndex;
8031 var ename = name == 'touchstart' ? 'click' : name;
8032 this.fireEvent("header" + ename, this, cellIndex, e);
8037 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8038 cell = Roo.get(t).findParent('td', false, true);
8040 Roo.log("failed to find th in tbody?");
8041 Roo.log(e.getTarget());
8046 var row = cell.findParent('tr', false, true);
8047 var cellIndex = cell.dom.cellIndex;
8048 var rowIndex = row.dom.rowIndex - 1;
8052 this.fireEvent("row" + name, this, rowIndex, e);
8056 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
8062 onMouseover : function(e, el)
8064 var cell = Roo.get(el);
8070 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8071 cell = cell.findParent('td', false, true);
8074 var row = cell.findParent('tr', false, true);
8075 var cellIndex = cell.dom.cellIndex;
8076 var rowIndex = row.dom.rowIndex - 1; // start from 0
8078 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
8082 onMouseout : function(e, el)
8084 var cell = Roo.get(el);
8090 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8091 cell = cell.findParent('td', false, true);
8094 var row = cell.findParent('tr', false, true);
8095 var cellIndex = cell.dom.cellIndex;
8096 var rowIndex = row.dom.rowIndex - 1; // start from 0
8098 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
8102 onClick : function(e, el)
8104 var cell = Roo.get(el);
8106 if(!cell || (!this.cellSelection && !this.rowSelection)){
8110 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8111 cell = cell.findParent('td', false, true);
8114 if(!cell || typeof(cell) == 'undefined'){
8118 var row = cell.findParent('tr', false, true);
8120 if(!row || typeof(row) == 'undefined'){
8124 var cellIndex = cell.dom.cellIndex;
8125 var rowIndex = this.getRowIndex(row);
8127 // why??? - should these not be based on SelectionModel?
8128 if(this.cellSelection){
8129 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
8132 if(this.rowSelection){
8133 this.fireEvent('rowclick', this, row, rowIndex, e);
8139 onDblClick : function(e,el)
8141 var cell = Roo.get(el);
8143 if(!cell || (!this.cellSelection && !this.rowSelection)){
8147 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8148 cell = cell.findParent('td', false, true);
8151 if(!cell || typeof(cell) == 'undefined'){
8155 var row = cell.findParent('tr', false, true);
8157 if(!row || typeof(row) == 'undefined'){
8161 var cellIndex = cell.dom.cellIndex;
8162 var rowIndex = this.getRowIndex(row);
8164 if(this.cellSelection){
8165 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
8168 if(this.rowSelection){
8169 this.fireEvent('rowdblclick', this, row, rowIndex, e);
8173 sort : function(e,el)
8175 var col = Roo.get(el);
8177 if(!col.hasClass('sortable')){
8181 var sort = col.attr('sort');
8184 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
8188 this.store.sortInfo = {field : sort, direction : dir};
8191 Roo.log("calling footer first");
8192 this.footer.onClick('first');
8195 this.store.load({ params : { start : 0 } });
8199 renderHeader : function()
8207 this.totalWidth = 0;
8209 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8211 var config = cm.config[i];
8215 cls : 'x-hcol-' + i,
8217 html: cm.getColumnHeader(i)
8222 if(typeof(config.sortable) != 'undefined' && config.sortable){
8224 c.html = '<i class="glyphicon"></i>' + c.html;
8227 // could use BS4 hidden-..-down
8229 if(typeof(config.lgHeader) != 'undefined'){
8230 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
8233 if(typeof(config.mdHeader) != 'undefined'){
8234 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
8237 if(typeof(config.smHeader) != 'undefined'){
8238 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
8241 if(typeof(config.xsHeader) != 'undefined'){
8242 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
8249 if(typeof(config.tooltip) != 'undefined'){
8250 c.tooltip = config.tooltip;
8253 if(typeof(config.colspan) != 'undefined'){
8254 c.colspan = config.colspan;
8257 if(typeof(config.hidden) != 'undefined' && config.hidden){
8258 c.style += ' display:none;';
8261 if(typeof(config.dataIndex) != 'undefined'){
8262 c.sort = config.dataIndex;
8267 if(typeof(config.align) != 'undefined' && config.align.length){
8268 c.style += ' text-align:' + config.align + ';';
8271 if(typeof(config.width) != 'undefined'){
8272 c.style += ' width:' + config.width + 'px;';
8273 this.totalWidth += config.width;
8275 this.totalWidth += 100; // assume minimum of 100 per column?
8278 if(typeof(config.cls) != 'undefined'){
8279 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
8282 ['xs','sm','md','lg'].map(function(size){
8284 if(typeof(config[size]) == 'undefined'){
8288 if (!config[size]) { // 0 = hidden
8289 // BS 4 '0' is treated as hide that column and below.
8290 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
8294 c.cls += ' col-' + size + '-' + config[size] + (
8295 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8307 renderBody : function()
8317 colspan : this.cm.getColumnCount()
8327 renderFooter : function()
8337 colspan : this.cm.getColumnCount()
8351 // Roo.log('ds onload');
8356 var ds = this.store;
8358 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
8359 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
8360 if (_this.store.sortInfo) {
8362 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
8363 e.select('i', true).addClass(['glyphicon-arrow-up']);
8366 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
8367 e.select('i', true).addClass(['glyphicon-arrow-down']);
8372 var tbody = this.mainBody;
8374 if(ds.getCount() > 0){
8375 ds.data.each(function(d,rowIndex){
8376 var row = this.renderRow(cm, ds, rowIndex);
8378 tbody.createChild(row);
8382 if(row.cellObjects.length){
8383 Roo.each(row.cellObjects, function(r){
8384 _this.renderCellObject(r);
8391 var tfoot = this.el.select('tfoot', true).first();
8393 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
8395 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
8397 var total = this.ds.getTotalCount();
8399 if(this.footer.pageSize < total){
8400 this.mainFoot.show();
8404 Roo.each(this.el.select('tbody td', true).elements, function(e){
8405 e.on('mouseover', _this.onMouseover, _this);
8408 Roo.each(this.el.select('tbody td', true).elements, function(e){
8409 e.on('mouseout', _this.onMouseout, _this);
8411 this.fireEvent('rowsrendered', this);
8417 onUpdate : function(ds,record)
8419 this.refreshRow(record);
8423 onRemove : function(ds, record, index, isUpdate){
8424 if(isUpdate !== true){
8425 this.fireEvent("beforerowremoved", this, index, record);
8427 var bt = this.mainBody.dom;
8429 var rows = this.el.select('tbody > tr', true).elements;
8431 if(typeof(rows[index]) != 'undefined'){
8432 bt.removeChild(rows[index].dom);
8435 // if(bt.rows[index]){
8436 // bt.removeChild(bt.rows[index]);
8439 if(isUpdate !== true){
8440 //this.stripeRows(index);
8441 //this.syncRowHeights(index, index);
8443 this.fireEvent("rowremoved", this, index, record);
8447 onAdd : function(ds, records, rowIndex)
8449 //Roo.log('on Add called');
8450 // - note this does not handle multiple adding very well..
8451 var bt = this.mainBody.dom;
8452 for (var i =0 ; i < records.length;i++) {
8453 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
8454 //Roo.log(records[i]);
8455 //Roo.log(this.store.getAt(rowIndex+i));
8456 this.insertRow(this.store, rowIndex + i, false);
8463 refreshRow : function(record){
8464 var ds = this.store, index;
8465 if(typeof record == 'number'){
8467 record = ds.getAt(index);
8469 index = ds.indexOf(record);
8471 return; // should not happen - but seems to
8474 this.insertRow(ds, index, true);
8476 this.onRemove(ds, record, index+1, true);
8478 //this.syncRowHeights(index, index);
8480 this.fireEvent("rowupdated", this, index, record);
8483 insertRow : function(dm, rowIndex, isUpdate){
8486 this.fireEvent("beforerowsinserted", this, rowIndex);
8488 //var s = this.getScrollState();
8489 var row = this.renderRow(this.cm, this.store, rowIndex);
8490 // insert before rowIndex..
8491 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8495 if(row.cellObjects.length){
8496 Roo.each(row.cellObjects, function(r){
8497 _this.renderCellObject(r);
8502 this.fireEvent("rowsinserted", this, rowIndex);
8503 //this.syncRowHeights(firstRow, lastRow);
8504 //this.stripeRows(firstRow);
8511 getRowDom : function(rowIndex)
8513 var rows = this.el.select('tbody > tr', true).elements;
8515 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8518 // returns the object tree for a tr..
8521 renderRow : function(cm, ds, rowIndex)
8523 var d = ds.getAt(rowIndex);
8527 cls : 'x-row-' + rowIndex,
8531 var cellObjects = [];
8533 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8534 var config = cm.config[i];
8536 var renderer = cm.getRenderer(i);
8540 if(typeof(renderer) !== 'undefined'){
8541 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8543 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8544 // and are rendered into the cells after the row is rendered - using the id for the element.
8546 if(typeof(value) === 'object'){
8556 rowIndex : rowIndex,
8561 this.fireEvent('rowclass', this, rowcfg);
8565 cls : rowcfg.rowClass + ' x-col-' + i,
8567 html: (typeof(value) === 'object') ? '' : value
8574 if(typeof(config.colspan) != 'undefined'){
8575 td.colspan = config.colspan;
8578 if(typeof(config.hidden) != 'undefined' && config.hidden){
8579 td.style += ' display:none;';
8582 if(typeof(config.align) != 'undefined' && config.align.length){
8583 td.style += ' text-align:' + config.align + ';';
8585 if(typeof(config.valign) != 'undefined' && config.valign.length){
8586 td.style += ' vertical-align:' + config.valign + ';';
8589 if(typeof(config.width) != 'undefined'){
8590 td.style += ' width:' + config.width + 'px;';
8593 if(typeof(config.cursor) != 'undefined'){
8594 td.style += ' cursor:' + config.cursor + ';';
8597 if(typeof(config.cls) != 'undefined'){
8598 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8601 ['xs','sm','md','lg'].map(function(size){
8603 if(typeof(config[size]) == 'undefined'){
8609 if (!config[size]) { // 0 = hidden
8610 // BS 4 '0' is treated as hide that column and below.
8611 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8615 td.cls += ' col-' + size + '-' + config[size] + (
8616 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8626 row.cellObjects = cellObjects;
8634 onBeforeLoad : function()
8643 this.el.select('tbody', true).first().dom.innerHTML = '';
8646 * Show or hide a row.
8647 * @param {Number} rowIndex to show or hide
8648 * @param {Boolean} state hide
8650 setRowVisibility : function(rowIndex, state)
8652 var bt = this.mainBody.dom;
8654 var rows = this.el.select('tbody > tr', true).elements;
8656 if(typeof(rows[rowIndex]) == 'undefined'){
8659 rows[rowIndex].dom.style.display = state ? '' : 'none';
8663 getSelectionModel : function(){
8665 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8667 return this.selModel;
8670 * Render the Roo.bootstrap object from renderder
8672 renderCellObject : function(r)
8676 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8678 var t = r.cfg.render(r.container);
8681 Roo.each(r.cfg.cn, function(c){
8683 container: t.getChildContainer(),
8686 _this.renderCellObject(child);
8691 getRowIndex : function(row)
8695 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8706 * Returns the grid's underlying element = used by panel.Grid
8707 * @return {Element} The element
8709 getGridEl : function(){
8713 * Forces a resize - used by panel.Grid
8714 * @return {Element} The element
8716 autoSize : function()
8718 //var ctr = Roo.get(this.container.dom.parentElement);
8719 var ctr = Roo.get(this.el.dom);
8721 var thd = this.getGridEl().select('thead',true).first();
8722 var tbd = this.getGridEl().select('tbody', true).first();
8723 var tfd = this.getGridEl().select('tfoot', true).first();
8725 var cw = ctr.getWidth();
8726 this.getGridEl().select('tfoot tr, tfoot td',true).setWidth(cw);
8730 tbd.setWidth(ctr.getWidth());
8731 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8732 // this needs fixing for various usage - currently only hydra job advers I think..
8734 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8736 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8739 cw = Math.max(cw, this.totalWidth);
8740 this.getGridEl().select('tbody tr',true).setWidth(cw);
8742 // resize 'expandable coloumn?
8744 return; // we doe not have a view in this design..
8747 onBodyScroll: function()
8749 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8751 this.mainHead.setStyle({
8752 'position' : 'relative',
8753 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8759 var scrollHeight = this.mainBody.dom.scrollHeight;
8761 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8763 var height = this.mainBody.getHeight();
8765 if(scrollHeight - height == scrollTop) {
8767 var total = this.ds.getTotalCount();
8769 if(this.footer.cursor + this.footer.pageSize < total){
8771 this.footer.ds.load({
8773 start : this.footer.cursor + this.footer.pageSize,
8774 limit : this.footer.pageSize
8784 onHeaderChange : function()
8786 var header = this.renderHeader();
8787 var table = this.el.select('table', true).first();
8789 this.mainHead.remove();
8790 this.mainHead = table.createChild(header, this.mainBody, false);
8793 onHiddenChange : function(colModel, colIndex, hidden)
8795 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8796 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8798 this.CSS.updateRule(thSelector, "display", "");
8799 this.CSS.updateRule(tdSelector, "display", "");
8802 this.CSS.updateRule(thSelector, "display", "none");
8803 this.CSS.updateRule(tdSelector, "display", "none");
8806 this.onHeaderChange();
8810 setColumnWidth: function(col_index, width)
8812 // width = "md-2 xs-2..."
8813 if(!this.colModel.config[col_index]) {
8817 var w = width.split(" ");
8819 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8821 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8824 for(var j = 0; j < w.length; j++) {
8830 var size_cls = w[j].split("-");
8832 if(!Number.isInteger(size_cls[1] * 1)) {
8836 if(!this.colModel.config[col_index][size_cls[0]]) {
8840 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8844 h_row[0].classList.replace(
8845 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8846 "col-"+size_cls[0]+"-"+size_cls[1]
8849 for(var i = 0; i < rows.length; i++) {
8851 var size_cls = w[j].split("-");
8853 if(!Number.isInteger(size_cls[1] * 1)) {
8857 if(!this.colModel.config[col_index][size_cls[0]]) {
8861 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8865 rows[i].classList.replace(
8866 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8867 "col-"+size_cls[0]+"-"+size_cls[1]
8871 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8886 * @class Roo.bootstrap.TableCell
8887 * @extends Roo.bootstrap.Component
8888 * Bootstrap TableCell class
8889 * @cfg {String} html cell contain text
8890 * @cfg {String} cls cell class
8891 * @cfg {String} tag cell tag (td|th) default td
8892 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8893 * @cfg {String} align Aligns the content in a cell
8894 * @cfg {String} axis Categorizes cells
8895 * @cfg {String} bgcolor Specifies the background color of a cell
8896 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8897 * @cfg {Number} colspan Specifies the number of columns a cell should span
8898 * @cfg {String} headers Specifies one or more header cells a cell is related to
8899 * @cfg {Number} height Sets the height of a cell
8900 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8901 * @cfg {Number} rowspan Sets the number of rows a cell should span
8902 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8903 * @cfg {String} valign Vertical aligns the content in a cell
8904 * @cfg {Number} width Specifies the width of a cell
8907 * Create a new TableCell
8908 * @param {Object} config The config object
8911 Roo.bootstrap.TableCell = function(config){
8912 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8915 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8935 getAutoCreate : function(){
8936 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8956 cfg.align=this.align
8962 cfg.bgcolor=this.bgcolor
8965 cfg.charoff=this.charoff
8968 cfg.colspan=this.colspan
8971 cfg.headers=this.headers
8974 cfg.height=this.height
8977 cfg.nowrap=this.nowrap
8980 cfg.rowspan=this.rowspan
8983 cfg.scope=this.scope
8986 cfg.valign=this.valign
8989 cfg.width=this.width
9008 * @class Roo.bootstrap.TableRow
9009 * @extends Roo.bootstrap.Component
9010 * Bootstrap TableRow class
9011 * @cfg {String} cls row class
9012 * @cfg {String} align Aligns the content in a table row
9013 * @cfg {String} bgcolor Specifies a background color for a table row
9014 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
9015 * @cfg {String} valign Vertical aligns the content in a table row
9018 * Create a new TableRow
9019 * @param {Object} config The config object
9022 Roo.bootstrap.TableRow = function(config){
9023 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
9026 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
9034 getAutoCreate : function(){
9035 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
9045 cfg.align = this.align;
9048 cfg.bgcolor = this.bgcolor;
9051 cfg.charoff = this.charoff;
9054 cfg.valign = this.valign;
9072 * @class Roo.bootstrap.TableBody
9073 * @extends Roo.bootstrap.Component
9074 * Bootstrap TableBody class
9075 * @cfg {String} cls element class
9076 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
9077 * @cfg {String} align Aligns the content inside the element
9078 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
9079 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
9082 * Create a new TableBody
9083 * @param {Object} config The config object
9086 Roo.bootstrap.TableBody = function(config){
9087 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
9090 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
9098 getAutoCreate : function(){
9099 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
9113 cfg.align = this.align;
9116 cfg.charoff = this.charoff;
9119 cfg.valign = this.valign;
9126 // initEvents : function()
9133 // this.store = Roo.factory(this.store, Roo.data);
9134 // this.store.on('load', this.onLoad, this);
9136 // this.store.load();
9140 // onLoad: function ()
9142 // this.fireEvent('load', this);
9152 * Ext JS Library 1.1.1
9153 * Copyright(c) 2006-2007, Ext JS, LLC.
9155 * Originally Released Under LGPL - original licence link has changed is not relivant.
9158 * <script type="text/javascript">
9161 // as we use this in bootstrap.
9162 Roo.namespace('Roo.form');
9164 * @class Roo.form.Action
9165 * Internal Class used to handle form actions
9167 * @param {Roo.form.BasicForm} el The form element or its id
9168 * @param {Object} config Configuration options
9173 // define the action interface
9174 Roo.form.Action = function(form, options){
9176 this.options = options || {};
9179 * Client Validation Failed
9182 Roo.form.Action.CLIENT_INVALID = 'client';
9184 * Server Validation Failed
9187 Roo.form.Action.SERVER_INVALID = 'server';
9189 * Connect to Server Failed
9192 Roo.form.Action.CONNECT_FAILURE = 'connect';
9194 * Reading Data from Server Failed
9197 Roo.form.Action.LOAD_FAILURE = 'load';
9199 Roo.form.Action.prototype = {
9201 failureType : undefined,
9202 response : undefined,
9206 run : function(options){
9211 success : function(response){
9216 handleResponse : function(response){
9220 // default connection failure
9221 failure : function(response){
9223 this.response = response;
9224 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9225 this.form.afterAction(this, false);
9228 processResponse : function(response){
9229 this.response = response;
9230 if(!response.responseText){
9233 this.result = this.handleResponse(response);
9237 // utility functions used internally
9238 getUrl : function(appendParams){
9239 var url = this.options.url || this.form.url || this.form.el.dom.action;
9241 var p = this.getParams();
9243 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
9249 getMethod : function(){
9250 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
9253 getParams : function(){
9254 var bp = this.form.baseParams;
9255 var p = this.options.params;
9257 if(typeof p == "object"){
9258 p = Roo.urlEncode(Roo.applyIf(p, bp));
9259 }else if(typeof p == 'string' && bp){
9260 p += '&' + Roo.urlEncode(bp);
9263 p = Roo.urlEncode(bp);
9268 createCallback : function(){
9270 success: this.success,
9271 failure: this.failure,
9273 timeout: (this.form.timeout*1000),
9274 upload: this.form.fileUpload ? this.success : undefined
9279 Roo.form.Action.Submit = function(form, options){
9280 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
9283 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
9286 haveProgress : false,
9287 uploadComplete : false,
9289 // uploadProgress indicator.
9290 uploadProgress : function()
9292 if (!this.form.progressUrl) {
9296 if (!this.haveProgress) {
9297 Roo.MessageBox.progress("Uploading", "Uploading");
9299 if (this.uploadComplete) {
9300 Roo.MessageBox.hide();
9304 this.haveProgress = true;
9306 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
9308 var c = new Roo.data.Connection();
9310 url : this.form.progressUrl,
9315 success : function(req){
9316 //console.log(data);
9320 rdata = Roo.decode(req.responseText)
9322 Roo.log("Invalid data from server..");
9326 if (!rdata || !rdata.success) {
9328 Roo.MessageBox.alert(Roo.encode(rdata));
9331 var data = rdata.data;
9333 if (this.uploadComplete) {
9334 Roo.MessageBox.hide();
9339 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
9340 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
9343 this.uploadProgress.defer(2000,this);
9346 failure: function(data) {
9347 Roo.log('progress url failed ');
9358 // run get Values on the form, so it syncs any secondary forms.
9359 this.form.getValues();
9361 var o = this.options;
9362 var method = this.getMethod();
9363 var isPost = method == 'POST';
9364 if(o.clientValidation === false || this.form.isValid()){
9366 if (this.form.progressUrl) {
9367 this.form.findField('UPLOAD_IDENTIFIER').setValue(
9368 (new Date() * 1) + '' + Math.random());
9373 Roo.Ajax.request(Roo.apply(this.createCallback(), {
9374 form:this.form.el.dom,
9375 url:this.getUrl(!isPost),
9377 params:isPost ? this.getParams() : null,
9378 isUpload: this.form.fileUpload,
9379 formData : this.form.formData
9382 this.uploadProgress();
9384 }else if (o.clientValidation !== false){ // client validation failed
9385 this.failureType = Roo.form.Action.CLIENT_INVALID;
9386 this.form.afterAction(this, false);
9390 success : function(response)
9392 this.uploadComplete= true;
9393 if (this.haveProgress) {
9394 Roo.MessageBox.hide();
9398 var result = this.processResponse(response);
9399 if(result === true || result.success){
9400 this.form.afterAction(this, true);
9404 this.form.markInvalid(result.errors);
9405 this.failureType = Roo.form.Action.SERVER_INVALID;
9407 this.form.afterAction(this, false);
9409 failure : function(response)
9411 this.uploadComplete= true;
9412 if (this.haveProgress) {
9413 Roo.MessageBox.hide();
9416 this.response = response;
9417 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9418 this.form.afterAction(this, false);
9421 handleResponse : function(response){
9422 if(this.form.errorReader){
9423 var rs = this.form.errorReader.read(response);
9426 for(var i = 0, len = rs.records.length; i < len; i++) {
9427 var r = rs.records[i];
9431 if(errors.length < 1){
9435 success : rs.success,
9441 ret = Roo.decode(response.responseText);
9445 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
9455 Roo.form.Action.Load = function(form, options){
9456 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
9457 this.reader = this.form.reader;
9460 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9465 Roo.Ajax.request(Roo.apply(
9466 this.createCallback(), {
9467 method:this.getMethod(),
9468 url:this.getUrl(false),
9469 params:this.getParams()
9473 success : function(response){
9475 var result = this.processResponse(response);
9476 if(result === true || !result.success || !result.data){
9477 this.failureType = Roo.form.Action.LOAD_FAILURE;
9478 this.form.afterAction(this, false);
9481 this.form.clearInvalid();
9482 this.form.setValues(result.data);
9483 this.form.afterAction(this, true);
9486 handleResponse : function(response){
9487 if(this.form.reader){
9488 var rs = this.form.reader.read(response);
9489 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9491 success : rs.success,
9495 return Roo.decode(response.responseText);
9499 Roo.form.Action.ACTION_TYPES = {
9500 'load' : Roo.form.Action.Load,
9501 'submit' : Roo.form.Action.Submit
9510 * @class Roo.bootstrap.Form
9511 * @extends Roo.bootstrap.Component
9512 * Bootstrap Form class
9513 * @cfg {String} method GET | POST (default POST)
9514 * @cfg {String} labelAlign top | left (default top)
9515 * @cfg {String} align left | right - for navbars
9516 * @cfg {Boolean} loadMask load mask when submit (default true)
9521 * @param {Object} config The config object
9525 Roo.bootstrap.Form = function(config){
9527 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9529 Roo.bootstrap.Form.popover.apply();
9533 * @event clientvalidation
9534 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9535 * @param {Form} this
9536 * @param {Boolean} valid true if the form has passed client-side validation
9538 clientvalidation: true,
9540 * @event beforeaction
9541 * Fires before any action is performed. Return false to cancel the action.
9542 * @param {Form} this
9543 * @param {Action} action The action to be performed
9547 * @event actionfailed
9548 * Fires when an action fails.
9549 * @param {Form} this
9550 * @param {Action} action The action that failed
9552 actionfailed : true,
9554 * @event actioncomplete
9555 * Fires when an action is completed.
9556 * @param {Form} this
9557 * @param {Action} action The action that completed
9559 actioncomplete : true
9563 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9566 * @cfg {String} method
9567 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9572 * The URL to use for form actions if one isn't supplied in the action options.
9575 * @cfg {Boolean} fileUpload
9576 * Set to true if this form is a file upload.
9580 * @cfg {Object} baseParams
9581 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9585 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9589 * @cfg {Sting} align (left|right) for navbar forms
9594 activeAction : null,
9597 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9598 * element by passing it or its id or mask the form itself by passing in true.
9601 waitMsgTarget : false,
9606 * @cfg {Boolean} errorMask (true|false) default false
9611 * @cfg {Number} maskOffset Default 100
9616 * @cfg {Boolean} maskBody
9620 getAutoCreate : function(){
9624 method : this.method || 'POST',
9625 id : this.id || Roo.id(),
9628 if (this.parent().xtype.match(/^Nav/)) {
9629 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9633 if (this.labelAlign == 'left' ) {
9634 cfg.cls += ' form-horizontal';
9640 initEvents : function()
9642 this.el.on('submit', this.onSubmit, this);
9643 // this was added as random key presses on the form where triggering form submit.
9644 this.el.on('keypress', function(e) {
9645 if (e.getCharCode() != 13) {
9648 // we might need to allow it for textareas.. and some other items.
9649 // check e.getTarget().
9651 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9655 Roo.log("keypress blocked");
9663 onSubmit : function(e){
9668 * Returns true if client-side validation on the form is successful.
9671 isValid : function(){
9672 var items = this.getItems();
9676 items.each(function(f){
9682 Roo.log('invalid field: ' + f.name);
9686 if(!target && f.el.isVisible(true)){
9692 if(this.errorMask && !valid){
9693 Roo.bootstrap.Form.popover.mask(this, target);
9700 * Returns true if any fields in this form have changed since their original load.
9703 isDirty : function(){
9705 var items = this.getItems();
9706 items.each(function(f){
9716 * Performs a predefined action (submit or load) or custom actions you define on this form.
9717 * @param {String} actionName The name of the action type
9718 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9719 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9720 * accept other config options):
9722 Property Type Description
9723 ---------------- --------------- ----------------------------------------------------------------------------------
9724 url String The url for the action (defaults to the form's url)
9725 method String The form method to use (defaults to the form's method, or POST if not defined)
9726 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9727 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9728 validate the form on the client (defaults to false)
9730 * @return {BasicForm} this
9732 doAction : function(action, options){
9733 if(typeof action == 'string'){
9734 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9736 if(this.fireEvent('beforeaction', this, action) !== false){
9737 this.beforeAction(action);
9738 action.run.defer(100, action);
9744 beforeAction : function(action){
9745 var o = action.options;
9750 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9752 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9755 // not really supported yet.. ??
9757 //if(this.waitMsgTarget === true){
9758 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9759 //}else if(this.waitMsgTarget){
9760 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9761 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9763 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9769 afterAction : function(action, success){
9770 this.activeAction = null;
9771 var o = action.options;
9776 Roo.get(document.body).unmask();
9782 //if(this.waitMsgTarget === true){
9783 // this.el.unmask();
9784 //}else if(this.waitMsgTarget){
9785 // this.waitMsgTarget.unmask();
9787 // Roo.MessageBox.updateProgress(1);
9788 // Roo.MessageBox.hide();
9795 Roo.callback(o.success, o.scope, [this, action]);
9796 this.fireEvent('actioncomplete', this, action);
9800 // failure condition..
9801 // we have a scenario where updates need confirming.
9802 // eg. if a locking scenario exists..
9803 // we look for { errors : { needs_confirm : true }} in the response.
9805 (typeof(action.result) != 'undefined') &&
9806 (typeof(action.result.errors) != 'undefined') &&
9807 (typeof(action.result.errors.needs_confirm) != 'undefined')
9810 Roo.log("not supported yet");
9813 Roo.MessageBox.confirm(
9814 "Change requires confirmation",
9815 action.result.errorMsg,
9820 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9830 Roo.callback(o.failure, o.scope, [this, action]);
9831 // show an error message if no failed handler is set..
9832 if (!this.hasListener('actionfailed')) {
9833 Roo.log("need to add dialog support");
9835 Roo.MessageBox.alert("Error",
9836 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9837 action.result.errorMsg :
9838 "Saving Failed, please check your entries or try again"
9843 this.fireEvent('actionfailed', this, action);
9848 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9849 * @param {String} id The value to search for
9852 findField : function(id){
9853 var items = this.getItems();
9854 var field = items.get(id);
9856 items.each(function(f){
9857 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9864 return field || null;
9867 * Mark fields in this form invalid in bulk.
9868 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9869 * @return {BasicForm} this
9871 markInvalid : function(errors){
9872 if(errors instanceof Array){
9873 for(var i = 0, len = errors.length; i < len; i++){
9874 var fieldError = errors[i];
9875 var f = this.findField(fieldError.id);
9877 f.markInvalid(fieldError.msg);
9883 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9884 field.markInvalid(errors[id]);
9888 //Roo.each(this.childForms || [], function (f) {
9889 // f.markInvalid(errors);
9896 * Set values for fields in this form in bulk.
9897 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9898 * @return {BasicForm} this
9900 setValues : function(values){
9901 if(values instanceof Array){ // array of objects
9902 for(var i = 0, len = values.length; i < len; i++){
9904 var f = this.findField(v.id);
9906 f.setValue(v.value);
9907 if(this.trackResetOnLoad){
9908 f.originalValue = f.getValue();
9912 }else{ // object hash
9915 if(typeof values[id] != 'function' && (field = this.findField(id))){
9917 if (field.setFromData &&
9919 field.displayField &&
9920 // combos' with local stores can
9921 // be queried via setValue()
9922 // to set their value..
9923 (field.store && !field.store.isLocal)
9927 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9928 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9929 field.setFromData(sd);
9931 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9933 field.setFromData(values);
9936 field.setValue(values[id]);
9940 if(this.trackResetOnLoad){
9941 field.originalValue = field.getValue();
9947 //Roo.each(this.childForms || [], function (f) {
9948 // f.setValues(values);
9955 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9956 * they are returned as an array.
9957 * @param {Boolean} asString
9960 getValues : function(asString){
9961 //if (this.childForms) {
9962 // copy values from the child forms
9963 // Roo.each(this.childForms, function (f) {
9964 // this.setValues(f.getValues());
9970 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9971 if(asString === true){
9974 return Roo.urlDecode(fs);
9978 * Returns the fields in this form as an object with key/value pairs.
9979 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9982 getFieldValues : function(with_hidden)
9984 var items = this.getItems();
9986 items.each(function(f){
9992 var v = f.getValue();
9994 if (f.inputType =='radio') {
9995 if (typeof(ret[f.getName()]) == 'undefined') {
9996 ret[f.getName()] = ''; // empty..
9999 if (!f.el.dom.checked) {
10003 v = f.el.dom.value;
10007 if(f.xtype == 'MoneyField'){
10008 ret[f.currencyName] = f.getCurrency();
10011 // not sure if this supported any more..
10012 if ((typeof(v) == 'object') && f.getRawValue) {
10013 v = f.getRawValue() ; // dates..
10015 // combo boxes where name != hiddenName...
10016 if (f.name !== false && f.name != '' && f.name != f.getName()) {
10017 ret[f.name] = f.getRawValue();
10019 ret[f.getName()] = v;
10026 * Clears all invalid messages in this form.
10027 * @return {BasicForm} this
10029 clearInvalid : function(){
10030 var items = this.getItems();
10032 items.each(function(f){
10040 * Resets this form.
10041 * @return {BasicForm} this
10043 reset : function(){
10044 var items = this.getItems();
10045 items.each(function(f){
10049 Roo.each(this.childForms || [], function (f) {
10057 getItems : function()
10059 var r=new Roo.util.MixedCollection(false, function(o){
10060 return o.id || (o.id = Roo.id());
10062 var iter = function(el) {
10069 Roo.each(el.items,function(e) {
10078 hideFields : function(items)
10080 Roo.each(items, function(i){
10082 var f = this.findField(i);
10093 showFields : function(items)
10095 Roo.each(items, function(i){
10097 var f = this.findField(i);
10110 Roo.apply(Roo.bootstrap.Form, {
10126 intervalID : false,
10132 if(this.isApplied){
10137 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
10138 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
10139 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
10140 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
10143 this.maskEl.top.enableDisplayMode("block");
10144 this.maskEl.left.enableDisplayMode("block");
10145 this.maskEl.bottom.enableDisplayMode("block");
10146 this.maskEl.right.enableDisplayMode("block");
10148 this.toolTip = new Roo.bootstrap.Tooltip({
10149 cls : 'roo-form-error-popover',
10151 'left' : ['r-l', [-2,0], 'right'],
10152 'right' : ['l-r', [2,0], 'left'],
10153 'bottom' : ['tl-bl', [0,2], 'top'],
10154 'top' : [ 'bl-tl', [0,-2], 'bottom']
10158 this.toolTip.render(Roo.get(document.body));
10160 this.toolTip.el.enableDisplayMode("block");
10162 Roo.get(document.body).on('click', function(){
10166 Roo.get(document.body).on('touchstart', function(){
10170 this.isApplied = true
10173 mask : function(form, target)
10177 this.target = target;
10179 if(!this.form.errorMask || !target.el){
10183 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
10185 Roo.log(scrollable);
10187 var ot = this.target.el.calcOffsetsTo(scrollable);
10189 var scrollTo = ot[1] - this.form.maskOffset;
10191 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
10193 scrollable.scrollTo('top', scrollTo);
10195 var box = this.target.el.getBox();
10197 var zIndex = Roo.bootstrap.Modal.zIndex++;
10200 this.maskEl.top.setStyle('position', 'absolute');
10201 this.maskEl.top.setStyle('z-index', zIndex);
10202 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
10203 this.maskEl.top.setLeft(0);
10204 this.maskEl.top.setTop(0);
10205 this.maskEl.top.show();
10207 this.maskEl.left.setStyle('position', 'absolute');
10208 this.maskEl.left.setStyle('z-index', zIndex);
10209 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
10210 this.maskEl.left.setLeft(0);
10211 this.maskEl.left.setTop(box.y - this.padding);
10212 this.maskEl.left.show();
10214 this.maskEl.bottom.setStyle('position', 'absolute');
10215 this.maskEl.bottom.setStyle('z-index', zIndex);
10216 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
10217 this.maskEl.bottom.setLeft(0);
10218 this.maskEl.bottom.setTop(box.bottom + this.padding);
10219 this.maskEl.bottom.show();
10221 this.maskEl.right.setStyle('position', 'absolute');
10222 this.maskEl.right.setStyle('z-index', zIndex);
10223 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
10224 this.maskEl.right.setLeft(box.right + this.padding);
10225 this.maskEl.right.setTop(box.y - this.padding);
10226 this.maskEl.right.show();
10228 this.toolTip.bindEl = this.target.el;
10230 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
10232 var tip = this.target.blankText;
10234 if(this.target.getValue() !== '' ) {
10236 if (this.target.invalidText.length) {
10237 tip = this.target.invalidText;
10238 } else if (this.target.regexText.length){
10239 tip = this.target.regexText;
10243 this.toolTip.show(tip);
10245 this.intervalID = window.setInterval(function() {
10246 Roo.bootstrap.Form.popover.unmask();
10249 window.onwheel = function(){ return false;};
10251 (function(){ this.isMasked = true; }).defer(500, this);
10255 unmask : function()
10257 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
10261 this.maskEl.top.setStyle('position', 'absolute');
10262 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
10263 this.maskEl.top.hide();
10265 this.maskEl.left.setStyle('position', 'absolute');
10266 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
10267 this.maskEl.left.hide();
10269 this.maskEl.bottom.setStyle('position', 'absolute');
10270 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
10271 this.maskEl.bottom.hide();
10273 this.maskEl.right.setStyle('position', 'absolute');
10274 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
10275 this.maskEl.right.hide();
10277 this.toolTip.hide();
10279 this.toolTip.el.hide();
10281 window.onwheel = function(){ return true;};
10283 if(this.intervalID){
10284 window.clearInterval(this.intervalID);
10285 this.intervalID = false;
10288 this.isMasked = false;
10298 * Ext JS Library 1.1.1
10299 * Copyright(c) 2006-2007, Ext JS, LLC.
10301 * Originally Released Under LGPL - original licence link has changed is not relivant.
10304 * <script type="text/javascript">
10307 * @class Roo.form.VTypes
10308 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
10311 Roo.form.VTypes = function(){
10312 // closure these in so they are only created once.
10313 var alpha = /^[a-zA-Z_]+$/;
10314 var alphanum = /^[a-zA-Z0-9_]+$/;
10315 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
10316 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
10318 // All these messages and functions are configurable
10321 * The function used to validate email addresses
10322 * @param {String} value The email address
10324 'email' : function(v){
10325 return email.test(v);
10328 * The error text to display when the email validation function returns false
10331 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
10333 * The keystroke filter mask to be applied on email input
10336 'emailMask' : /[a-z0-9_\.\-@]/i,
10339 * The function used to validate URLs
10340 * @param {String} value The URL
10342 'url' : function(v){
10343 return url.test(v);
10346 * The error text to display when the url validation function returns false
10349 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
10352 * The function used to validate alpha values
10353 * @param {String} value The value
10355 'alpha' : function(v){
10356 return alpha.test(v);
10359 * The error text to display when the alpha validation function returns false
10362 'alphaText' : 'This field should only contain letters and _',
10364 * The keystroke filter mask to be applied on alpha input
10367 'alphaMask' : /[a-z_]/i,
10370 * The function used to validate alphanumeric values
10371 * @param {String} value The value
10373 'alphanum' : function(v){
10374 return alphanum.test(v);
10377 * The error text to display when the alphanumeric validation function returns false
10380 'alphanumText' : 'This field should only contain letters, numbers and _',
10382 * The keystroke filter mask to be applied on alphanumeric input
10385 'alphanumMask' : /[a-z0-9_]/i
10395 * @class Roo.bootstrap.Input
10396 * @extends Roo.bootstrap.Component
10397 * Bootstrap Input class
10398 * @cfg {Boolean} disabled is it disabled
10399 * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType
10400 * @cfg {String} name name of the input
10401 * @cfg {string} fieldLabel - the label associated
10402 * @cfg {string} placeholder - placeholder to put in text.
10403 * @cfg {string} before - input group add on before
10404 * @cfg {string} after - input group add on after
10405 * @cfg {string} size - (lg|sm) or leave empty..
10406 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
10407 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
10408 * @cfg {Number} md colspan out of 12 for computer-sized screens
10409 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
10410 * @cfg {string} value default value of the input
10411 * @cfg {Number} labelWidth set the width of label
10412 * @cfg {Number} labellg set the width of label (1-12)
10413 * @cfg {Number} labelmd set the width of label (1-12)
10414 * @cfg {Number} labelsm set the width of label (1-12)
10415 * @cfg {Number} labelxs set the width of label (1-12)
10416 * @cfg {String} labelAlign (top|left)
10417 * @cfg {Boolean} readOnly Specifies that the field should be read-only
10418 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
10419 * @cfg {String} indicatorpos (left|right) default left
10420 * @cfg {String} capture (user|camera) use for file input only. (default empty)
10421 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
10422 * @cfg {Boolean} preventMark Do not show tick or cross if error/success
10424 * @cfg {String} align (left|center|right) Default left
10425 * @cfg {Boolean} forceFeedback (true|false) Default false
10428 * Create a new Input
10429 * @param {Object} config The config object
10432 Roo.bootstrap.Input = function(config){
10434 Roo.bootstrap.Input.superclass.constructor.call(this, config);
10439 * Fires when this field receives input focus.
10440 * @param {Roo.form.Field} this
10445 * Fires when this field loses input focus.
10446 * @param {Roo.form.Field} this
10450 * @event specialkey
10451 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
10452 * {@link Roo.EventObject#getKey} to determine which key was pressed.
10453 * @param {Roo.form.Field} this
10454 * @param {Roo.EventObject} e The event object
10459 * Fires just before the field blurs if the field value has changed.
10460 * @param {Roo.form.Field} this
10461 * @param {Mixed} newValue The new value
10462 * @param {Mixed} oldValue The original value
10467 * Fires after the field has been marked as invalid.
10468 * @param {Roo.form.Field} this
10469 * @param {String} msg The validation message
10474 * Fires after the field has been validated with no errors.
10475 * @param {Roo.form.Field} this
10480 * Fires after the key up
10481 * @param {Roo.form.Field} this
10482 * @param {Roo.EventObject} e The event Object
10488 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10490 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10491 automatic validation (defaults to "keyup").
10493 validationEvent : "keyup",
10495 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10497 validateOnBlur : true,
10499 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10501 validationDelay : 250,
10503 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10505 focusClass : "x-form-focus", // not needed???
10509 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10511 invalidClass : "has-warning",
10514 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10516 validClass : "has-success",
10519 * @cfg {Boolean} hasFeedback (true|false) default true
10521 hasFeedback : true,
10524 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10526 invalidFeedbackClass : "glyphicon-warning-sign",
10529 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10531 validFeedbackClass : "glyphicon-ok",
10534 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10536 selectOnFocus : false,
10539 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10543 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10548 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10550 disableKeyFilter : false,
10553 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10557 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10561 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10563 blankText : "Please complete this mandatory field",
10566 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10570 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10572 maxLength : Number.MAX_VALUE,
10574 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10576 minLengthText : "The minimum length for this field is {0}",
10578 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10580 maxLengthText : "The maximum length for this field is {0}",
10584 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10585 * If available, this function will be called only after the basic validators all return true, and will be passed the
10586 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10590 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10591 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10592 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10596 * @cfg {String} regexText -- Depricated - use Invalid Text
10601 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10607 autocomplete: false,
10611 inputType : 'text',
10614 placeholder: false,
10619 preventMark: false,
10620 isFormField : true,
10623 labelAlign : false,
10626 formatedValue : false,
10627 forceFeedback : false,
10629 indicatorpos : 'left',
10639 parentLabelAlign : function()
10642 while (parent.parent()) {
10643 parent = parent.parent();
10644 if (typeof(parent.labelAlign) !='undefined') {
10645 return parent.labelAlign;
10652 getAutoCreate : function()
10654 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10660 if(this.inputType != 'hidden'){
10661 cfg.cls = 'form-group' //input-group
10667 type : this.inputType,
10668 value : this.value,
10669 cls : 'form-control',
10670 placeholder : this.placeholder || '',
10671 autocomplete : this.autocomplete || 'new-password'
10673 if (this.inputType == 'file') {
10674 input.style = 'overflow:hidden'; // why not in CSS?
10677 if(this.capture.length){
10678 input.capture = this.capture;
10681 if(this.accept.length){
10682 input.accept = this.accept + "/*";
10686 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10689 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10690 input.maxLength = this.maxLength;
10693 if (this.disabled) {
10694 input.disabled=true;
10697 if (this.readOnly) {
10698 input.readonly=true;
10702 input.name = this.name;
10706 input.cls += ' input-' + this.size;
10710 ['xs','sm','md','lg'].map(function(size){
10711 if (settings[size]) {
10712 cfg.cls += ' col-' + size + '-' + settings[size];
10716 var inputblock = input;
10720 cls: 'glyphicon form-control-feedback'
10723 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10726 cls : 'has-feedback',
10734 if (this.before || this.after) {
10737 cls : 'input-group',
10741 if (this.before && typeof(this.before) == 'string') {
10743 inputblock.cn.push({
10745 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10749 if (this.before && typeof(this.before) == 'object') {
10750 this.before = Roo.factory(this.before);
10752 inputblock.cn.push({
10754 cls : 'roo-input-before input-group-prepend input-group-' +
10755 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10759 inputblock.cn.push(input);
10761 if (this.after && typeof(this.after) == 'string') {
10762 inputblock.cn.push({
10764 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10768 if (this.after && typeof(this.after) == 'object') {
10769 this.after = Roo.factory(this.after);
10771 inputblock.cn.push({
10773 cls : 'roo-input-after input-group-append input-group-' +
10774 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10778 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10779 inputblock.cls += ' has-feedback';
10780 inputblock.cn.push(feedback);
10785 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10786 tooltip : 'This field is required'
10788 if (this.allowBlank ) {
10789 indicator.style = this.allowBlank ? ' display:none' : '';
10791 if (align ==='left' && this.fieldLabel.length) {
10793 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10800 cls : 'control-label col-form-label',
10801 html : this.fieldLabel
10812 var labelCfg = cfg.cn[1];
10813 var contentCfg = cfg.cn[2];
10815 if(this.indicatorpos == 'right'){
10820 cls : 'control-label col-form-label',
10824 html : this.fieldLabel
10838 labelCfg = cfg.cn[0];
10839 contentCfg = cfg.cn[1];
10843 if(this.labelWidth > 12){
10844 labelCfg.style = "width: " + this.labelWidth + 'px';
10847 if(this.labelWidth < 13 && this.labelmd == 0){
10848 this.labelmd = this.labelWidth;
10851 if(this.labellg > 0){
10852 labelCfg.cls += ' col-lg-' + this.labellg;
10853 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10856 if(this.labelmd > 0){
10857 labelCfg.cls += ' col-md-' + this.labelmd;
10858 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10861 if(this.labelsm > 0){
10862 labelCfg.cls += ' col-sm-' + this.labelsm;
10863 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10866 if(this.labelxs > 0){
10867 labelCfg.cls += ' col-xs-' + this.labelxs;
10868 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10872 } else if ( this.fieldLabel.length) {
10879 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10880 tooltip : 'This field is required',
10881 style : this.allowBlank ? ' display:none' : ''
10885 //cls : 'input-group-addon',
10886 html : this.fieldLabel
10894 if(this.indicatorpos == 'right'){
10899 //cls : 'input-group-addon',
10900 html : this.fieldLabel
10905 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10906 tooltip : 'This field is required',
10907 style : this.allowBlank ? ' display:none' : ''
10927 if (this.parentType === 'Navbar' && this.parent().bar) {
10928 cfg.cls += ' navbar-form';
10931 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10932 // on BS4 we do this only if not form
10933 cfg.cls += ' navbar-form';
10941 * return the real input element.
10943 inputEl: function ()
10945 return this.el.select('input.form-control',true).first();
10948 tooltipEl : function()
10950 return this.inputEl();
10953 indicatorEl : function()
10955 if (Roo.bootstrap.version == 4) {
10956 return false; // not enabled in v4 yet.
10959 var indicator = this.el.select('i.roo-required-indicator',true).first();
10969 setDisabled : function(v)
10971 var i = this.inputEl().dom;
10973 i.removeAttribute('disabled');
10977 i.setAttribute('disabled','true');
10979 initEvents : function()
10982 this.inputEl().on("keydown" , this.fireKey, this);
10983 this.inputEl().on("focus", this.onFocus, this);
10984 this.inputEl().on("blur", this.onBlur, this);
10986 this.inputEl().relayEvent('keyup', this);
10988 this.indicator = this.indicatorEl();
10990 if(this.indicator){
10991 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10994 // reference to original value for reset
10995 this.originalValue = this.getValue();
10996 //Roo.form.TextField.superclass.initEvents.call(this);
10997 if(this.validationEvent == 'keyup'){
10998 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
10999 this.inputEl().on('keyup', this.filterValidation, this);
11001 else if(this.validationEvent !== false){
11002 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
11005 if(this.selectOnFocus){
11006 this.on("focus", this.preFocus, this);
11009 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
11010 this.inputEl().on("keypress", this.filterKeys, this);
11012 this.inputEl().relayEvent('keypress', this);
11015 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
11016 this.el.on("click", this.autoSize, this);
11019 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
11020 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
11023 if (typeof(this.before) == 'object') {
11024 this.before.render(this.el.select('.roo-input-before',true).first());
11026 if (typeof(this.after) == 'object') {
11027 this.after.render(this.el.select('.roo-input-after',true).first());
11030 this.inputEl().on('change', this.onChange, this);
11033 filterValidation : function(e){
11034 if(!e.isNavKeyPress()){
11035 this.validationTask.delay(this.validationDelay);
11039 * Validates the field value
11040 * @return {Boolean} True if the value is valid, else false
11042 validate : function(){
11043 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
11044 if(this.disabled || this.validateValue(this.getRawValue())){
11049 this.markInvalid();
11055 * Validates a value according to the field's validation rules and marks the field as invalid
11056 * if the validation fails
11057 * @param {Mixed} value The value to validate
11058 * @return {Boolean} True if the value is valid, else false
11060 validateValue : function(value)
11062 if(this.getVisibilityEl().hasClass('hidden')){
11066 if(value.length < 1) { // if it's blank
11067 if(this.allowBlank){
11073 if(value.length < this.minLength){
11076 if(value.length > this.maxLength){
11080 var vt = Roo.form.VTypes;
11081 if(!vt[this.vtype](value, this)){
11085 if(typeof this.validator == "function"){
11086 var msg = this.validator(value);
11090 if (typeof(msg) == 'string') {
11091 this.invalidText = msg;
11095 if(this.regex && !this.regex.test(value)){
11103 fireKey : function(e){
11104 //Roo.log('field ' + e.getKey());
11105 if(e.isNavKeyPress()){
11106 this.fireEvent("specialkey", this, e);
11109 focus : function (selectText){
11111 this.inputEl().focus();
11112 if(selectText === true){
11113 this.inputEl().dom.select();
11119 onFocus : function(){
11120 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11121 // this.el.addClass(this.focusClass);
11123 if(!this.hasFocus){
11124 this.hasFocus = true;
11125 this.startValue = this.getValue();
11126 this.fireEvent("focus", this);
11130 beforeBlur : Roo.emptyFn,
11134 onBlur : function(){
11136 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11137 //this.el.removeClass(this.focusClass);
11139 this.hasFocus = false;
11140 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
11143 var v = this.getValue();
11144 if(String(v) !== String(this.startValue)){
11145 this.fireEvent('change', this, v, this.startValue);
11147 this.fireEvent("blur", this);
11150 onChange : function(e)
11152 var v = this.getValue();
11153 if(String(v) !== String(this.startValue)){
11154 this.fireEvent('change', this, v, this.startValue);
11160 * Resets the current field value to the originally loaded value and clears any validation messages
11162 reset : function(){
11163 this.setValue(this.originalValue);
11167 * Returns the name of the field
11168 * @return {Mixed} name The name field
11170 getName: function(){
11174 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11175 * @return {Mixed} value The field value
11177 getValue : function(){
11179 var v = this.inputEl().getValue();
11184 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
11185 * @return {Mixed} value The field value
11187 getRawValue : function(){
11188 var v = this.inputEl().getValue();
11194 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
11195 * @param {Mixed} value The value to set
11197 setRawValue : function(v){
11198 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11201 selectText : function(start, end){
11202 var v = this.getRawValue();
11204 start = start === undefined ? 0 : start;
11205 end = end === undefined ? v.length : end;
11206 var d = this.inputEl().dom;
11207 if(d.setSelectionRange){
11208 d.setSelectionRange(start, end);
11209 }else if(d.createTextRange){
11210 var range = d.createTextRange();
11211 range.moveStart("character", start);
11212 range.moveEnd("character", v.length-end);
11219 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
11220 * @param {Mixed} value The value to set
11222 setValue : function(v){
11225 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11231 processValue : function(value){
11232 if(this.stripCharsRe){
11233 var newValue = value.replace(this.stripCharsRe, '');
11234 if(newValue !== value){
11235 this.setRawValue(newValue);
11242 preFocus : function(){
11244 if(this.selectOnFocus){
11245 this.inputEl().dom.select();
11248 filterKeys : function(e){
11249 var k = e.getKey();
11250 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
11253 var c = e.getCharCode(), cc = String.fromCharCode(c);
11254 if(Roo.isIE && (e.isSpecialKey() || !cc)){
11257 if(!this.maskRe.test(cc)){
11262 * Clear any invalid styles/messages for this field
11264 clearInvalid : function(){
11266 if(!this.el || this.preventMark){ // not rendered
11271 this.el.removeClass([this.invalidClass, 'is-invalid']);
11273 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11275 var feedback = this.el.select('.form-control-feedback', true).first();
11278 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11283 if(this.indicator){
11284 this.indicator.removeClass('visible');
11285 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11288 this.fireEvent('valid', this);
11292 * Mark this field as valid
11294 markValid : function()
11296 if(!this.el || this.preventMark){ // not rendered...
11300 this.el.removeClass([this.invalidClass, this.validClass]);
11301 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11303 var feedback = this.el.select('.form-control-feedback', true).first();
11306 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11309 if(this.indicator){
11310 this.indicator.removeClass('visible');
11311 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11319 if(this.allowBlank && !this.getRawValue().length){
11322 if (Roo.bootstrap.version == 3) {
11323 this.el.addClass(this.validClass);
11325 this.inputEl().addClass('is-valid');
11328 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11330 var feedback = this.el.select('.form-control-feedback', true).first();
11333 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11334 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11339 this.fireEvent('valid', this);
11343 * Mark this field as invalid
11344 * @param {String} msg The validation message
11346 markInvalid : function(msg)
11348 if(!this.el || this.preventMark){ // not rendered
11352 this.el.removeClass([this.invalidClass, this.validClass]);
11353 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11355 var feedback = this.el.select('.form-control-feedback', true).first();
11358 this.el.select('.form-control-feedback', true).first().removeClass(
11359 [this.invalidFeedbackClass, this.validFeedbackClass]);
11366 if(this.allowBlank && !this.getRawValue().length){
11370 if(this.indicator){
11371 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11372 this.indicator.addClass('visible');
11374 if (Roo.bootstrap.version == 3) {
11375 this.el.addClass(this.invalidClass);
11377 this.inputEl().addClass('is-invalid');
11382 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11384 var feedback = this.el.select('.form-control-feedback', true).first();
11387 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11389 if(this.getValue().length || this.forceFeedback){
11390 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11397 this.fireEvent('invalid', this, msg);
11400 SafariOnKeyDown : function(event)
11402 // this is a workaround for a password hang bug on chrome/ webkit.
11403 if (this.inputEl().dom.type != 'password') {
11407 var isSelectAll = false;
11409 if(this.inputEl().dom.selectionEnd > 0){
11410 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
11412 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
11413 event.preventDefault();
11418 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
11420 event.preventDefault();
11421 // this is very hacky as keydown always get's upper case.
11423 var cc = String.fromCharCode(event.getCharCode());
11424 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
11428 adjustWidth : function(tag, w){
11429 tag = tag.toLowerCase();
11430 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
11431 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
11432 if(tag == 'input'){
11435 if(tag == 'textarea'){
11438 }else if(Roo.isOpera){
11439 if(tag == 'input'){
11442 if(tag == 'textarea'){
11450 setFieldLabel : function(v)
11452 if(!this.rendered){
11456 if(this.indicatorEl()){
11457 var ar = this.el.select('label > span',true);
11459 if (ar.elements.length) {
11460 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11461 this.fieldLabel = v;
11465 var br = this.el.select('label',true);
11467 if(br.elements.length) {
11468 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11469 this.fieldLabel = v;
11473 Roo.log('Cannot Found any of label > span || label in input');
11477 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11478 this.fieldLabel = v;
11493 * @class Roo.bootstrap.TextArea
11494 * @extends Roo.bootstrap.Input
11495 * Bootstrap TextArea class
11496 * @cfg {Number} cols Specifies the visible width of a text area
11497 * @cfg {Number} rows Specifies the visible number of lines in a text area
11498 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11499 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11500 * @cfg {string} html text
11503 * Create a new TextArea
11504 * @param {Object} config The config object
11507 Roo.bootstrap.TextArea = function(config){
11508 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11512 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11522 getAutoCreate : function(){
11524 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11530 if(this.inputType != 'hidden'){
11531 cfg.cls = 'form-group' //input-group
11539 value : this.value || '',
11540 html: this.html || '',
11541 cls : 'form-control',
11542 placeholder : this.placeholder || ''
11546 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11547 input.maxLength = this.maxLength;
11551 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11555 input.cols = this.cols;
11558 if (this.readOnly) {
11559 input.readonly = true;
11563 input.name = this.name;
11567 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11571 ['xs','sm','md','lg'].map(function(size){
11572 if (settings[size]) {
11573 cfg.cls += ' col-' + size + '-' + settings[size];
11577 var inputblock = input;
11579 if(this.hasFeedback && !this.allowBlank){
11583 cls: 'glyphicon form-control-feedback'
11587 cls : 'has-feedback',
11596 if (this.before || this.after) {
11599 cls : 'input-group',
11603 inputblock.cn.push({
11605 cls : 'input-group-addon',
11610 inputblock.cn.push(input);
11612 if(this.hasFeedback && !this.allowBlank){
11613 inputblock.cls += ' has-feedback';
11614 inputblock.cn.push(feedback);
11618 inputblock.cn.push({
11620 cls : 'input-group-addon',
11627 if (align ==='left' && this.fieldLabel.length) {
11632 cls : 'control-label',
11633 html : this.fieldLabel
11644 if(this.labelWidth > 12){
11645 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11648 if(this.labelWidth < 13 && this.labelmd == 0){
11649 this.labelmd = this.labelWidth;
11652 if(this.labellg > 0){
11653 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11654 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11657 if(this.labelmd > 0){
11658 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11659 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11662 if(this.labelsm > 0){
11663 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11664 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11667 if(this.labelxs > 0){
11668 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11669 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11672 } else if ( this.fieldLabel.length) {
11677 //cls : 'input-group-addon',
11678 html : this.fieldLabel
11696 if (this.disabled) {
11697 input.disabled=true;
11704 * return the real textarea element.
11706 inputEl: function ()
11708 return this.el.select('textarea.form-control',true).first();
11712 * Clear any invalid styles/messages for this field
11714 clearInvalid : function()
11717 if(!this.el || this.preventMark){ // not rendered
11721 var label = this.el.select('label', true).first();
11722 var icon = this.el.select('i.fa-star', true).first();
11727 this.el.removeClass( this.validClass);
11728 this.inputEl().removeClass('is-invalid');
11730 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11732 var feedback = this.el.select('.form-control-feedback', true).first();
11735 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11740 this.fireEvent('valid', this);
11744 * Mark this field as valid
11746 markValid : function()
11748 if(!this.el || this.preventMark){ // not rendered
11752 this.el.removeClass([this.invalidClass, this.validClass]);
11753 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11755 var feedback = this.el.select('.form-control-feedback', true).first();
11758 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11761 if(this.disabled || this.allowBlank){
11765 var label = this.el.select('label', true).first();
11766 var icon = this.el.select('i.fa-star', true).first();
11771 if (Roo.bootstrap.version == 3) {
11772 this.el.addClass(this.validClass);
11774 this.inputEl().addClass('is-valid');
11778 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11780 var feedback = this.el.select('.form-control-feedback', true).first();
11783 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11784 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11789 this.fireEvent('valid', this);
11793 * Mark this field as invalid
11794 * @param {String} msg The validation message
11796 markInvalid : function(msg)
11798 if(!this.el || this.preventMark){ // not rendered
11802 this.el.removeClass([this.invalidClass, this.validClass]);
11803 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11805 var feedback = this.el.select('.form-control-feedback', true).first();
11808 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11811 if(this.disabled || this.allowBlank){
11815 var label = this.el.select('label', true).first();
11816 var icon = this.el.select('i.fa-star', true).first();
11818 if(!this.getValue().length && label && !icon){
11819 this.el.createChild({
11821 cls : 'text-danger fa fa-lg fa-star',
11822 tooltip : 'This field is required',
11823 style : 'margin-right:5px;'
11827 if (Roo.bootstrap.version == 3) {
11828 this.el.addClass(this.invalidClass);
11830 this.inputEl().addClass('is-invalid');
11833 // fixme ... this may be depricated need to test..
11834 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11836 var feedback = this.el.select('.form-control-feedback', true).first();
11839 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11841 if(this.getValue().length || this.forceFeedback){
11842 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11849 this.fireEvent('invalid', this, msg);
11857 * trigger field - base class for combo..
11862 * @class Roo.bootstrap.TriggerField
11863 * @extends Roo.bootstrap.Input
11864 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11865 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11866 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11867 * for which you can provide a custom implementation. For example:
11869 var trigger = new Roo.bootstrap.TriggerField();
11870 trigger.onTriggerClick = myTriggerFn;
11871 trigger.applyTo('my-field');
11874 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11875 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11876 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11877 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11878 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11881 * Create a new TriggerField.
11882 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11883 * to the base TextField)
11885 Roo.bootstrap.TriggerField = function(config){
11886 this.mimicing = false;
11887 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11890 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11892 * @cfg {String} triggerClass A CSS class to apply to the trigger
11895 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11900 * @cfg {Boolean} removable (true|false) special filter default false
11904 /** @cfg {Boolean} grow @hide */
11905 /** @cfg {Number} growMin @hide */
11906 /** @cfg {Number} growMax @hide */
11912 autoSize: Roo.emptyFn,
11916 deferHeight : true,
11919 actionMode : 'wrap',
11924 getAutoCreate : function(){
11926 var align = this.labelAlign || this.parentLabelAlign();
11931 cls: 'form-group' //input-group
11938 type : this.inputType,
11939 cls : 'form-control',
11940 autocomplete: 'new-password',
11941 placeholder : this.placeholder || ''
11945 input.name = this.name;
11948 input.cls += ' input-' + this.size;
11951 if (this.disabled) {
11952 input.disabled=true;
11955 var inputblock = input;
11957 if(this.hasFeedback && !this.allowBlank){
11961 cls: 'glyphicon form-control-feedback'
11964 if(this.removable && !this.editable ){
11966 cls : 'has-feedback',
11972 cls : 'roo-combo-removable-btn close'
11979 cls : 'has-feedback',
11988 if(this.removable && !this.editable ){
11990 cls : 'roo-removable',
11996 cls : 'roo-combo-removable-btn close'
12003 if (this.before || this.after) {
12006 cls : 'input-group',
12010 inputblock.cn.push({
12012 cls : 'input-group-addon input-group-prepend input-group-text',
12017 inputblock.cn.push(input);
12019 if(this.hasFeedback && !this.allowBlank){
12020 inputblock.cls += ' has-feedback';
12021 inputblock.cn.push(feedback);
12025 inputblock.cn.push({
12027 cls : 'input-group-addon input-group-append input-group-text',
12036 var ibwrap = inputblock;
12041 cls: 'roo-select2-choices',
12045 cls: 'roo-select2-search-field',
12057 cls: 'roo-select2-container input-group',
12062 cls: 'form-hidden-field'
12068 if(!this.multiple && this.showToggleBtn){
12074 if (this.caret != false) {
12077 cls: 'fa fa-' + this.caret
12084 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
12086 Roo.bootstrap.version == 3 ? caret : '',
12089 cls: 'combobox-clear',
12103 combobox.cls += ' roo-select2-container-multi';
12107 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
12108 tooltip : 'This field is required'
12110 if (Roo.bootstrap.version == 4) {
12113 style : 'display:none'
12118 if (align ==='left' && this.fieldLabel.length) {
12120 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
12127 cls : 'control-label',
12128 html : this.fieldLabel
12140 var labelCfg = cfg.cn[1];
12141 var contentCfg = cfg.cn[2];
12143 if(this.indicatorpos == 'right'){
12148 cls : 'control-label',
12152 html : this.fieldLabel
12166 labelCfg = cfg.cn[0];
12167 contentCfg = cfg.cn[1];
12170 if(this.labelWidth > 12){
12171 labelCfg.style = "width: " + this.labelWidth + 'px';
12174 if(this.labelWidth < 13 && this.labelmd == 0){
12175 this.labelmd = this.labelWidth;
12178 if(this.labellg > 0){
12179 labelCfg.cls += ' col-lg-' + this.labellg;
12180 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12183 if(this.labelmd > 0){
12184 labelCfg.cls += ' col-md-' + this.labelmd;
12185 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12188 if(this.labelsm > 0){
12189 labelCfg.cls += ' col-sm-' + this.labelsm;
12190 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12193 if(this.labelxs > 0){
12194 labelCfg.cls += ' col-xs-' + this.labelxs;
12195 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12198 } else if ( this.fieldLabel.length) {
12199 // Roo.log(" label");
12204 //cls : 'input-group-addon',
12205 html : this.fieldLabel
12213 if(this.indicatorpos == 'right'){
12221 html : this.fieldLabel
12235 // Roo.log(" no label && no align");
12242 ['xs','sm','md','lg'].map(function(size){
12243 if (settings[size]) {
12244 cfg.cls += ' col-' + size + '-' + settings[size];
12255 onResize : function(w, h){
12256 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
12257 // if(typeof w == 'number'){
12258 // var x = w - this.trigger.getWidth();
12259 // this.inputEl().setWidth(this.adjustWidth('input', x));
12260 // this.trigger.setStyle('left', x+'px');
12265 adjustSize : Roo.BoxComponent.prototype.adjustSize,
12268 getResizeEl : function(){
12269 return this.inputEl();
12273 getPositionEl : function(){
12274 return this.inputEl();
12278 alignErrorIcon : function(){
12279 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
12283 initEvents : function(){
12287 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
12288 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
12289 if(!this.multiple && this.showToggleBtn){
12290 this.trigger = this.el.select('span.dropdown-toggle',true).first();
12291 if(this.hideTrigger){
12292 this.trigger.setDisplayed(false);
12294 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
12298 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
12301 if(this.removable && !this.editable && !this.tickable){
12302 var close = this.closeTriggerEl();
12305 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
12306 close.on('click', this.removeBtnClick, this, close);
12310 //this.trigger.addClassOnOver('x-form-trigger-over');
12311 //this.trigger.addClassOnClick('x-form-trigger-click');
12314 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
12318 closeTriggerEl : function()
12320 var close = this.el.select('.roo-combo-removable-btn', true).first();
12321 return close ? close : false;
12324 removeBtnClick : function(e, h, el)
12326 e.preventDefault();
12328 if(this.fireEvent("remove", this) !== false){
12330 this.fireEvent("afterremove", this)
12334 createList : function()
12336 this.list = Roo.get(document.body).createChild({
12337 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
12338 cls: 'typeahead typeahead-long dropdown-menu',
12339 style: 'display:none'
12342 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
12347 initTrigger : function(){
12352 onDestroy : function(){
12354 this.trigger.removeAllListeners();
12355 // this.trigger.remove();
12358 // this.wrap.remove();
12360 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
12364 onFocus : function(){
12365 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
12367 if(!this.mimicing){
12368 this.wrap.addClass('x-trigger-wrap-focus');
12369 this.mimicing = true;
12370 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
12371 if(this.monitorTab){
12372 this.el.on("keydown", this.checkTab, this);
12379 checkTab : function(e){
12380 if(e.getKey() == e.TAB){
12381 this.triggerBlur();
12386 onBlur : function(){
12391 mimicBlur : function(e, t){
12393 if(!this.wrap.contains(t) && this.validateBlur()){
12394 this.triggerBlur();
12400 triggerBlur : function(){
12401 this.mimicing = false;
12402 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
12403 if(this.monitorTab){
12404 this.el.un("keydown", this.checkTab, this);
12406 //this.wrap.removeClass('x-trigger-wrap-focus');
12407 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
12411 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
12412 validateBlur : function(e, t){
12417 onDisable : function(){
12418 this.inputEl().dom.disabled = true;
12419 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
12421 // this.wrap.addClass('x-item-disabled');
12426 onEnable : function(){
12427 this.inputEl().dom.disabled = false;
12428 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
12430 // this.el.removeClass('x-item-disabled');
12435 onShow : function(){
12436 var ae = this.getActionEl();
12439 ae.dom.style.display = '';
12440 ae.dom.style.visibility = 'visible';
12446 onHide : function(){
12447 var ae = this.getActionEl();
12448 ae.dom.style.display = 'none';
12452 * The function that should handle the trigger's click event. This method does nothing by default until overridden
12453 * by an implementing function.
12455 * @param {EventObject} e
12457 onTriggerClick : Roo.emptyFn
12465 * @class Roo.bootstrap.CardUploader
12466 * @extends Roo.bootstrap.Button
12467 * Bootstrap Card Uploader class - it's a button which when you add files to it, adds cards below with preview and the name...
12468 * @cfg {Number} errorTimeout default 3000
12469 * @cfg {Array} images an array of ?? Img objects ??? when loading existing files..
12470 * @cfg {Array} html The button text.
12474 * Create a new CardUploader
12475 * @param {Object} config The config object
12478 Roo.bootstrap.CardUploader = function(config){
12482 Roo.bootstrap.CardUploader.superclass.constructor.call(this, config);
12485 this.fileCollection = new Roo.util.MixedCollection(false,function(r) {
12492 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input, {
12495 errorTimeout : 3000,
12499 fileCollection : false,
12502 getAutoCreate : function()
12506 cls :'form-group' ,
12511 //cls : 'input-group-addon',
12512 html : this.fieldLabel
12519 value : this.value,
12520 cls : 'd-none form-control'
12525 multiple : 'multiple',
12527 cls : 'd-none roo-card-upload-selector'
12531 cls : 'roo-card-uploader-button-container w-100 mb-2'
12534 cls : 'card-columns roo-card-uploader-container'
12544 getChildContainer : function() /// what children are added to.
12546 return this.containerEl;
12549 getButtonContainer : function() /// what children are added to.
12551 return this.el.select(".roo-card-uploader-button-container").first();
12554 initEvents : function()
12557 Roo.bootstrap.Input.prototype.initEvents.call(this);
12561 xns: Roo.bootstrap,
12564 container_method : 'getButtonContainer' ,
12565 html : this.html, // fix changable?
12568 'click' : function(btn, e) {
12577 this.urlAPI = (window.createObjectURL && window) ||
12578 (window.URL && URL.revokeObjectURL && URL) ||
12579 (window.webkitURL && webkitURL);
12584 this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
12586 this.selectorEl.on('change', this.onFileSelected, this);
12589 this.images.forEach(function(img) {
12592 this.images = false;
12594 this.containerEl = this.el.select('.roo-card-uploader-container', true).first();
12600 onClick : function(e)
12602 e.preventDefault();
12604 this.selectorEl.dom.click();
12608 onFileSelected : function(e)
12610 e.preventDefault();
12612 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
12616 Roo.each(this.selectorEl.dom.files, function(file){
12617 this.addFile(file);
12626 addFile : function(file)
12629 if(typeof(file) === 'string'){
12630 throw "Add file by name?"; // should not happen
12634 if(!file || !this.urlAPI){
12644 var url = _this.urlAPI.createObjectURL( file);
12647 id : Roo.bootstrap.CardUploader.ID--,
12648 is_uploaded : false,
12651 mimetype : file.type,
12658 addCard : function (data)
12660 // hidden input element?
12661 // if the file is not an image...
12662 //then we need to use something other that and header_image
12667 xns : Roo.bootstrap,
12668 xtype : 'CardFooter',
12671 xns : Roo.bootstrap,
12677 xns : Roo.bootstrap,
12679 html : String.format("<small>{0}</small>", data.title),
12680 cls : 'col-11 text-left',
12685 click : function() {
12686 this.downloadCard(data.id)
12692 xns : Roo.bootstrap,
12700 click : function() {
12701 t.removeCard(data.id)
12713 var cn = this.addxtype(
12716 xns : Roo.bootstrap,
12719 header : !data.mimetype.match(/image/) && !data.preview ? "Document": false,
12720 header_image : data.mimetype.match(/image/) ? data.src : data.preview,
12721 header_image_fit_square: true, // fixme - we probably need to use the 'Img' element to do stuff like this.
12726 initEvents : function() {
12727 Roo.bootstrap.Card.prototype.initEvents.call(this);
12728 this.imgEl = this.el.select('.card-img-top').first();
12730 this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
12731 this.imgEl.set({ 'pointer' : 'cursor' });
12740 // dont' really need ot update items.
12741 // this.items.push(cn);
12742 this.fileCollection.add(cn);
12743 this.updateInput();
12746 removeCard : function(id)
12749 var card = this.fileCollection.get(id);
12750 card.data.is_deleted = 1;
12751 card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
12752 this.fileCollection.remove(card);
12753 //this.items = this.items.filter(function(e) { return e != card });
12754 // dont' really need ot update items.
12755 card.el.dom.parentNode.removeChild(card.el.dom);
12760 this.fileCollection.each(function(card) {
12761 card.el.dom.parentNode.removeChild(card.el.dom);
12763 this.fileCollection.clear();
12764 this.updateInput();
12767 updateInput : function()
12770 this.fileCollection.each(function(e) {
12774 this.inputEl().dom.value = JSON.stringify(data);
12781 Roo.bootstrap.CardUploader.ID = -1;/*
12783 * Ext JS Library 1.1.1
12784 * Copyright(c) 2006-2007, Ext JS, LLC.
12786 * Originally Released Under LGPL - original licence link has changed is not relivant.
12789 * <script type="text/javascript">
12794 * @class Roo.data.SortTypes
12796 * Defines the default sorting (casting?) comparison functions used when sorting data.
12798 Roo.data.SortTypes = {
12800 * Default sort that does nothing
12801 * @param {Mixed} s The value being converted
12802 * @return {Mixed} The comparison value
12804 none : function(s){
12809 * The regular expression used to strip tags
12813 stripTagsRE : /<\/?[^>]+>/gi,
12816 * Strips all HTML tags to sort on text only
12817 * @param {Mixed} s The value being converted
12818 * @return {String} The comparison value
12820 asText : function(s){
12821 return String(s).replace(this.stripTagsRE, "");
12825 * Strips all HTML tags to sort on text only - Case insensitive
12826 * @param {Mixed} s The value being converted
12827 * @return {String} The comparison value
12829 asUCText : function(s){
12830 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12834 * Case insensitive string
12835 * @param {Mixed} s The value being converted
12836 * @return {String} The comparison value
12838 asUCString : function(s) {
12839 return String(s).toUpperCase();
12844 * @param {Mixed} s The value being converted
12845 * @return {Number} The comparison value
12847 asDate : function(s) {
12851 if(s instanceof Date){
12852 return s.getTime();
12854 return Date.parse(String(s));
12859 * @param {Mixed} s The value being converted
12860 * @return {Float} The comparison value
12862 asFloat : function(s) {
12863 var val = parseFloat(String(s).replace(/,/g, ""));
12872 * @param {Mixed} s The value being converted
12873 * @return {Number} The comparison value
12875 asInt : function(s) {
12876 var val = parseInt(String(s).replace(/,/g, ""));
12884 * Ext JS Library 1.1.1
12885 * Copyright(c) 2006-2007, Ext JS, LLC.
12887 * Originally Released Under LGPL - original licence link has changed is not relivant.
12890 * <script type="text/javascript">
12894 * @class Roo.data.Record
12895 * Instances of this class encapsulate both record <em>definition</em> information, and record
12896 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12897 * to access Records cached in an {@link Roo.data.Store} object.<br>
12899 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12900 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12903 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12905 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12906 * {@link #create}. The parameters are the same.
12907 * @param {Array} data An associative Array of data values keyed by the field name.
12908 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12909 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12910 * not specified an integer id is generated.
12912 Roo.data.Record = function(data, id){
12913 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12918 * Generate a constructor for a specific record layout.
12919 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12920 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12921 * Each field definition object may contain the following properties: <ul>
12922 * <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,
12923 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12924 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12925 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12926 * is being used, then this is a string containing the javascript expression to reference the data relative to
12927 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12928 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12929 * this may be omitted.</p></li>
12930 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12931 * <ul><li>auto (Default, implies no conversion)</li>
12936 * <li>date</li></ul></p></li>
12937 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12938 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12939 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12940 * by the Reader into an object that will be stored in the Record. It is passed the
12941 * following parameters:<ul>
12942 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12944 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12946 * <br>usage:<br><pre><code>
12947 var TopicRecord = Roo.data.Record.create(
12948 {name: 'title', mapping: 'topic_title'},
12949 {name: 'author', mapping: 'username'},
12950 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12951 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12952 {name: 'lastPoster', mapping: 'user2'},
12953 {name: 'excerpt', mapping: 'post_text'}
12956 var myNewRecord = new TopicRecord({
12957 title: 'Do my job please',
12960 lastPost: new Date(),
12961 lastPoster: 'Animal',
12962 excerpt: 'No way dude!'
12964 myStore.add(myNewRecord);
12969 Roo.data.Record.create = function(o){
12970 var f = function(){
12971 f.superclass.constructor.apply(this, arguments);
12973 Roo.extend(f, Roo.data.Record);
12974 var p = f.prototype;
12975 p.fields = new Roo.util.MixedCollection(false, function(field){
12978 for(var i = 0, len = o.length; i < len; i++){
12979 p.fields.add(new Roo.data.Field(o[i]));
12981 f.getField = function(name){
12982 return p.fields.get(name);
12987 Roo.data.Record.AUTO_ID = 1000;
12988 Roo.data.Record.EDIT = 'edit';
12989 Roo.data.Record.REJECT = 'reject';
12990 Roo.data.Record.COMMIT = 'commit';
12992 Roo.data.Record.prototype = {
12994 * Readonly flag - true if this record has been modified.
13003 join : function(store){
13004 this.store = store;
13008 * Set the named field to the specified value.
13009 * @param {String} name The name of the field to set.
13010 * @param {Object} value The value to set the field to.
13012 set : function(name, value){
13013 if(this.data[name] == value){
13017 if(!this.modified){
13018 this.modified = {};
13020 if(typeof this.modified[name] == 'undefined'){
13021 this.modified[name] = this.data[name];
13023 this.data[name] = value;
13024 if(!this.editing && this.store){
13025 this.store.afterEdit(this);
13030 * Get the value of the named field.
13031 * @param {String} name The name of the field to get the value of.
13032 * @return {Object} The value of the field.
13034 get : function(name){
13035 return this.data[name];
13039 beginEdit : function(){
13040 this.editing = true;
13041 this.modified = {};
13045 cancelEdit : function(){
13046 this.editing = false;
13047 delete this.modified;
13051 endEdit : function(){
13052 this.editing = false;
13053 if(this.dirty && this.store){
13054 this.store.afterEdit(this);
13059 * Usually called by the {@link Roo.data.Store} which owns the Record.
13060 * Rejects all changes made to the Record since either creation, or the last commit operation.
13061 * Modified fields are reverted to their original values.
13063 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
13064 * of reject operations.
13066 reject : function(){
13067 var m = this.modified;
13069 if(typeof m[n] != "function"){
13070 this.data[n] = m[n];
13073 this.dirty = false;
13074 delete this.modified;
13075 this.editing = false;
13077 this.store.afterReject(this);
13082 * Usually called by the {@link Roo.data.Store} which owns the Record.
13083 * Commits all changes made to the Record since either creation, or the last commit operation.
13085 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
13086 * of commit operations.
13088 commit : function(){
13089 this.dirty = false;
13090 delete this.modified;
13091 this.editing = false;
13093 this.store.afterCommit(this);
13098 hasError : function(){
13099 return this.error != null;
13103 clearError : function(){
13108 * Creates a copy of this record.
13109 * @param {String} id (optional) A new record id if you don't want to use this record's id
13112 copy : function(newId) {
13113 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
13117 * Ext JS Library 1.1.1
13118 * Copyright(c) 2006-2007, Ext JS, LLC.
13120 * Originally Released Under LGPL - original licence link has changed is not relivant.
13123 * <script type="text/javascript">
13129 * @class Roo.data.Store
13130 * @extends Roo.util.Observable
13131 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
13132 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
13134 * 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
13135 * has no knowledge of the format of the data returned by the Proxy.<br>
13137 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
13138 * instances from the data object. These records are cached and made available through accessor functions.
13140 * Creates a new Store.
13141 * @param {Object} config A config object containing the objects needed for the Store to access data,
13142 * and read the data into Records.
13144 Roo.data.Store = function(config){
13145 this.data = new Roo.util.MixedCollection(false);
13146 this.data.getKey = function(o){
13149 this.baseParams = {};
13151 this.paramNames = {
13156 "multisort" : "_multisort"
13159 if(config && config.data){
13160 this.inlineData = config.data;
13161 delete config.data;
13164 Roo.apply(this, config);
13166 if(this.reader){ // reader passed
13167 this.reader = Roo.factory(this.reader, Roo.data);
13168 this.reader.xmodule = this.xmodule || false;
13169 if(!this.recordType){
13170 this.recordType = this.reader.recordType;
13172 if(this.reader.onMetaChange){
13173 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
13177 if(this.recordType){
13178 this.fields = this.recordType.prototype.fields;
13180 this.modified = [];
13184 * @event datachanged
13185 * Fires when the data cache has changed, and a widget which is using this Store
13186 * as a Record cache should refresh its view.
13187 * @param {Store} this
13189 datachanged : true,
13191 * @event metachange
13192 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
13193 * @param {Store} this
13194 * @param {Object} meta The JSON metadata
13199 * Fires when Records have been added to the Store
13200 * @param {Store} this
13201 * @param {Roo.data.Record[]} records The array of Records added
13202 * @param {Number} index The index at which the record(s) were added
13207 * Fires when a Record has been removed from the Store
13208 * @param {Store} this
13209 * @param {Roo.data.Record} record The Record that was removed
13210 * @param {Number} index The index at which the record was removed
13215 * Fires when a Record has been updated
13216 * @param {Store} this
13217 * @param {Roo.data.Record} record The Record that was updated
13218 * @param {String} operation The update operation being performed. Value may be one of:
13220 Roo.data.Record.EDIT
13221 Roo.data.Record.REJECT
13222 Roo.data.Record.COMMIT
13228 * Fires when the data cache has been cleared.
13229 * @param {Store} this
13233 * @event beforeload
13234 * Fires before a request is made for a new data object. If the beforeload handler returns false
13235 * the load action will be canceled.
13236 * @param {Store} this
13237 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13241 * @event beforeloadadd
13242 * Fires after a new set of Records has been loaded.
13243 * @param {Store} this
13244 * @param {Roo.data.Record[]} records The Records that were loaded
13245 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13247 beforeloadadd : true,
13250 * Fires after a new set of Records has been loaded, before they are added to the store.
13251 * @param {Store} this
13252 * @param {Roo.data.Record[]} records The Records that were loaded
13253 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13254 * @params {Object} return from reader
13258 * @event loadexception
13259 * Fires if an exception occurs in the Proxy during loading.
13260 * Called with the signature of the Proxy's "loadexception" event.
13261 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
13264 * @param {Object} return from JsonData.reader() - success, totalRecords, records
13265 * @param {Object} load options
13266 * @param {Object} jsonData from your request (normally this contains the Exception)
13268 loadexception : true
13272 this.proxy = Roo.factory(this.proxy, Roo.data);
13273 this.proxy.xmodule = this.xmodule || false;
13274 this.relayEvents(this.proxy, ["loadexception"]);
13276 this.sortToggle = {};
13277 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
13279 Roo.data.Store.superclass.constructor.call(this);
13281 if(this.inlineData){
13282 this.loadData(this.inlineData);
13283 delete this.inlineData;
13287 Roo.extend(Roo.data.Store, Roo.util.Observable, {
13289 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
13290 * without a remote query - used by combo/forms at present.
13294 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
13297 * @cfg {Array} data Inline data to be loaded when the store is initialized.
13300 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
13301 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
13304 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
13305 * on any HTTP request
13308 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
13311 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
13315 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
13316 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
13318 remoteSort : false,
13321 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
13322 * loaded or when a record is removed. (defaults to false).
13324 pruneModifiedRecords : false,
13327 lastOptions : null,
13330 * Add Records to the Store and fires the add event.
13331 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13333 add : function(records){
13334 records = [].concat(records);
13335 for(var i = 0, len = records.length; i < len; i++){
13336 records[i].join(this);
13338 var index = this.data.length;
13339 this.data.addAll(records);
13340 this.fireEvent("add", this, records, index);
13344 * Remove a Record from the Store and fires the remove event.
13345 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
13347 remove : function(record){
13348 var index = this.data.indexOf(record);
13349 this.data.removeAt(index);
13351 if(this.pruneModifiedRecords){
13352 this.modified.remove(record);
13354 this.fireEvent("remove", this, record, index);
13358 * Remove all Records from the Store and fires the clear event.
13360 removeAll : function(){
13362 if(this.pruneModifiedRecords){
13363 this.modified = [];
13365 this.fireEvent("clear", this);
13369 * Inserts Records to the Store at the given index and fires the add event.
13370 * @param {Number} index The start index at which to insert the passed Records.
13371 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13373 insert : function(index, records){
13374 records = [].concat(records);
13375 for(var i = 0, len = records.length; i < len; i++){
13376 this.data.insert(index, records[i]);
13377 records[i].join(this);
13379 this.fireEvent("add", this, records, index);
13383 * Get the index within the cache of the passed Record.
13384 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
13385 * @return {Number} The index of the passed Record. Returns -1 if not found.
13387 indexOf : function(record){
13388 return this.data.indexOf(record);
13392 * Get the index within the cache of the Record with the passed id.
13393 * @param {String} id The id of the Record to find.
13394 * @return {Number} The index of the Record. Returns -1 if not found.
13396 indexOfId : function(id){
13397 return this.data.indexOfKey(id);
13401 * Get the Record with the specified id.
13402 * @param {String} id The id of the Record to find.
13403 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
13405 getById : function(id){
13406 return this.data.key(id);
13410 * Get the Record at the specified index.
13411 * @param {Number} index The index of the Record to find.
13412 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
13414 getAt : function(index){
13415 return this.data.itemAt(index);
13419 * Returns a range of Records between specified indices.
13420 * @param {Number} startIndex (optional) The starting index (defaults to 0)
13421 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
13422 * @return {Roo.data.Record[]} An array of Records
13424 getRange : function(start, end){
13425 return this.data.getRange(start, end);
13429 storeOptions : function(o){
13430 o = Roo.apply({}, o);
13433 this.lastOptions = o;
13437 * Loads the Record cache from the configured Proxy using the configured Reader.
13439 * If using remote paging, then the first load call must specify the <em>start</em>
13440 * and <em>limit</em> properties in the options.params property to establish the initial
13441 * position within the dataset, and the number of Records to cache on each read from the Proxy.
13443 * <strong>It is important to note that for remote data sources, loading is asynchronous,
13444 * and this call will return before the new data has been loaded. Perform any post-processing
13445 * in a callback function, or in a "load" event handler.</strong>
13447 * @param {Object} options An object containing properties which control loading options:<ul>
13448 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
13449 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
13450 * passed the following arguments:<ul>
13451 * <li>r : Roo.data.Record[]</li>
13452 * <li>options: Options object from the load call</li>
13453 * <li>success: Boolean success indicator</li></ul></li>
13454 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
13455 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
13458 load : function(options){
13459 options = options || {};
13460 if(this.fireEvent("beforeload", this, options) !== false){
13461 this.storeOptions(options);
13462 var p = Roo.apply(options.params || {}, this.baseParams);
13463 // if meta was not loaded from remote source.. try requesting it.
13464 if (!this.reader.metaFromRemote) {
13465 p._requestMeta = 1;
13467 if(this.sortInfo && this.remoteSort){
13468 var pn = this.paramNames;
13469 p[pn["sort"]] = this.sortInfo.field;
13470 p[pn["dir"]] = this.sortInfo.direction;
13472 if (this.multiSort) {
13473 var pn = this.paramNames;
13474 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
13477 this.proxy.load(p, this.reader, this.loadRecords, this, options);
13482 * Reloads the Record cache from the configured Proxy using the configured Reader and
13483 * the options from the last load operation performed.
13484 * @param {Object} options (optional) An object containing properties which may override the options
13485 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
13486 * the most recently used options are reused).
13488 reload : function(options){
13489 this.load(Roo.applyIf(options||{}, this.lastOptions));
13493 // Called as a callback by the Reader during a load operation.
13494 loadRecords : function(o, options, success){
13495 if(!o || success === false){
13496 if(success !== false){
13497 this.fireEvent("load", this, [], options, o);
13499 if(options.callback){
13500 options.callback.call(options.scope || this, [], options, false);
13504 // if data returned failure - throw an exception.
13505 if (o.success === false) {
13506 // show a message if no listener is registered.
13507 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
13508 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
13510 // loadmask wil be hooked into this..
13511 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
13514 var r = o.records, t = o.totalRecords || r.length;
13516 this.fireEvent("beforeloadadd", this, r, options, o);
13518 if(!options || options.add !== true){
13519 if(this.pruneModifiedRecords){
13520 this.modified = [];
13522 for(var i = 0, len = r.length; i < len; i++){
13526 this.data = this.snapshot;
13527 delete this.snapshot;
13530 this.data.addAll(r);
13531 this.totalLength = t;
13533 this.fireEvent("datachanged", this);
13535 this.totalLength = Math.max(t, this.data.length+r.length);
13539 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
13541 var e = new Roo.data.Record({});
13543 e.set(this.parent.displayField, this.parent.emptyTitle);
13544 e.set(this.parent.valueField, '');
13549 this.fireEvent("load", this, r, options, o);
13550 if(options.callback){
13551 options.callback.call(options.scope || this, r, options, true);
13557 * Loads data from a passed data block. A Reader which understands the format of the data
13558 * must have been configured in the constructor.
13559 * @param {Object} data The data block from which to read the Records. The format of the data expected
13560 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
13561 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
13563 loadData : function(o, append){
13564 var r = this.reader.readRecords(o);
13565 this.loadRecords(r, {add: append}, true);
13569 * using 'cn' the nested child reader read the child array into it's child stores.
13570 * @param {Object} rec The record with a 'children array
13572 loadDataFromChildren : function(rec)
13574 this.loadData(this.reader.toLoadData(rec));
13579 * Gets the number of cached records.
13581 * <em>If using paging, this may not be the total size of the dataset. If the data object
13582 * used by the Reader contains the dataset size, then the getTotalCount() function returns
13583 * the data set size</em>
13585 getCount : function(){
13586 return this.data.length || 0;
13590 * Gets the total number of records in the dataset as returned by the server.
13592 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
13593 * the dataset size</em>
13595 getTotalCount : function(){
13596 return this.totalLength || 0;
13600 * Returns the sort state of the Store as an object with two properties:
13602 field {String} The name of the field by which the Records are sorted
13603 direction {String} The sort order, "ASC" or "DESC"
13606 getSortState : function(){
13607 return this.sortInfo;
13611 applySort : function(){
13612 if(this.sortInfo && !this.remoteSort){
13613 var s = this.sortInfo, f = s.field;
13614 var st = this.fields.get(f).sortType;
13615 var fn = function(r1, r2){
13616 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
13617 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
13619 this.data.sort(s.direction, fn);
13620 if(this.snapshot && this.snapshot != this.data){
13621 this.snapshot.sort(s.direction, fn);
13627 * Sets the default sort column and order to be used by the next load operation.
13628 * @param {String} fieldName The name of the field to sort by.
13629 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13631 setDefaultSort : function(field, dir){
13632 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
13636 * Sort the Records.
13637 * If remote sorting is used, the sort is performed on the server, and the cache is
13638 * reloaded. If local sorting is used, the cache is sorted internally.
13639 * @param {String} fieldName The name of the field to sort by.
13640 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13642 sort : function(fieldName, dir){
13643 var f = this.fields.get(fieldName);
13645 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
13647 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
13648 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
13653 this.sortToggle[f.name] = dir;
13654 this.sortInfo = {field: f.name, direction: dir};
13655 if(!this.remoteSort){
13657 this.fireEvent("datachanged", this);
13659 this.load(this.lastOptions);
13664 * Calls the specified function for each of the Records in the cache.
13665 * @param {Function} fn The function to call. The Record is passed as the first parameter.
13666 * Returning <em>false</em> aborts and exits the iteration.
13667 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
13669 each : function(fn, scope){
13670 this.data.each(fn, scope);
13674 * Gets all records modified since the last commit. Modified records are persisted across load operations
13675 * (e.g., during paging).
13676 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
13678 getModifiedRecords : function(){
13679 return this.modified;
13683 createFilterFn : function(property, value, anyMatch){
13684 if(!value.exec){ // not a regex
13685 value = String(value);
13686 if(value.length == 0){
13689 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
13691 return function(r){
13692 return value.test(r.data[property]);
13697 * Sums the value of <i>property</i> for each record between start and end and returns the result.
13698 * @param {String} property A field on your records
13699 * @param {Number} start The record index to start at (defaults to 0)
13700 * @param {Number} end The last record index to include (defaults to length - 1)
13701 * @return {Number} The sum
13703 sum : function(property, start, end){
13704 var rs = this.data.items, v = 0;
13705 start = start || 0;
13706 end = (end || end === 0) ? end : rs.length-1;
13708 for(var i = start; i <= end; i++){
13709 v += (rs[i].data[property] || 0);
13715 * Filter the records by a specified property.
13716 * @param {String} field A field on your records
13717 * @param {String/RegExp} value Either a string that the field
13718 * should start with or a RegExp to test against the field
13719 * @param {Boolean} anyMatch True to match any part not just the beginning
13721 filter : function(property, value, anyMatch){
13722 var fn = this.createFilterFn(property, value, anyMatch);
13723 return fn ? this.filterBy(fn) : this.clearFilter();
13727 * Filter by a function. The specified function will be called with each
13728 * record in this data source. If the function returns true the record is included,
13729 * otherwise it is filtered.
13730 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13731 * @param {Object} scope (optional) The scope of the function (defaults to this)
13733 filterBy : function(fn, scope){
13734 this.snapshot = this.snapshot || this.data;
13735 this.data = this.queryBy(fn, scope||this);
13736 this.fireEvent("datachanged", this);
13740 * Query the records by a specified property.
13741 * @param {String} field A field on your records
13742 * @param {String/RegExp} value Either a string that the field
13743 * should start with or a RegExp to test against the field
13744 * @param {Boolean} anyMatch True to match any part not just the beginning
13745 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13747 query : function(property, value, anyMatch){
13748 var fn = this.createFilterFn(property, value, anyMatch);
13749 return fn ? this.queryBy(fn) : this.data.clone();
13753 * Query by a function. The specified function will be called with each
13754 * record in this data source. If the function returns true the record is included
13756 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13757 * @param {Object} scope (optional) The scope of the function (defaults to this)
13758 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13760 queryBy : function(fn, scope){
13761 var data = this.snapshot || this.data;
13762 return data.filterBy(fn, scope||this);
13766 * Collects unique values for a particular dataIndex from this store.
13767 * @param {String} dataIndex The property to collect
13768 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
13769 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
13770 * @return {Array} An array of the unique values
13772 collect : function(dataIndex, allowNull, bypassFilter){
13773 var d = (bypassFilter === true && this.snapshot) ?
13774 this.snapshot.items : this.data.items;
13775 var v, sv, r = [], l = {};
13776 for(var i = 0, len = d.length; i < len; i++){
13777 v = d[i].data[dataIndex];
13779 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
13788 * Revert to a view of the Record cache with no filtering applied.
13789 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13791 clearFilter : function(suppressEvent){
13792 if(this.snapshot && this.snapshot != this.data){
13793 this.data = this.snapshot;
13794 delete this.snapshot;
13795 if(suppressEvent !== true){
13796 this.fireEvent("datachanged", this);
13802 afterEdit : function(record){
13803 if(this.modified.indexOf(record) == -1){
13804 this.modified.push(record);
13806 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13810 afterReject : function(record){
13811 this.modified.remove(record);
13812 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13816 afterCommit : function(record){
13817 this.modified.remove(record);
13818 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13822 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13823 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13825 commitChanges : function(){
13826 var m = this.modified.slice(0);
13827 this.modified = [];
13828 for(var i = 0, len = m.length; i < len; i++){
13834 * Cancel outstanding changes on all changed records.
13836 rejectChanges : function(){
13837 var m = this.modified.slice(0);
13838 this.modified = [];
13839 for(var i = 0, len = m.length; i < len; i++){
13844 onMetaChange : function(meta, rtype, o){
13845 this.recordType = rtype;
13846 this.fields = rtype.prototype.fields;
13847 delete this.snapshot;
13848 this.sortInfo = meta.sortInfo || this.sortInfo;
13849 this.modified = [];
13850 this.fireEvent('metachange', this, this.reader.meta);
13853 moveIndex : function(data, type)
13855 var index = this.indexOf(data);
13857 var newIndex = index + type;
13861 this.insert(newIndex, data);
13866 * Ext JS Library 1.1.1
13867 * Copyright(c) 2006-2007, Ext JS, LLC.
13869 * Originally Released Under LGPL - original licence link has changed is not relivant.
13872 * <script type="text/javascript">
13876 * @class Roo.data.SimpleStore
13877 * @extends Roo.data.Store
13878 * Small helper class to make creating Stores from Array data easier.
13879 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13880 * @cfg {Array} fields An array of field definition objects, or field name strings.
13881 * @cfg {Object} an existing reader (eg. copied from another store)
13882 * @cfg {Array} data The multi-dimensional array of data
13884 * @param {Object} config
13886 Roo.data.SimpleStore = function(config)
13888 Roo.data.SimpleStore.superclass.constructor.call(this, {
13890 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13893 Roo.data.Record.create(config.fields)
13895 proxy : new Roo.data.MemoryProxy(config.data)
13899 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13901 * Ext JS Library 1.1.1
13902 * Copyright(c) 2006-2007, Ext JS, LLC.
13904 * Originally Released Under LGPL - original licence link has changed is not relivant.
13907 * <script type="text/javascript">
13912 * @extends Roo.data.Store
13913 * @class Roo.data.JsonStore
13914 * Small helper class to make creating Stores for JSON data easier. <br/>
13916 var store = new Roo.data.JsonStore({
13917 url: 'get-images.php',
13919 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13922 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13923 * JsonReader and HttpProxy (unless inline data is provided).</b>
13924 * @cfg {Array} fields An array of field definition objects, or field name strings.
13926 * @param {Object} config
13928 Roo.data.JsonStore = function(c){
13929 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13930 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13931 reader: new Roo.data.JsonReader(c, c.fields)
13934 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13936 * Ext JS Library 1.1.1
13937 * Copyright(c) 2006-2007, Ext JS, LLC.
13939 * Originally Released Under LGPL - original licence link has changed is not relivant.
13942 * <script type="text/javascript">
13946 Roo.data.Field = function(config){
13947 if(typeof config == "string"){
13948 config = {name: config};
13950 Roo.apply(this, config);
13953 this.type = "auto";
13956 var st = Roo.data.SortTypes;
13957 // named sortTypes are supported, here we look them up
13958 if(typeof this.sortType == "string"){
13959 this.sortType = st[this.sortType];
13962 // set default sortType for strings and dates
13963 if(!this.sortType){
13966 this.sortType = st.asUCString;
13969 this.sortType = st.asDate;
13972 this.sortType = st.none;
13977 var stripRe = /[\$,%]/g;
13979 // prebuilt conversion function for this field, instead of
13980 // switching every time we're reading a value
13982 var cv, dateFormat = this.dateFormat;
13987 cv = function(v){ return v; };
13990 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13994 return v !== undefined && v !== null && v !== '' ?
13995 parseInt(String(v).replace(stripRe, ""), 10) : '';
14000 return v !== undefined && v !== null && v !== '' ?
14001 parseFloat(String(v).replace(stripRe, ""), 10) : '';
14006 cv = function(v){ return v === true || v === "true" || v == 1; };
14013 if(v instanceof Date){
14017 if(dateFormat == "timestamp"){
14018 return new Date(v*1000);
14020 return Date.parseDate(v, dateFormat);
14022 var parsed = Date.parse(v);
14023 return parsed ? new Date(parsed) : null;
14032 Roo.data.Field.prototype = {
14040 * Ext JS Library 1.1.1
14041 * Copyright(c) 2006-2007, Ext JS, LLC.
14043 * Originally Released Under LGPL - original licence link has changed is not relivant.
14046 * <script type="text/javascript">
14049 // Base class for reading structured data from a data source. This class is intended to be
14050 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
14053 * @class Roo.data.DataReader
14054 * Base class for reading structured data from a data source. This class is intended to be
14055 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
14058 Roo.data.DataReader = function(meta, recordType){
14062 this.recordType = recordType instanceof Array ?
14063 Roo.data.Record.create(recordType) : recordType;
14066 Roo.data.DataReader.prototype = {
14069 readerType : 'Data',
14071 * Create an empty record
14072 * @param {Object} data (optional) - overlay some values
14073 * @return {Roo.data.Record} record created.
14075 newRow : function(d) {
14077 this.recordType.prototype.fields.each(function(c) {
14079 case 'int' : da[c.name] = 0; break;
14080 case 'date' : da[c.name] = new Date(); break;
14081 case 'float' : da[c.name] = 0.0; break;
14082 case 'boolean' : da[c.name] = false; break;
14083 default : da[c.name] = ""; break;
14087 return new this.recordType(Roo.apply(da, d));
14093 * Ext JS Library 1.1.1
14094 * Copyright(c) 2006-2007, Ext JS, LLC.
14096 * Originally Released Under LGPL - original licence link has changed is not relivant.
14099 * <script type="text/javascript">
14103 * @class Roo.data.DataProxy
14104 * @extends Roo.data.Observable
14105 * This class is an abstract base class for implementations which provide retrieval of
14106 * unformatted data objects.<br>
14108 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
14109 * (of the appropriate type which knows how to parse the data object) to provide a block of
14110 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
14112 * Custom implementations must implement the load method as described in
14113 * {@link Roo.data.HttpProxy#load}.
14115 Roo.data.DataProxy = function(){
14118 * @event beforeload
14119 * Fires before a network request is made to retrieve a data object.
14120 * @param {Object} This DataProxy object.
14121 * @param {Object} params The params parameter to the load function.
14126 * Fires before the load method's callback is called.
14127 * @param {Object} This DataProxy object.
14128 * @param {Object} o The data object.
14129 * @param {Object} arg The callback argument object passed to the load function.
14133 * @event loadexception
14134 * Fires if an Exception occurs during data retrieval.
14135 * @param {Object} This DataProxy object.
14136 * @param {Object} o The data object.
14137 * @param {Object} arg The callback argument object passed to the load function.
14138 * @param {Object} e The Exception.
14140 loadexception : true
14142 Roo.data.DataProxy.superclass.constructor.call(this);
14145 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
14148 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
14152 * Ext JS Library 1.1.1
14153 * Copyright(c) 2006-2007, Ext JS, LLC.
14155 * Originally Released Under LGPL - original licence link has changed is not relivant.
14158 * <script type="text/javascript">
14161 * @class Roo.data.MemoryProxy
14162 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
14163 * to the Reader when its load method is called.
14165 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
14167 Roo.data.MemoryProxy = function(data){
14171 Roo.data.MemoryProxy.superclass.constructor.call(this);
14175 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
14178 * Load data from the requested source (in this case an in-memory
14179 * data object passed to the constructor), read the data object into
14180 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14181 * process that block using the passed callback.
14182 * @param {Object} params This parameter is not used by the MemoryProxy class.
14183 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14184 * object into a block of Roo.data.Records.
14185 * @param {Function} callback The function into which to pass the block of Roo.data.records.
14186 * The function must be passed <ul>
14187 * <li>The Record block object</li>
14188 * <li>The "arg" argument from the load function</li>
14189 * <li>A boolean success indicator</li>
14191 * @param {Object} scope The scope in which to call the callback
14192 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14194 load : function(params, reader, callback, scope, arg){
14195 params = params || {};
14198 result = reader.readRecords(params.data ? params.data :this.data);
14200 this.fireEvent("loadexception", this, arg, null, e);
14201 callback.call(scope, null, arg, false);
14204 callback.call(scope, result, arg, true);
14208 update : function(params, records){
14213 * Ext JS Library 1.1.1
14214 * Copyright(c) 2006-2007, Ext JS, LLC.
14216 * Originally Released Under LGPL - original licence link has changed is not relivant.
14219 * <script type="text/javascript">
14222 * @class Roo.data.HttpProxy
14223 * @extends Roo.data.DataProxy
14224 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
14225 * configured to reference a certain URL.<br><br>
14227 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
14228 * from which the running page was served.<br><br>
14230 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
14232 * Be aware that to enable the browser to parse an XML document, the server must set
14233 * the Content-Type header in the HTTP response to "text/xml".
14235 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
14236 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
14237 * will be used to make the request.
14239 Roo.data.HttpProxy = function(conn){
14240 Roo.data.HttpProxy.superclass.constructor.call(this);
14241 // is conn a conn config or a real conn?
14243 this.useAjax = !conn || !conn.events;
14247 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
14248 // thse are take from connection...
14251 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
14254 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
14255 * extra parameters to each request made by this object. (defaults to undefined)
14258 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
14259 * to each request made by this object. (defaults to undefined)
14262 * @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)
14265 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
14268 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
14274 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
14278 * Return the {@link Roo.data.Connection} object being used by this Proxy.
14279 * @return {Connection} The Connection object. This object may be used to subscribe to events on
14280 * a finer-grained basis than the DataProxy events.
14282 getConnection : function(){
14283 return this.useAjax ? Roo.Ajax : this.conn;
14287 * Load data from the configured {@link Roo.data.Connection}, read the data object into
14288 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
14289 * process that block using the passed callback.
14290 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14291 * for the request to the remote server.
14292 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14293 * object into a block of Roo.data.Records.
14294 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14295 * The function must be passed <ul>
14296 * <li>The Record block object</li>
14297 * <li>The "arg" argument from the load function</li>
14298 * <li>A boolean success indicator</li>
14300 * @param {Object} scope The scope in which to call the callback
14301 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14303 load : function(params, reader, callback, scope, arg){
14304 if(this.fireEvent("beforeload", this, params) !== false){
14306 params : params || {},
14308 callback : callback,
14313 callback : this.loadResponse,
14317 Roo.applyIf(o, this.conn);
14318 if(this.activeRequest){
14319 Roo.Ajax.abort(this.activeRequest);
14321 this.activeRequest = Roo.Ajax.request(o);
14323 this.conn.request(o);
14326 callback.call(scope||this, null, arg, false);
14331 loadResponse : function(o, success, response){
14332 delete this.activeRequest;
14334 this.fireEvent("loadexception", this, o, response);
14335 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14340 result = o.reader.read(response);
14342 this.fireEvent("loadexception", this, o, response, e);
14343 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14347 this.fireEvent("load", this, o, o.request.arg);
14348 o.request.callback.call(o.request.scope, result, o.request.arg, true);
14352 update : function(dataSet){
14357 updateResponse : function(dataSet){
14362 * Ext JS Library 1.1.1
14363 * Copyright(c) 2006-2007, Ext JS, LLC.
14365 * Originally Released Under LGPL - original licence link has changed is not relivant.
14368 * <script type="text/javascript">
14372 * @class Roo.data.ScriptTagProxy
14373 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
14374 * other than the originating domain of the running page.<br><br>
14376 * <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
14377 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
14379 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
14380 * source code that is used as the source inside a <script> tag.<br><br>
14382 * In order for the browser to process the returned data, the server must wrap the data object
14383 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
14384 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
14385 * depending on whether the callback name was passed:
14388 boolean scriptTag = false;
14389 String cb = request.getParameter("callback");
14392 response.setContentType("text/javascript");
14394 response.setContentType("application/x-json");
14396 Writer out = response.getWriter();
14398 out.write(cb + "(");
14400 out.print(dataBlock.toJsonString());
14407 * @param {Object} config A configuration object.
14409 Roo.data.ScriptTagProxy = function(config){
14410 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
14411 Roo.apply(this, config);
14412 this.head = document.getElementsByTagName("head")[0];
14415 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
14417 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
14419 * @cfg {String} url The URL from which to request the data object.
14422 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
14426 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
14427 * the server the name of the callback function set up by the load call to process the returned data object.
14428 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
14429 * javascript output which calls this named function passing the data object as its only parameter.
14431 callbackParam : "callback",
14433 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
14434 * name to the request.
14439 * Load data from the configured URL, read the data object into
14440 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14441 * process that block using the passed callback.
14442 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14443 * for the request to the remote server.
14444 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14445 * object into a block of Roo.data.Records.
14446 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14447 * The function must be passed <ul>
14448 * <li>The Record block object</li>
14449 * <li>The "arg" argument from the load function</li>
14450 * <li>A boolean success indicator</li>
14452 * @param {Object} scope The scope in which to call the callback
14453 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14455 load : function(params, reader, callback, scope, arg){
14456 if(this.fireEvent("beforeload", this, params) !== false){
14458 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
14460 var url = this.url;
14461 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
14463 url += "&_dc=" + (new Date().getTime());
14465 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
14468 cb : "stcCallback"+transId,
14469 scriptId : "stcScript"+transId,
14473 callback : callback,
14479 window[trans.cb] = function(o){
14480 conn.handleResponse(o, trans);
14483 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
14485 if(this.autoAbort !== false){
14489 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
14491 var script = document.createElement("script");
14492 script.setAttribute("src", url);
14493 script.setAttribute("type", "text/javascript");
14494 script.setAttribute("id", trans.scriptId);
14495 this.head.appendChild(script);
14497 this.trans = trans;
14499 callback.call(scope||this, null, arg, false);
14504 isLoading : function(){
14505 return this.trans ? true : false;
14509 * Abort the current server request.
14511 abort : function(){
14512 if(this.isLoading()){
14513 this.destroyTrans(this.trans);
14518 destroyTrans : function(trans, isLoaded){
14519 this.head.removeChild(document.getElementById(trans.scriptId));
14520 clearTimeout(trans.timeoutId);
14522 window[trans.cb] = undefined;
14524 delete window[trans.cb];
14527 // if hasn't been loaded, wait for load to remove it to prevent script error
14528 window[trans.cb] = function(){
14529 window[trans.cb] = undefined;
14531 delete window[trans.cb];
14538 handleResponse : function(o, trans){
14539 this.trans = false;
14540 this.destroyTrans(trans, true);
14543 result = trans.reader.readRecords(o);
14545 this.fireEvent("loadexception", this, o, trans.arg, e);
14546 trans.callback.call(trans.scope||window, null, trans.arg, false);
14549 this.fireEvent("load", this, o, trans.arg);
14550 trans.callback.call(trans.scope||window, result, trans.arg, true);
14554 handleFailure : function(trans){
14555 this.trans = false;
14556 this.destroyTrans(trans, false);
14557 this.fireEvent("loadexception", this, null, trans.arg);
14558 trans.callback.call(trans.scope||window, null, trans.arg, false);
14562 * Ext JS Library 1.1.1
14563 * Copyright(c) 2006-2007, Ext JS, LLC.
14565 * Originally Released Under LGPL - original licence link has changed is not relivant.
14568 * <script type="text/javascript">
14572 * @class Roo.data.JsonReader
14573 * @extends Roo.data.DataReader
14574 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
14575 * based on mappings in a provided Roo.data.Record constructor.
14577 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
14578 * in the reply previously.
14583 var RecordDef = Roo.data.Record.create([
14584 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
14585 {name: 'occupation'} // This field will use "occupation" as the mapping.
14587 var myReader = new Roo.data.JsonReader({
14588 totalProperty: "results", // The property which contains the total dataset size (optional)
14589 root: "rows", // The property which contains an Array of row objects
14590 id: "id" // The property within each row object that provides an ID for the record (optional)
14594 * This would consume a JSON file like this:
14596 { 'results': 2, 'rows': [
14597 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
14598 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
14601 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
14602 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
14603 * paged from the remote server.
14604 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
14605 * @cfg {String} root name of the property which contains the Array of row objects.
14606 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14607 * @cfg {Array} fields Array of field definition objects
14609 * Create a new JsonReader
14610 * @param {Object} meta Metadata configuration options
14611 * @param {Object} recordType Either an Array of field definition objects,
14612 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
14614 Roo.data.JsonReader = function(meta, recordType){
14617 // set some defaults:
14618 Roo.applyIf(meta, {
14619 totalProperty: 'total',
14620 successProperty : 'success',
14625 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14627 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
14629 readerType : 'Json',
14632 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
14633 * Used by Store query builder to append _requestMeta to params.
14636 metaFromRemote : false,
14638 * This method is only used by a DataProxy which has retrieved data from a remote server.
14639 * @param {Object} response The XHR object which contains the JSON data in its responseText.
14640 * @return {Object} data A data block which is used by an Roo.data.Store object as
14641 * a cache of Roo.data.Records.
14643 read : function(response){
14644 var json = response.responseText;
14646 var o = /* eval:var:o */ eval("("+json+")");
14648 throw {message: "JsonReader.read: Json object not found"};
14654 this.metaFromRemote = true;
14655 this.meta = o.metaData;
14656 this.recordType = Roo.data.Record.create(o.metaData.fields);
14657 this.onMetaChange(this.meta, this.recordType, o);
14659 return this.readRecords(o);
14662 // private function a store will implement
14663 onMetaChange : function(meta, recordType, o){
14670 simpleAccess: function(obj, subsc) {
14677 getJsonAccessor: function(){
14679 return function(expr) {
14681 return(re.test(expr))
14682 ? new Function("obj", "return obj." + expr)
14687 return Roo.emptyFn;
14692 * Create a data block containing Roo.data.Records from an XML document.
14693 * @param {Object} o An object which contains an Array of row objects in the property specified
14694 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
14695 * which contains the total size of the dataset.
14696 * @return {Object} data A data block which is used by an Roo.data.Store object as
14697 * a cache of Roo.data.Records.
14699 readRecords : function(o){
14701 * After any data loads, the raw JSON data is available for further custom processing.
14705 var s = this.meta, Record = this.recordType,
14706 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
14708 // Generate extraction functions for the totalProperty, the root, the id, and for each field
14710 if(s.totalProperty) {
14711 this.getTotal = this.getJsonAccessor(s.totalProperty);
14713 if(s.successProperty) {
14714 this.getSuccess = this.getJsonAccessor(s.successProperty);
14716 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
14718 var g = this.getJsonAccessor(s.id);
14719 this.getId = function(rec) {
14721 return (r === undefined || r === "") ? null : r;
14724 this.getId = function(){return null;};
14727 for(var jj = 0; jj < fl; jj++){
14729 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
14730 this.ef[jj] = this.getJsonAccessor(map);
14734 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
14735 if(s.totalProperty){
14736 var vt = parseInt(this.getTotal(o), 10);
14741 if(s.successProperty){
14742 var vs = this.getSuccess(o);
14743 if(vs === false || vs === 'false'){
14748 for(var i = 0; i < c; i++){
14751 var id = this.getId(n);
14752 for(var j = 0; j < fl; j++){
14754 var v = this.ef[j](n);
14756 Roo.log('missing convert for ' + f.name);
14760 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
14762 var record = new Record(values, id);
14764 records[i] = record;
14770 totalRecords : totalRecords
14773 // used when loading children.. @see loadDataFromChildren
14774 toLoadData: function(rec)
14776 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14777 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14778 return { data : data, total : data.length };
14783 * Ext JS Library 1.1.1
14784 * Copyright(c) 2006-2007, Ext JS, LLC.
14786 * Originally Released Under LGPL - original licence link has changed is not relivant.
14789 * <script type="text/javascript">
14793 * @class Roo.data.ArrayReader
14794 * @extends Roo.data.DataReader
14795 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14796 * Each element of that Array represents a row of data fields. The
14797 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14798 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14802 var RecordDef = Roo.data.Record.create([
14803 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14804 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14806 var myReader = new Roo.data.ArrayReader({
14807 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14811 * This would consume an Array like this:
14813 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14817 * Create a new JsonReader
14818 * @param {Object} meta Metadata configuration options.
14819 * @param {Object|Array} recordType Either an Array of field definition objects
14821 * @cfg {Array} fields Array of field definition objects
14822 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14823 * as specified to {@link Roo.data.Record#create},
14824 * or an {@link Roo.data.Record} object
14827 * created using {@link Roo.data.Record#create}.
14829 Roo.data.ArrayReader = function(meta, recordType)
14831 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14834 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14837 * Create a data block containing Roo.data.Records from an XML document.
14838 * @param {Object} o An Array of row objects which represents the dataset.
14839 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14840 * a cache of Roo.data.Records.
14842 readRecords : function(o)
14844 var sid = this.meta ? this.meta.id : null;
14845 var recordType = this.recordType, fields = recordType.prototype.fields;
14848 for(var i = 0; i < root.length; i++){
14851 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14852 for(var j = 0, jlen = fields.length; j < jlen; j++){
14853 var f = fields.items[j];
14854 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14855 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14857 values[f.name] = v;
14859 var record = new recordType(values, id);
14861 records[records.length] = record;
14865 totalRecords : records.length
14868 // used when loading children.. @see loadDataFromChildren
14869 toLoadData: function(rec)
14871 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14872 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14883 * @class Roo.bootstrap.ComboBox
14884 * @extends Roo.bootstrap.TriggerField
14885 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14886 * @cfg {Boolean} append (true|false) default false
14887 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14888 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14889 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14890 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14891 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14892 * @cfg {Boolean} animate default true
14893 * @cfg {Boolean} emptyResultText only for touch device
14894 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14895 * @cfg {String} emptyTitle default ''
14896 * @cfg {Number} width fixed with? experimental
14898 * Create a new ComboBox.
14899 * @param {Object} config Configuration options
14901 Roo.bootstrap.ComboBox = function(config){
14902 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14906 * Fires when the dropdown list is expanded
14907 * @param {Roo.bootstrap.ComboBox} combo This combo box
14912 * Fires when the dropdown list is collapsed
14913 * @param {Roo.bootstrap.ComboBox} combo This combo box
14917 * @event beforeselect
14918 * Fires before a list item is selected. Return false to cancel the selection.
14919 * @param {Roo.bootstrap.ComboBox} combo This combo box
14920 * @param {Roo.data.Record} record The data record returned from the underlying store
14921 * @param {Number} index The index of the selected item in the dropdown list
14923 'beforeselect' : true,
14926 * Fires when a list item is selected
14927 * @param {Roo.bootstrap.ComboBox} combo This combo box
14928 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14929 * @param {Number} index The index of the selected item in the dropdown list
14933 * @event beforequery
14934 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14935 * The event object passed has these properties:
14936 * @param {Roo.bootstrap.ComboBox} combo This combo box
14937 * @param {String} query The query
14938 * @param {Boolean} forceAll true to force "all" query
14939 * @param {Boolean} cancel true to cancel the query
14940 * @param {Object} e The query event object
14942 'beforequery': true,
14945 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14946 * @param {Roo.bootstrap.ComboBox} combo This combo box
14951 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14952 * @param {Roo.bootstrap.ComboBox} combo This combo box
14953 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14958 * Fires when the remove value from the combobox array
14959 * @param {Roo.bootstrap.ComboBox} combo This combo box
14963 * @event afterremove
14964 * Fires when the remove value from the combobox array
14965 * @param {Roo.bootstrap.ComboBox} combo This combo box
14967 'afterremove' : true,
14969 * @event specialfilter
14970 * Fires when specialfilter
14971 * @param {Roo.bootstrap.ComboBox} combo This combo box
14973 'specialfilter' : true,
14976 * Fires when tick the element
14977 * @param {Roo.bootstrap.ComboBox} combo This combo box
14981 * @event touchviewdisplay
14982 * Fires when touch view require special display (default is using displayField)
14983 * @param {Roo.bootstrap.ComboBox} combo This combo box
14984 * @param {Object} cfg set html .
14986 'touchviewdisplay' : true
14991 this.tickItems = [];
14993 this.selectedIndex = -1;
14994 if(this.mode == 'local'){
14995 if(config.queryDelay === undefined){
14996 this.queryDelay = 10;
14998 if(config.minChars === undefined){
15004 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
15007 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
15008 * rendering into an Roo.Editor, defaults to false)
15011 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
15012 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
15015 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
15018 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
15019 * the dropdown list (defaults to undefined, with no header element)
15023 * @cfg {String/Roo.Template} tpl The template to use to render the output default is '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>'
15027 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
15029 listWidth: undefined,
15031 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
15032 * mode = 'remote' or 'text' if mode = 'local')
15034 displayField: undefined,
15037 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
15038 * mode = 'remote' or 'value' if mode = 'local').
15039 * Note: use of a valueField requires the user make a selection
15040 * in order for a value to be mapped.
15042 valueField: undefined,
15044 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
15049 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
15050 * field's data value (defaults to the underlying DOM element's name)
15052 hiddenName: undefined,
15054 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
15058 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
15060 selectedClass: 'active',
15063 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
15067 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
15068 * anchor positions (defaults to 'tl-bl')
15070 listAlign: 'tl-bl?',
15072 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
15076 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
15077 * query specified by the allQuery config option (defaults to 'query')
15079 triggerAction: 'query',
15081 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
15082 * (defaults to 4, does not apply if editable = false)
15086 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
15087 * delay (typeAheadDelay) if it matches a known value (defaults to false)
15091 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
15092 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
15096 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
15097 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
15101 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
15102 * when editable = true (defaults to false)
15104 selectOnFocus:false,
15106 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
15108 queryParam: 'query',
15110 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
15111 * when mode = 'remote' (defaults to 'Loading...')
15113 loadingText: 'Loading...',
15115 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
15119 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
15123 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
15124 * traditional select (defaults to true)
15128 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
15132 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
15136 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
15137 * listWidth has a higher value)
15141 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
15142 * allow the user to set arbitrary text into the field (defaults to false)
15144 forceSelection:false,
15146 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
15147 * if typeAhead = true (defaults to 250)
15149 typeAheadDelay : 250,
15151 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
15152 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
15154 valueNotFoundText : undefined,
15156 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
15158 blockFocus : false,
15161 * @cfg {Boolean} disableClear Disable showing of clear button.
15163 disableClear : false,
15165 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
15167 alwaysQuery : false,
15170 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
15175 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
15177 invalidClass : "has-warning",
15180 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
15182 validClass : "has-success",
15185 * @cfg {Boolean} specialFilter (true|false) special filter default false
15187 specialFilter : false,
15190 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
15192 mobileTouchView : true,
15195 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
15197 useNativeIOS : false,
15200 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
15202 mobile_restrict_height : false,
15204 ios_options : false,
15216 btnPosition : 'right',
15217 triggerList : true,
15218 showToggleBtn : true,
15220 emptyResultText: 'Empty',
15221 triggerText : 'Select',
15225 // element that contains real text value.. (when hidden is used..)
15227 getAutoCreate : function()
15232 * Render classic select for iso
15235 if(Roo.isIOS && this.useNativeIOS){
15236 cfg = this.getAutoCreateNativeIOS();
15244 if(Roo.isTouch && this.mobileTouchView){
15245 cfg = this.getAutoCreateTouchView();
15252 if(!this.tickable){
15253 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
15258 * ComboBox with tickable selections
15261 var align = this.labelAlign || this.parentLabelAlign();
15264 cls : 'form-group roo-combobox-tickable' //input-group
15267 var btn_text_select = '';
15268 var btn_text_done = '';
15269 var btn_text_cancel = '';
15271 if (this.btn_text_show) {
15272 btn_text_select = 'Select';
15273 btn_text_done = 'Done';
15274 btn_text_cancel = 'Cancel';
15279 cls : 'tickable-buttons',
15284 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
15285 //html : this.triggerText
15286 html: btn_text_select
15292 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
15294 html: btn_text_done
15300 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
15302 html: btn_text_cancel
15308 buttons.cn.unshift({
15310 cls: 'roo-select2-search-field-input'
15316 Roo.each(buttons.cn, function(c){
15318 c.cls += ' btn-' + _this.size;
15321 if (_this.disabled) {
15328 style : 'display: contents',
15333 cls: 'form-hidden-field'
15337 cls: 'roo-select2-choices',
15341 cls: 'roo-select2-search-field',
15352 cls: 'roo-select2-container input-group roo-select2-container-multi',
15358 // cls: 'typeahead typeahead-long dropdown-menu',
15359 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
15364 if(this.hasFeedback && !this.allowBlank){
15368 cls: 'glyphicon form-control-feedback'
15371 combobox.cn.push(feedback);
15378 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
15379 tooltip : 'This field is required'
15381 if (Roo.bootstrap.version == 4) {
15384 style : 'display:none'
15387 if (align ==='left' && this.fieldLabel.length) {
15389 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
15396 cls : 'control-label col-form-label',
15397 html : this.fieldLabel
15409 var labelCfg = cfg.cn[1];
15410 var contentCfg = cfg.cn[2];
15413 if(this.indicatorpos == 'right'){
15419 cls : 'control-label col-form-label',
15423 html : this.fieldLabel
15439 labelCfg = cfg.cn[0];
15440 contentCfg = cfg.cn[1];
15444 if(this.labelWidth > 12){
15445 labelCfg.style = "width: " + this.labelWidth + 'px';
15447 if(this.width * 1 > 0){
15448 contentCfg.style = "width: " + this.width + 'px';
15450 if(this.labelWidth < 13 && this.labelmd == 0){
15451 this.labelmd = this.labelWidth;
15454 if(this.labellg > 0){
15455 labelCfg.cls += ' col-lg-' + this.labellg;
15456 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15459 if(this.labelmd > 0){
15460 labelCfg.cls += ' col-md-' + this.labelmd;
15461 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15464 if(this.labelsm > 0){
15465 labelCfg.cls += ' col-sm-' + this.labelsm;
15466 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15469 if(this.labelxs > 0){
15470 labelCfg.cls += ' col-xs-' + this.labelxs;
15471 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15475 } else if ( this.fieldLabel.length) {
15476 // Roo.log(" label");
15481 //cls : 'input-group-addon',
15482 html : this.fieldLabel
15487 if(this.indicatorpos == 'right'){
15491 //cls : 'input-group-addon',
15492 html : this.fieldLabel
15502 // Roo.log(" no label && no align");
15509 ['xs','sm','md','lg'].map(function(size){
15510 if (settings[size]) {
15511 cfg.cls += ' col-' + size + '-' + settings[size];
15519 _initEventsCalled : false,
15522 initEvents: function()
15524 if (this._initEventsCalled) { // as we call render... prevent looping...
15527 this._initEventsCalled = true;
15530 throw "can not find store for combo";
15533 this.indicator = this.indicatorEl();
15535 this.store = Roo.factory(this.store, Roo.data);
15536 this.store.parent = this;
15538 // if we are building from html. then this element is so complex, that we can not really
15539 // use the rendered HTML.
15540 // so we have to trash and replace the previous code.
15541 if (Roo.XComponent.build_from_html) {
15542 // remove this element....
15543 var e = this.el.dom, k=0;
15544 while (e ) { e = e.previousSibling; ++k;}
15549 this.rendered = false;
15551 this.render(this.parent().getChildContainer(true), k);
15554 if(Roo.isIOS && this.useNativeIOS){
15555 this.initIOSView();
15563 if(Roo.isTouch && this.mobileTouchView){
15564 this.initTouchView();
15569 this.initTickableEvents();
15573 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
15575 if(this.hiddenName){
15577 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15579 this.hiddenField.dom.value =
15580 this.hiddenValue !== undefined ? this.hiddenValue :
15581 this.value !== undefined ? this.value : '';
15583 // prevent input submission
15584 this.el.dom.removeAttribute('name');
15585 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15590 // this.el.dom.setAttribute('autocomplete', 'off');
15593 var cls = 'x-combo-list';
15595 //this.list = new Roo.Layer({
15596 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
15602 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15603 _this.list.setWidth(lw);
15606 this.list.on('mouseover', this.onViewOver, this);
15607 this.list.on('mousemove', this.onViewMove, this);
15608 this.list.on('scroll', this.onViewScroll, this);
15611 this.list.swallowEvent('mousewheel');
15612 this.assetHeight = 0;
15615 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
15616 this.assetHeight += this.header.getHeight();
15619 this.innerList = this.list.createChild({cls:cls+'-inner'});
15620 this.innerList.on('mouseover', this.onViewOver, this);
15621 this.innerList.on('mousemove', this.onViewMove, this);
15622 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15624 if(this.allowBlank && !this.pageSize && !this.disableClear){
15625 this.footer = this.list.createChild({cls:cls+'-ft'});
15626 this.pageTb = new Roo.Toolbar(this.footer);
15630 this.footer = this.list.createChild({cls:cls+'-ft'});
15631 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
15632 {pageSize: this.pageSize});
15636 if (this.pageTb && this.allowBlank && !this.disableClear) {
15638 this.pageTb.add(new Roo.Toolbar.Fill(), {
15639 cls: 'x-btn-icon x-btn-clear',
15641 handler: function()
15644 _this.clearValue();
15645 _this.onSelect(false, -1);
15650 this.assetHeight += this.footer.getHeight();
15655 this.tpl = Roo.bootstrap.version == 4 ?
15656 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
15657 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
15660 this.view = new Roo.View(this.list, this.tpl, {
15661 singleSelect:true, store: this.store, selectedClass: this.selectedClass
15663 //this.view.wrapEl.setDisplayed(false);
15664 this.view.on('click', this.onViewClick, this);
15667 this.store.on('beforeload', this.onBeforeLoad, this);
15668 this.store.on('load', this.onLoad, this);
15669 this.store.on('loadexception', this.onLoadException, this);
15671 if(this.resizable){
15672 this.resizer = new Roo.Resizable(this.list, {
15673 pinned:true, handles:'se'
15675 this.resizer.on('resize', function(r, w, h){
15676 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
15677 this.listWidth = w;
15678 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
15679 this.restrictHeight();
15681 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
15684 if(!this.editable){
15685 this.editable = true;
15686 this.setEditable(false);
15691 if (typeof(this.events.add.listeners) != 'undefined') {
15693 this.addicon = this.wrap.createChild(
15694 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
15696 this.addicon.on('click', function(e) {
15697 this.fireEvent('add', this);
15700 if (typeof(this.events.edit.listeners) != 'undefined') {
15702 this.editicon = this.wrap.createChild(
15703 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
15704 if (this.addicon) {
15705 this.editicon.setStyle('margin-left', '40px');
15707 this.editicon.on('click', function(e) {
15709 // we fire even if inothing is selected..
15710 this.fireEvent('edit', this, this.lastData );
15716 this.keyNav = new Roo.KeyNav(this.inputEl(), {
15717 "up" : function(e){
15718 this.inKeyMode = true;
15722 "down" : function(e){
15723 if(!this.isExpanded()){
15724 this.onTriggerClick();
15726 this.inKeyMode = true;
15731 "enter" : function(e){
15732 // this.onViewClick();
15736 if(this.fireEvent("specialkey", this, e)){
15737 this.onViewClick(false);
15743 "esc" : function(e){
15747 "tab" : function(e){
15750 if(this.fireEvent("specialkey", this, e)){
15751 this.onViewClick(false);
15759 doRelay : function(foo, bar, hname){
15760 if(hname == 'down' || this.scope.isExpanded()){
15761 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15770 this.queryDelay = Math.max(this.queryDelay || 10,
15771 this.mode == 'local' ? 10 : 250);
15774 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15776 if(this.typeAhead){
15777 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15779 if(this.editable !== false){
15780 this.inputEl().on("keyup", this.onKeyUp, this);
15782 if(this.forceSelection){
15783 this.inputEl().on('blur', this.doForce, this);
15787 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15788 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15792 initTickableEvents: function()
15796 if(this.hiddenName){
15798 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15800 this.hiddenField.dom.value =
15801 this.hiddenValue !== undefined ? this.hiddenValue :
15802 this.value !== undefined ? this.value : '';
15804 // prevent input submission
15805 this.el.dom.removeAttribute('name');
15806 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15811 // this.list = this.el.select('ul.dropdown-menu',true).first();
15813 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15814 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15815 if(this.triggerList){
15816 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15819 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15820 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15822 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15823 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15825 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15826 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15828 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15829 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15830 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15833 this.cancelBtn.hide();
15838 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15839 _this.list.setWidth(lw);
15842 this.list.on('mouseover', this.onViewOver, this);
15843 this.list.on('mousemove', this.onViewMove, this);
15845 this.list.on('scroll', this.onViewScroll, this);
15848 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15849 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15852 this.view = new Roo.View(this.list, this.tpl, {
15857 selectedClass: this.selectedClass
15860 //this.view.wrapEl.setDisplayed(false);
15861 this.view.on('click', this.onViewClick, this);
15865 this.store.on('beforeload', this.onBeforeLoad, this);
15866 this.store.on('load', this.onLoad, this);
15867 this.store.on('loadexception', this.onLoadException, this);
15870 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15871 "up" : function(e){
15872 this.inKeyMode = true;
15876 "down" : function(e){
15877 this.inKeyMode = true;
15881 "enter" : function(e){
15882 if(this.fireEvent("specialkey", this, e)){
15883 this.onViewClick(false);
15889 "esc" : function(e){
15890 this.onTickableFooterButtonClick(e, false, false);
15893 "tab" : function(e){
15894 this.fireEvent("specialkey", this, e);
15896 this.onTickableFooterButtonClick(e, false, false);
15903 doRelay : function(e, fn, key){
15904 if(this.scope.isExpanded()){
15905 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15914 this.queryDelay = Math.max(this.queryDelay || 10,
15915 this.mode == 'local' ? 10 : 250);
15918 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15920 if(this.typeAhead){
15921 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15924 if(this.editable !== false){
15925 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15928 this.indicator = this.indicatorEl();
15930 if(this.indicator){
15931 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15932 this.indicator.hide();
15937 onDestroy : function(){
15939 this.view.setStore(null);
15940 this.view.el.removeAllListeners();
15941 this.view.el.remove();
15942 this.view.purgeListeners();
15945 this.list.dom.innerHTML = '';
15949 this.store.un('beforeload', this.onBeforeLoad, this);
15950 this.store.un('load', this.onLoad, this);
15951 this.store.un('loadexception', this.onLoadException, this);
15953 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15957 fireKey : function(e){
15958 if(e.isNavKeyPress() && !this.list.isVisible()){
15959 this.fireEvent("specialkey", this, e);
15964 onResize: function(w, h)
15968 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15970 // if(typeof w != 'number'){
15971 // // we do not handle it!?!?
15974 // var tw = this.trigger.getWidth();
15975 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15976 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15978 // this.inputEl().setWidth( this.adjustWidth('input', x));
15980 // //this.trigger.setStyle('left', x+'px');
15982 // if(this.list && this.listWidth === undefined){
15983 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15984 // this.list.setWidth(lw);
15985 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15993 * Allow or prevent the user from directly editing the field text. If false is passed,
15994 * the user will only be able to select from the items defined in the dropdown list. This method
15995 * is the runtime equivalent of setting the 'editable' config option at config time.
15996 * @param {Boolean} value True to allow the user to directly edit the field text
15998 setEditable : function(value){
15999 if(value == this.editable){
16002 this.editable = value;
16004 this.inputEl().dom.setAttribute('readOnly', true);
16005 this.inputEl().on('mousedown', this.onTriggerClick, this);
16006 this.inputEl().addClass('x-combo-noedit');
16008 this.inputEl().dom.setAttribute('readOnly', false);
16009 this.inputEl().un('mousedown', this.onTriggerClick, this);
16010 this.inputEl().removeClass('x-combo-noedit');
16016 onBeforeLoad : function(combo,opts){
16017 if(!this.hasFocus){
16021 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
16023 this.restrictHeight();
16024 this.selectedIndex = -1;
16028 onLoad : function(){
16030 this.hasQuery = false;
16032 if(!this.hasFocus){
16036 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
16037 this.loading.hide();
16040 if(this.store.getCount() > 0){
16043 this.restrictHeight();
16044 if(this.lastQuery == this.allQuery){
16045 if(this.editable && !this.tickable){
16046 this.inputEl().dom.select();
16050 !this.selectByValue(this.value, true) &&
16053 !this.store.lastOptions ||
16054 typeof(this.store.lastOptions.add) == 'undefined' ||
16055 this.store.lastOptions.add != true
16058 this.select(0, true);
16061 if(this.autoFocus){
16064 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
16065 this.taTask.delay(this.typeAheadDelay);
16069 this.onEmptyResults();
16075 onLoadException : function()
16077 this.hasQuery = false;
16079 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
16080 this.loading.hide();
16083 if(this.tickable && this.editable){
16088 // only causes errors at present
16089 //Roo.log(this.store.reader.jsonData);
16090 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
16092 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
16098 onTypeAhead : function(){
16099 if(this.store.getCount() > 0){
16100 var r = this.store.getAt(0);
16101 var newValue = r.data[this.displayField];
16102 var len = newValue.length;
16103 var selStart = this.getRawValue().length;
16105 if(selStart != len){
16106 this.setRawValue(newValue);
16107 this.selectText(selStart, newValue.length);
16113 onSelect : function(record, index){
16115 if(this.fireEvent('beforeselect', this, record, index) !== false){
16117 this.setFromData(index > -1 ? record.data : false);
16120 this.fireEvent('select', this, record, index);
16125 * Returns the currently selected field value or empty string if no value is set.
16126 * @return {String} value The selected value
16128 getValue : function()
16130 if(Roo.isIOS && this.useNativeIOS){
16131 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
16135 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
16138 if(this.valueField){
16139 return typeof this.value != 'undefined' ? this.value : '';
16141 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
16145 getRawValue : function()
16147 if(Roo.isIOS && this.useNativeIOS){
16148 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
16151 var v = this.inputEl().getValue();
16157 * Clears any text/value currently set in the field
16159 clearValue : function(){
16161 if(this.hiddenField){
16162 this.hiddenField.dom.value = '';
16165 this.setRawValue('');
16166 this.lastSelectionText = '';
16167 this.lastData = false;
16169 var close = this.closeTriggerEl();
16180 * Sets the specified value into the field. If the value finds a match, the corresponding record text
16181 * will be displayed in the field. If the value does not match the data value of an existing item,
16182 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
16183 * Otherwise the field will be blank (although the value will still be set).
16184 * @param {String} value The value to match
16186 setValue : function(v)
16188 if(Roo.isIOS && this.useNativeIOS){
16189 this.setIOSValue(v);
16199 if(this.valueField){
16200 var r = this.findRecord(this.valueField, v);
16202 text = r.data[this.displayField];
16203 }else if(this.valueNotFoundText !== undefined){
16204 text = this.valueNotFoundText;
16207 this.lastSelectionText = text;
16208 if(this.hiddenField){
16209 this.hiddenField.dom.value = v;
16211 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
16214 var close = this.closeTriggerEl();
16217 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
16223 * @property {Object} the last set data for the element
16228 * Sets the value of the field based on a object which is related to the record format for the store.
16229 * @param {Object} value the value to set as. or false on reset?
16231 setFromData : function(o){
16238 var dv = ''; // display value
16239 var vv = ''; // value value..
16241 if (this.displayField) {
16242 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16244 // this is an error condition!!!
16245 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16248 if(this.valueField){
16249 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
16252 var close = this.closeTriggerEl();
16255 if(dv.length || vv * 1 > 0){
16257 this.blockFocus=true;
16263 if(this.hiddenField){
16264 this.hiddenField.dom.value = vv;
16266 this.lastSelectionText = dv;
16267 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16271 // no hidden field.. - we store the value in 'value', but still display
16272 // display field!!!!
16273 this.lastSelectionText = dv;
16274 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16281 reset : function(){
16282 // overridden so that last data is reset..
16289 this.setValue(this.originalValue);
16290 //this.clearInvalid();
16291 this.lastData = false;
16293 this.view.clearSelections();
16299 findRecord : function(prop, value){
16301 if(this.store.getCount() > 0){
16302 this.store.each(function(r){
16303 if(r.data[prop] == value){
16313 getName: function()
16315 // returns hidden if it's set..
16316 if (!this.rendered) {return ''};
16317 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
16321 onViewMove : function(e, t){
16322 this.inKeyMode = false;
16326 onViewOver : function(e, t){
16327 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
16330 var item = this.view.findItemFromChild(t);
16333 var index = this.view.indexOf(item);
16334 this.select(index, false);
16339 onViewClick : function(view, doFocus, el, e)
16341 var index = this.view.getSelectedIndexes()[0];
16343 var r = this.store.getAt(index);
16347 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
16354 Roo.each(this.tickItems, function(v,k){
16356 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
16358 _this.tickItems.splice(k, 1);
16360 if(typeof(e) == 'undefined' && view == false){
16361 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
16373 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
16374 this.tickItems.push(r.data);
16377 if(typeof(e) == 'undefined' && view == false){
16378 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
16385 this.onSelect(r, index);
16387 if(doFocus !== false && !this.blockFocus){
16388 this.inputEl().focus();
16393 restrictHeight : function(){
16394 //this.innerList.dom.style.height = '';
16395 //var inner = this.innerList.dom;
16396 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
16397 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
16398 //this.list.beginUpdate();
16399 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
16400 this.list.alignTo(this.inputEl(), this.listAlign);
16401 this.list.alignTo(this.inputEl(), this.listAlign);
16402 //this.list.endUpdate();
16406 onEmptyResults : function(){
16408 if(this.tickable && this.editable){
16409 this.hasFocus = false;
16410 this.restrictHeight();
16418 * Returns true if the dropdown list is expanded, else false.
16420 isExpanded : function(){
16421 return this.list.isVisible();
16425 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
16426 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16427 * @param {String} value The data value of the item to select
16428 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16429 * selected item if it is not currently in view (defaults to true)
16430 * @return {Boolean} True if the value matched an item in the list, else false
16432 selectByValue : function(v, scrollIntoView){
16433 if(v !== undefined && v !== null){
16434 var r = this.findRecord(this.valueField || this.displayField, v);
16436 this.select(this.store.indexOf(r), scrollIntoView);
16444 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
16445 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16446 * @param {Number} index The zero-based index of the list item to select
16447 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16448 * selected item if it is not currently in view (defaults to true)
16450 select : function(index, scrollIntoView){
16451 this.selectedIndex = index;
16452 this.view.select(index);
16453 if(scrollIntoView !== false){
16454 var el = this.view.getNode(index);
16456 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
16459 this.list.scrollChildIntoView(el, false);
16465 selectNext : function(){
16466 var ct = this.store.getCount();
16468 if(this.selectedIndex == -1){
16470 }else if(this.selectedIndex < ct-1){
16471 this.select(this.selectedIndex+1);
16477 selectPrev : function(){
16478 var ct = this.store.getCount();
16480 if(this.selectedIndex == -1){
16482 }else if(this.selectedIndex != 0){
16483 this.select(this.selectedIndex-1);
16489 onKeyUp : function(e){
16490 if(this.editable !== false && !e.isSpecialKey()){
16491 this.lastKey = e.getKey();
16492 this.dqTask.delay(this.queryDelay);
16497 validateBlur : function(){
16498 return !this.list || !this.list.isVisible();
16502 initQuery : function(){
16504 var v = this.getRawValue();
16506 if(this.tickable && this.editable){
16507 v = this.tickableInputEl().getValue();
16514 doForce : function(){
16515 if(this.inputEl().dom.value.length > 0){
16516 this.inputEl().dom.value =
16517 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
16523 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
16524 * query allowing the query action to be canceled if needed.
16525 * @param {String} query The SQL query to execute
16526 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
16527 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
16528 * saved in the current store (defaults to false)
16530 doQuery : function(q, forceAll){
16532 if(q === undefined || q === null){
16537 forceAll: forceAll,
16541 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
16546 forceAll = qe.forceAll;
16547 if(forceAll === true || (q.length >= this.minChars)){
16549 this.hasQuery = true;
16551 if(this.lastQuery != q || this.alwaysQuery){
16552 this.lastQuery = q;
16553 if(this.mode == 'local'){
16554 this.selectedIndex = -1;
16556 this.store.clearFilter();
16559 if(this.specialFilter){
16560 this.fireEvent('specialfilter', this);
16565 this.store.filter(this.displayField, q);
16568 this.store.fireEvent("datachanged", this.store);
16575 this.store.baseParams[this.queryParam] = q;
16577 var options = {params : this.getParams(q)};
16580 options.add = true;
16581 options.params.start = this.page * this.pageSize;
16584 this.store.load(options);
16587 * this code will make the page width larger, at the beginning, the list not align correctly,
16588 * we should expand the list on onLoad
16589 * so command out it
16594 this.selectedIndex = -1;
16599 this.loadNext = false;
16603 getParams : function(q){
16605 //p[this.queryParam] = q;
16609 p.limit = this.pageSize;
16615 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
16617 collapse : function(){
16618 if(!this.isExpanded()){
16624 this.hasFocus = false;
16628 this.cancelBtn.hide();
16629 this.trigger.show();
16632 this.tickableInputEl().dom.value = '';
16633 this.tickableInputEl().blur();
16638 Roo.get(document).un('mousedown', this.collapseIf, this);
16639 Roo.get(document).un('mousewheel', this.collapseIf, this);
16640 if (!this.editable) {
16641 Roo.get(document).un('keydown', this.listKeyPress, this);
16643 this.fireEvent('collapse', this);
16649 collapseIf : function(e){
16650 var in_combo = e.within(this.el);
16651 var in_list = e.within(this.list);
16652 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
16654 if (in_combo || in_list || is_list) {
16655 //e.stopPropagation();
16660 this.onTickableFooterButtonClick(e, false, false);
16668 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
16670 expand : function(){
16672 if(this.isExpanded() || !this.hasFocus){
16676 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
16677 this.list.setWidth(lw);
16683 this.restrictHeight();
16687 this.tickItems = Roo.apply([], this.item);
16690 this.cancelBtn.show();
16691 this.trigger.hide();
16694 this.tickableInputEl().focus();
16699 Roo.get(document).on('mousedown', this.collapseIf, this);
16700 Roo.get(document).on('mousewheel', this.collapseIf, this);
16701 if (!this.editable) {
16702 Roo.get(document).on('keydown', this.listKeyPress, this);
16705 this.fireEvent('expand', this);
16709 // Implements the default empty TriggerField.onTriggerClick function
16710 onTriggerClick : function(e)
16712 Roo.log('trigger click');
16714 if(this.disabled || !this.triggerList){
16719 this.loadNext = false;
16721 if(this.isExpanded()){
16723 if (!this.blockFocus) {
16724 this.inputEl().focus();
16728 this.hasFocus = true;
16729 if(this.triggerAction == 'all') {
16730 this.doQuery(this.allQuery, true);
16732 this.doQuery(this.getRawValue());
16734 if (!this.blockFocus) {
16735 this.inputEl().focus();
16740 onTickableTriggerClick : function(e)
16747 this.loadNext = false;
16748 this.hasFocus = true;
16750 if(this.triggerAction == 'all') {
16751 this.doQuery(this.allQuery, true);
16753 this.doQuery(this.getRawValue());
16757 onSearchFieldClick : function(e)
16759 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
16760 this.onTickableFooterButtonClick(e, false, false);
16764 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
16769 this.loadNext = false;
16770 this.hasFocus = true;
16772 if(this.triggerAction == 'all') {
16773 this.doQuery(this.allQuery, true);
16775 this.doQuery(this.getRawValue());
16779 listKeyPress : function(e)
16781 //Roo.log('listkeypress');
16782 // scroll to first matching element based on key pres..
16783 if (e.isSpecialKey()) {
16786 var k = String.fromCharCode(e.getKey()).toUpperCase();
16789 var csel = this.view.getSelectedNodes();
16790 var cselitem = false;
16792 var ix = this.view.indexOf(csel[0]);
16793 cselitem = this.store.getAt(ix);
16794 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16800 this.store.each(function(v) {
16802 // start at existing selection.
16803 if (cselitem.id == v.id) {
16809 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16810 match = this.store.indexOf(v);
16816 if (match === false) {
16817 return true; // no more action?
16820 this.view.select(match);
16821 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16822 sn.scrollIntoView(sn.dom.parentNode, false);
16825 onViewScroll : function(e, t){
16827 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){
16831 this.hasQuery = true;
16833 this.loading = this.list.select('.loading', true).first();
16835 if(this.loading === null){
16836 this.list.createChild({
16838 cls: 'loading roo-select2-more-results roo-select2-active',
16839 html: 'Loading more results...'
16842 this.loading = this.list.select('.loading', true).first();
16844 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16846 this.loading.hide();
16849 this.loading.show();
16854 this.loadNext = true;
16856 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16861 addItem : function(o)
16863 var dv = ''; // display value
16865 if (this.displayField) {
16866 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16868 // this is an error condition!!!
16869 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16876 var choice = this.choices.createChild({
16878 cls: 'roo-select2-search-choice',
16887 cls: 'roo-select2-search-choice-close fa fa-times',
16892 }, this.searchField);
16894 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16896 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16904 this.inputEl().dom.value = '';
16909 onRemoveItem : function(e, _self, o)
16911 e.preventDefault();
16913 this.lastItem = Roo.apply([], this.item);
16915 var index = this.item.indexOf(o.data) * 1;
16918 Roo.log('not this item?!');
16922 this.item.splice(index, 1);
16927 this.fireEvent('remove', this, e);
16933 syncValue : function()
16935 if(!this.item.length){
16942 Roo.each(this.item, function(i){
16943 if(_this.valueField){
16944 value.push(i[_this.valueField]);
16951 this.value = value.join(',');
16953 if(this.hiddenField){
16954 this.hiddenField.dom.value = this.value;
16957 this.store.fireEvent("datachanged", this.store);
16962 clearItem : function()
16964 if(!this.multiple){
16970 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16978 if(this.tickable && !Roo.isTouch){
16979 this.view.refresh();
16983 inputEl: function ()
16985 if(Roo.isIOS && this.useNativeIOS){
16986 return this.el.select('select.roo-ios-select', true).first();
16989 if(Roo.isTouch && this.mobileTouchView){
16990 return this.el.select('input.form-control',true).first();
16994 return this.searchField;
16997 return this.el.select('input.form-control',true).first();
17000 onTickableFooterButtonClick : function(e, btn, el)
17002 e.preventDefault();
17004 this.lastItem = Roo.apply([], this.item);
17006 if(btn && btn.name == 'cancel'){
17007 this.tickItems = Roo.apply([], this.item);
17016 Roo.each(this.tickItems, function(o){
17024 validate : function()
17026 if(this.getVisibilityEl().hasClass('hidden')){
17030 var v = this.getRawValue();
17033 v = this.getValue();
17036 if(this.disabled || this.allowBlank || v.length){
17041 this.markInvalid();
17045 tickableInputEl : function()
17047 if(!this.tickable || !this.editable){
17048 return this.inputEl();
17051 return this.inputEl().select('.roo-select2-search-field-input', true).first();
17055 getAutoCreateTouchView : function()
17060 cls: 'form-group' //input-group
17066 type : this.inputType,
17067 cls : 'form-control x-combo-noedit',
17068 autocomplete: 'new-password',
17069 placeholder : this.placeholder || '',
17074 input.name = this.name;
17078 input.cls += ' input-' + this.size;
17081 if (this.disabled) {
17082 input.disabled = true;
17086 cls : 'roo-combobox-wrap',
17093 inputblock.cls += ' input-group';
17095 inputblock.cn.unshift({
17097 cls : 'input-group-addon input-group-prepend input-group-text',
17102 if(this.removable && !this.multiple){
17103 inputblock.cls += ' roo-removable';
17105 inputblock.cn.push({
17108 cls : 'roo-combo-removable-btn close'
17112 if(this.hasFeedback && !this.allowBlank){
17114 inputblock.cls += ' has-feedback';
17116 inputblock.cn.push({
17118 cls: 'glyphicon form-control-feedback'
17125 inputblock.cls += (this.before) ? '' : ' input-group';
17127 inputblock.cn.push({
17129 cls : 'input-group-addon input-group-append input-group-text',
17135 var ibwrap = inputblock;
17140 cls: 'roo-select2-choices',
17144 cls: 'roo-select2-search-field',
17157 cls: 'roo-select2-container input-group roo-touchview-combobox ',
17162 cls: 'form-hidden-field'
17168 if(!this.multiple && this.showToggleBtn){
17174 if (this.caret != false) {
17177 cls: 'fa fa-' + this.caret
17184 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
17186 Roo.bootstrap.version == 3 ? caret : '',
17189 cls: 'combobox-clear',
17203 combobox.cls += ' roo-select2-container-multi';
17206 var align = this.labelAlign || this.parentLabelAlign();
17208 if (align ==='left' && this.fieldLabel.length) {
17213 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17214 tooltip : 'This field is required'
17218 cls : 'control-label col-form-label',
17219 html : this.fieldLabel
17223 cls : 'roo-combobox-wrap ',
17230 var labelCfg = cfg.cn[1];
17231 var contentCfg = cfg.cn[2];
17234 if(this.indicatorpos == 'right'){
17239 cls : 'control-label col-form-label',
17243 html : this.fieldLabel
17247 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17248 tooltip : 'This field is required'
17253 cls : "roo-combobox-wrap ",
17261 labelCfg = cfg.cn[0];
17262 contentCfg = cfg.cn[1];
17267 if(this.labelWidth > 12){
17268 labelCfg.style = "width: " + this.labelWidth + 'px';
17271 if(this.labelWidth < 13 && this.labelmd == 0){
17272 this.labelmd = this.labelWidth;
17275 if(this.labellg > 0){
17276 labelCfg.cls += ' col-lg-' + this.labellg;
17277 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
17280 if(this.labelmd > 0){
17281 labelCfg.cls += ' col-md-' + this.labelmd;
17282 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
17285 if(this.labelsm > 0){
17286 labelCfg.cls += ' col-sm-' + this.labelsm;
17287 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
17290 if(this.labelxs > 0){
17291 labelCfg.cls += ' col-xs-' + this.labelxs;
17292 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
17296 } else if ( this.fieldLabel.length) {
17300 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17301 tooltip : 'This field is required'
17305 cls : 'control-label',
17306 html : this.fieldLabel
17317 if(this.indicatorpos == 'right'){
17321 cls : 'control-label',
17322 html : this.fieldLabel,
17326 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17327 tooltip : 'This field is required'
17344 var settings = this;
17346 ['xs','sm','md','lg'].map(function(size){
17347 if (settings[size]) {
17348 cfg.cls += ' col-' + size + '-' + settings[size];
17355 initTouchView : function()
17357 this.renderTouchView();
17359 this.touchViewEl.on('scroll', function(){
17360 this.el.dom.scrollTop = 0;
17363 this.originalValue = this.getValue();
17365 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
17367 this.inputEl().on("click", this.showTouchView, this);
17368 if (this.triggerEl) {
17369 this.triggerEl.on("click", this.showTouchView, this);
17373 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
17374 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
17376 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
17378 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
17379 this.store.on('load', this.onTouchViewLoad, this);
17380 this.store.on('loadexception', this.onTouchViewLoadException, this);
17382 if(this.hiddenName){
17384 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
17386 this.hiddenField.dom.value =
17387 this.hiddenValue !== undefined ? this.hiddenValue :
17388 this.value !== undefined ? this.value : '';
17390 this.el.dom.removeAttribute('name');
17391 this.hiddenField.dom.setAttribute('name', this.hiddenName);
17395 this.choices = this.el.select('ul.roo-select2-choices', true).first();
17396 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
17399 if(this.removable && !this.multiple){
17400 var close = this.closeTriggerEl();
17402 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
17403 close.on('click', this.removeBtnClick, this, close);
17407 * fix the bug in Safari iOS8
17409 this.inputEl().on("focus", function(e){
17410 document.activeElement.blur();
17413 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
17420 renderTouchView : function()
17422 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
17423 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17425 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
17426 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17428 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
17429 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17430 this.touchViewBodyEl.setStyle('overflow', 'auto');
17432 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
17433 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17435 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
17436 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17440 showTouchView : function()
17446 this.touchViewHeaderEl.hide();
17448 if(this.modalTitle.length){
17449 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
17450 this.touchViewHeaderEl.show();
17453 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
17454 this.touchViewEl.show();
17456 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
17458 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
17459 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17461 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17463 if(this.modalTitle.length){
17464 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17467 this.touchViewBodyEl.setHeight(bodyHeight);
17471 (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
17473 this.touchViewEl.addClass(['in','show']);
17476 if(this._touchViewMask){
17477 Roo.get(document.body).addClass("x-body-masked");
17478 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17479 this._touchViewMask.setStyle('z-index', 10000);
17480 this._touchViewMask.addClass('show');
17483 this.doTouchViewQuery();
17487 hideTouchView : function()
17489 this.touchViewEl.removeClass(['in','show']);
17493 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
17495 this.touchViewEl.setStyle('display', 'none');
17498 if(this._touchViewMask){
17499 this._touchViewMask.removeClass('show');
17500 Roo.get(document.body).removeClass("x-body-masked");
17504 setTouchViewValue : function()
17511 Roo.each(this.tickItems, function(o){
17516 this.hideTouchView();
17519 doTouchViewQuery : function()
17528 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
17532 if(!this.alwaysQuery || this.mode == 'local'){
17533 this.onTouchViewLoad();
17540 onTouchViewBeforeLoad : function(combo,opts)
17546 onTouchViewLoad : function()
17548 if(this.store.getCount() < 1){
17549 this.onTouchViewEmptyResults();
17553 this.clearTouchView();
17555 var rawValue = this.getRawValue();
17557 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
17559 this.tickItems = [];
17561 this.store.data.each(function(d, rowIndex){
17562 var row = this.touchViewListGroup.createChild(template);
17564 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
17565 row.addClass(d.data.cls);
17568 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17571 html : d.data[this.displayField]
17574 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
17575 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
17578 row.removeClass('selected');
17579 if(!this.multiple && this.valueField &&
17580 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
17583 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17584 row.addClass('selected');
17587 if(this.multiple && this.valueField &&
17588 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
17592 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17593 this.tickItems.push(d.data);
17596 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
17600 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
17602 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17604 if(this.modalTitle.length){
17605 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17608 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
17610 if(this.mobile_restrict_height && listHeight < bodyHeight){
17611 this.touchViewBodyEl.setHeight(listHeight);
17616 if(firstChecked && listHeight > bodyHeight){
17617 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
17622 onTouchViewLoadException : function()
17624 this.hideTouchView();
17627 onTouchViewEmptyResults : function()
17629 this.clearTouchView();
17631 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
17633 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
17637 clearTouchView : function()
17639 this.touchViewListGroup.dom.innerHTML = '';
17642 onTouchViewClick : function(e, el, o)
17644 e.preventDefault();
17647 var rowIndex = o.rowIndex;
17649 var r = this.store.getAt(rowIndex);
17651 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
17653 if(!this.multiple){
17654 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
17655 c.dom.removeAttribute('checked');
17658 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17660 this.setFromData(r.data);
17662 var close = this.closeTriggerEl();
17668 this.hideTouchView();
17670 this.fireEvent('select', this, r, rowIndex);
17675 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
17676 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
17677 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
17681 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17682 this.addItem(r.data);
17683 this.tickItems.push(r.data);
17687 getAutoCreateNativeIOS : function()
17690 cls: 'form-group' //input-group,
17695 cls : 'roo-ios-select'
17699 combobox.name = this.name;
17702 if (this.disabled) {
17703 combobox.disabled = true;
17706 var settings = this;
17708 ['xs','sm','md','lg'].map(function(size){
17709 if (settings[size]) {
17710 cfg.cls += ' col-' + size + '-' + settings[size];
17720 initIOSView : function()
17722 this.store.on('load', this.onIOSViewLoad, this);
17727 onIOSViewLoad : function()
17729 if(this.store.getCount() < 1){
17733 this.clearIOSView();
17735 if(this.allowBlank) {
17737 var default_text = '-- SELECT --';
17739 if(this.placeholder.length){
17740 default_text = this.placeholder;
17743 if(this.emptyTitle.length){
17744 default_text += ' - ' + this.emptyTitle + ' -';
17747 var opt = this.inputEl().createChild({
17750 html : default_text
17754 o[this.valueField] = 0;
17755 o[this.displayField] = default_text;
17757 this.ios_options.push({
17764 this.store.data.each(function(d, rowIndex){
17768 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17769 html = d.data[this.displayField];
17774 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
17775 value = d.data[this.valueField];
17784 if(this.value == d.data[this.valueField]){
17785 option['selected'] = true;
17788 var opt = this.inputEl().createChild(option);
17790 this.ios_options.push({
17797 this.inputEl().on('change', function(){
17798 this.fireEvent('select', this);
17803 clearIOSView: function()
17805 this.inputEl().dom.innerHTML = '';
17807 this.ios_options = [];
17810 setIOSValue: function(v)
17814 if(!this.ios_options){
17818 Roo.each(this.ios_options, function(opts){
17820 opts.el.dom.removeAttribute('selected');
17822 if(opts.data[this.valueField] != v){
17826 opts.el.dom.setAttribute('selected', true);
17832 * @cfg {Boolean} grow
17836 * @cfg {Number} growMin
17840 * @cfg {Number} growMax
17849 Roo.apply(Roo.bootstrap.ComboBox, {
17853 cls: 'modal-header',
17875 cls: 'list-group-item',
17879 cls: 'roo-combobox-list-group-item-value'
17883 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17897 listItemCheckbox : {
17899 cls: 'list-group-item',
17903 cls: 'roo-combobox-list-group-item-value'
17907 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17923 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17928 cls: 'modal-footer',
17936 cls: 'col-xs-6 text-left',
17939 cls: 'btn btn-danger roo-touch-view-cancel',
17945 cls: 'col-xs-6 text-right',
17948 cls: 'btn btn-success roo-touch-view-ok',
17959 Roo.apply(Roo.bootstrap.ComboBox, {
17961 touchViewTemplate : {
17963 cls: 'modal fade roo-combobox-touch-view',
17967 cls: 'modal-dialog',
17968 style : 'position:fixed', // we have to fix position....
17972 cls: 'modal-content',
17974 Roo.bootstrap.ComboBox.header,
17975 Roo.bootstrap.ComboBox.body,
17976 Roo.bootstrap.ComboBox.footer
17985 * Ext JS Library 1.1.1
17986 * Copyright(c) 2006-2007, Ext JS, LLC.
17988 * Originally Released Under LGPL - original licence link has changed is not relivant.
17991 * <script type="text/javascript">
17996 * @extends Roo.util.Observable
17997 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
17998 * This class also supports single and multi selection modes. <br>
17999 * Create a data model bound view:
18001 var store = new Roo.data.Store(...);
18003 var view = new Roo.View({
18005 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
18007 singleSelect: true,
18008 selectedClass: "ydataview-selected",
18012 // listen for node click?
18013 view.on("click", function(vw, index, node, e){
18014 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
18018 dataModel.load("foobar.xml");
18020 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
18022 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
18023 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
18025 * Note: old style constructor is still suported (container, template, config)
18028 * Create a new View
18029 * @param {Object} config The config object
18032 Roo.View = function(config, depreciated_tpl, depreciated_config){
18034 this.parent = false;
18036 if (typeof(depreciated_tpl) == 'undefined') {
18037 // new way.. - universal constructor.
18038 Roo.apply(this, config);
18039 this.el = Roo.get(this.el);
18042 this.el = Roo.get(config);
18043 this.tpl = depreciated_tpl;
18044 Roo.apply(this, depreciated_config);
18046 this.wrapEl = this.el.wrap().wrap();
18047 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
18050 if(typeof(this.tpl) == "string"){
18051 this.tpl = new Roo.Template(this.tpl);
18053 // support xtype ctors..
18054 this.tpl = new Roo.factory(this.tpl, Roo);
18058 this.tpl.compile();
18063 * @event beforeclick
18064 * Fires before a click is processed. Returns false to cancel the default action.
18065 * @param {Roo.View} this
18066 * @param {Number} index The index of the target node
18067 * @param {HTMLElement} node The target node
18068 * @param {Roo.EventObject} e The raw event object
18070 "beforeclick" : true,
18073 * Fires when a template node is clicked.
18074 * @param {Roo.View} this
18075 * @param {Number} index The index of the target node
18076 * @param {HTMLElement} node The target node
18077 * @param {Roo.EventObject} e The raw event object
18082 * Fires when a template node is double clicked.
18083 * @param {Roo.View} this
18084 * @param {Number} index The index of the target node
18085 * @param {HTMLElement} node The target node
18086 * @param {Roo.EventObject} e The raw event object
18090 * @event contextmenu
18091 * Fires when a template node is right clicked.
18092 * @param {Roo.View} this
18093 * @param {Number} index The index of the target node
18094 * @param {HTMLElement} node The target node
18095 * @param {Roo.EventObject} e The raw event object
18097 "contextmenu" : true,
18099 * @event selectionchange
18100 * Fires when the selected nodes change.
18101 * @param {Roo.View} this
18102 * @param {Array} selections Array of the selected nodes
18104 "selectionchange" : true,
18107 * @event beforeselect
18108 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
18109 * @param {Roo.View} this
18110 * @param {HTMLElement} node The node to be selected
18111 * @param {Array} selections Array of currently selected nodes
18113 "beforeselect" : true,
18115 * @event preparedata
18116 * Fires on every row to render, to allow you to change the data.
18117 * @param {Roo.View} this
18118 * @param {Object} data to be rendered (change this)
18120 "preparedata" : true
18128 "click": this.onClick,
18129 "dblclick": this.onDblClick,
18130 "contextmenu": this.onContextMenu,
18134 this.selections = [];
18136 this.cmp = new Roo.CompositeElementLite([]);
18138 this.store = Roo.factory(this.store, Roo.data);
18139 this.setStore(this.store, true);
18142 if ( this.footer && this.footer.xtype) {
18144 var fctr = this.wrapEl.appendChild(document.createElement("div"));
18146 this.footer.dataSource = this.store;
18147 this.footer.container = fctr;
18148 this.footer = Roo.factory(this.footer, Roo);
18149 fctr.insertFirst(this.el);
18151 // this is a bit insane - as the paging toolbar seems to detach the el..
18152 // dom.parentNode.parentNode.parentNode
18153 // they get detached?
18157 Roo.View.superclass.constructor.call(this);
18162 Roo.extend(Roo.View, Roo.util.Observable, {
18165 * @cfg {Roo.data.Store} store Data store to load data from.
18170 * @cfg {String|Roo.Element} el The container element.
18175 * @cfg {String|Roo.Template} tpl The template used by this View
18179 * @cfg {String} dataName the named area of the template to use as the data area
18180 * Works with domtemplates roo-name="name"
18184 * @cfg {String} selectedClass The css class to add to selected nodes
18186 selectedClass : "x-view-selected",
18188 * @cfg {String} emptyText The empty text to show when nothing is loaded.
18193 * @cfg {String} text to display on mask (default Loading)
18197 * @cfg {Boolean} multiSelect Allow multiple selection
18199 multiSelect : false,
18201 * @cfg {Boolean} singleSelect Allow single selection
18203 singleSelect: false,
18206 * @cfg {Boolean} toggleSelect - selecting
18208 toggleSelect : false,
18211 * @cfg {Boolean} tickable - selecting
18216 * Returns the element this view is bound to.
18217 * @return {Roo.Element}
18219 getEl : function(){
18220 return this.wrapEl;
18226 * Refreshes the view. - called by datachanged on the store. - do not call directly.
18228 refresh : function(){
18229 //Roo.log('refresh');
18232 // if we are using something like 'domtemplate', then
18233 // the what gets used is:
18234 // t.applySubtemplate(NAME, data, wrapping data..)
18235 // the outer template then get' applied with
18236 // the store 'extra data'
18237 // and the body get's added to the
18238 // roo-name="data" node?
18239 // <span class='roo-tpl-{name}'></span> ?????
18243 this.clearSelections();
18244 this.el.update("");
18246 var records = this.store.getRange();
18247 if(records.length < 1) {
18249 // is this valid?? = should it render a template??
18251 this.el.update(this.emptyText);
18255 if (this.dataName) {
18256 this.el.update(t.apply(this.store.meta)); //????
18257 el = this.el.child('.roo-tpl-' + this.dataName);
18260 for(var i = 0, len = records.length; i < len; i++){
18261 var data = this.prepareData(records[i].data, i, records[i]);
18262 this.fireEvent("preparedata", this, data, i, records[i]);
18264 var d = Roo.apply({}, data);
18267 Roo.apply(d, {'roo-id' : Roo.id()});
18271 Roo.each(this.parent.item, function(item){
18272 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
18275 Roo.apply(d, {'roo-data-checked' : 'checked'});
18279 html[html.length] = Roo.util.Format.trim(
18281 t.applySubtemplate(this.dataName, d, this.store.meta) :
18288 el.update(html.join(""));
18289 this.nodes = el.dom.childNodes;
18290 this.updateIndexes(0);
18295 * Function to override to reformat the data that is sent to
18296 * the template for each node.
18297 * DEPRICATED - use the preparedata event handler.
18298 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
18299 * a JSON object for an UpdateManager bound view).
18301 prepareData : function(data, index, record)
18303 this.fireEvent("preparedata", this, data, index, record);
18307 onUpdate : function(ds, record){
18308 // Roo.log('on update');
18309 this.clearSelections();
18310 var index = this.store.indexOf(record);
18311 var n = this.nodes[index];
18312 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
18313 n.parentNode.removeChild(n);
18314 this.updateIndexes(index, index);
18320 onAdd : function(ds, records, index)
18322 //Roo.log(['on Add', ds, records, index] );
18323 this.clearSelections();
18324 if(this.nodes.length == 0){
18328 var n = this.nodes[index];
18329 for(var i = 0, len = records.length; i < len; i++){
18330 var d = this.prepareData(records[i].data, i, records[i]);
18332 this.tpl.insertBefore(n, d);
18335 this.tpl.append(this.el, d);
18338 this.updateIndexes(index);
18341 onRemove : function(ds, record, index){
18342 // Roo.log('onRemove');
18343 this.clearSelections();
18344 var el = this.dataName ?
18345 this.el.child('.roo-tpl-' + this.dataName) :
18348 el.dom.removeChild(this.nodes[index]);
18349 this.updateIndexes(index);
18353 * Refresh an individual node.
18354 * @param {Number} index
18356 refreshNode : function(index){
18357 this.onUpdate(this.store, this.store.getAt(index));
18360 updateIndexes : function(startIndex, endIndex){
18361 var ns = this.nodes;
18362 startIndex = startIndex || 0;
18363 endIndex = endIndex || ns.length - 1;
18364 for(var i = startIndex; i <= endIndex; i++){
18365 ns[i].nodeIndex = i;
18370 * Changes the data store this view uses and refresh the view.
18371 * @param {Store} store
18373 setStore : function(store, initial){
18374 if(!initial && this.store){
18375 this.store.un("datachanged", this.refresh);
18376 this.store.un("add", this.onAdd);
18377 this.store.un("remove", this.onRemove);
18378 this.store.un("update", this.onUpdate);
18379 this.store.un("clear", this.refresh);
18380 this.store.un("beforeload", this.onBeforeLoad);
18381 this.store.un("load", this.onLoad);
18382 this.store.un("loadexception", this.onLoad);
18386 store.on("datachanged", this.refresh, this);
18387 store.on("add", this.onAdd, this);
18388 store.on("remove", this.onRemove, this);
18389 store.on("update", this.onUpdate, this);
18390 store.on("clear", this.refresh, this);
18391 store.on("beforeload", this.onBeforeLoad, this);
18392 store.on("load", this.onLoad, this);
18393 store.on("loadexception", this.onLoad, this);
18401 * onbeforeLoad - masks the loading area.
18404 onBeforeLoad : function(store,opts)
18406 //Roo.log('onBeforeLoad');
18408 this.el.update("");
18410 this.el.mask(this.mask ? this.mask : "Loading" );
18412 onLoad : function ()
18419 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
18420 * @param {HTMLElement} node
18421 * @return {HTMLElement} The template node
18423 findItemFromChild : function(node){
18424 var el = this.dataName ?
18425 this.el.child('.roo-tpl-' + this.dataName,true) :
18428 if(!node || node.parentNode == el){
18431 var p = node.parentNode;
18432 while(p && p != el){
18433 if(p.parentNode == el){
18442 onClick : function(e){
18443 var item = this.findItemFromChild(e.getTarget());
18445 var index = this.indexOf(item);
18446 if(this.onItemClick(item, index, e) !== false){
18447 this.fireEvent("click", this, index, item, e);
18450 this.clearSelections();
18455 onContextMenu : function(e){
18456 var item = this.findItemFromChild(e.getTarget());
18458 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
18463 onDblClick : function(e){
18464 var item = this.findItemFromChild(e.getTarget());
18466 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
18470 onItemClick : function(item, index, e)
18472 if(this.fireEvent("beforeclick", this, index, item, e) === false){
18475 if (this.toggleSelect) {
18476 var m = this.isSelected(item) ? 'unselect' : 'select';
18479 _t[m](item, true, false);
18482 if(this.multiSelect || this.singleSelect){
18483 if(this.multiSelect && e.shiftKey && this.lastSelection){
18484 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
18486 this.select(item, this.multiSelect && e.ctrlKey);
18487 this.lastSelection = item;
18490 if(!this.tickable){
18491 e.preventDefault();
18499 * Get the number of selected nodes.
18502 getSelectionCount : function(){
18503 return this.selections.length;
18507 * Get the currently selected nodes.
18508 * @return {Array} An array of HTMLElements
18510 getSelectedNodes : function(){
18511 return this.selections;
18515 * Get the indexes of the selected nodes.
18518 getSelectedIndexes : function(){
18519 var indexes = [], s = this.selections;
18520 for(var i = 0, len = s.length; i < len; i++){
18521 indexes.push(s[i].nodeIndex);
18527 * Clear all selections
18528 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
18530 clearSelections : function(suppressEvent){
18531 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
18532 this.cmp.elements = this.selections;
18533 this.cmp.removeClass(this.selectedClass);
18534 this.selections = [];
18535 if(!suppressEvent){
18536 this.fireEvent("selectionchange", this, this.selections);
18542 * Returns true if the passed node is selected
18543 * @param {HTMLElement/Number} node The node or node index
18544 * @return {Boolean}
18546 isSelected : function(node){
18547 var s = this.selections;
18551 node = this.getNode(node);
18552 return s.indexOf(node) !== -1;
18557 * @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
18558 * @param {Boolean} keepExisting (optional) true to keep existing selections
18559 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18561 select : function(nodeInfo, keepExisting, suppressEvent){
18562 if(nodeInfo instanceof Array){
18564 this.clearSelections(true);
18566 for(var i = 0, len = nodeInfo.length; i < len; i++){
18567 this.select(nodeInfo[i], true, true);
18571 var node = this.getNode(nodeInfo);
18572 if(!node || this.isSelected(node)){
18573 return; // already selected.
18576 this.clearSelections(true);
18579 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
18580 Roo.fly(node).addClass(this.selectedClass);
18581 this.selections.push(node);
18582 if(!suppressEvent){
18583 this.fireEvent("selectionchange", this, this.selections);
18591 * @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
18592 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
18593 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18595 unselect : function(nodeInfo, keepExisting, suppressEvent)
18597 if(nodeInfo instanceof Array){
18598 Roo.each(this.selections, function(s) {
18599 this.unselect(s, nodeInfo);
18603 var node = this.getNode(nodeInfo);
18604 if(!node || !this.isSelected(node)){
18605 //Roo.log("not selected");
18606 return; // not selected.
18610 Roo.each(this.selections, function(s) {
18612 Roo.fly(node).removeClass(this.selectedClass);
18619 this.selections= ns;
18620 this.fireEvent("selectionchange", this, this.selections);
18624 * Gets a template node.
18625 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18626 * @return {HTMLElement} The node or null if it wasn't found
18628 getNode : function(nodeInfo){
18629 if(typeof nodeInfo == "string"){
18630 return document.getElementById(nodeInfo);
18631 }else if(typeof nodeInfo == "number"){
18632 return this.nodes[nodeInfo];
18638 * Gets a range template nodes.
18639 * @param {Number} startIndex
18640 * @param {Number} endIndex
18641 * @return {Array} An array of nodes
18643 getNodes : function(start, end){
18644 var ns = this.nodes;
18645 start = start || 0;
18646 end = typeof end == "undefined" ? ns.length - 1 : end;
18649 for(var i = start; i <= end; i++){
18653 for(var i = start; i >= end; i--){
18661 * Finds the index of the passed node
18662 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18663 * @return {Number} The index of the node or -1
18665 indexOf : function(node){
18666 node = this.getNode(node);
18667 if(typeof node.nodeIndex == "number"){
18668 return node.nodeIndex;
18670 var ns = this.nodes;
18671 for(var i = 0, len = ns.length; i < len; i++){
18682 * based on jquery fullcalendar
18686 Roo.bootstrap = Roo.bootstrap || {};
18688 * @class Roo.bootstrap.Calendar
18689 * @extends Roo.bootstrap.Component
18690 * Bootstrap Calendar class
18691 * @cfg {Boolean} loadMask (true|false) default false
18692 * @cfg {Object} header generate the user specific header of the calendar, default false
18695 * Create a new Container
18696 * @param {Object} config The config object
18701 Roo.bootstrap.Calendar = function(config){
18702 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
18706 * Fires when a date is selected
18707 * @param {DatePicker} this
18708 * @param {Date} date The selected date
18712 * @event monthchange
18713 * Fires when the displayed month changes
18714 * @param {DatePicker} this
18715 * @param {Date} date The selected month
18717 'monthchange': true,
18719 * @event evententer
18720 * Fires when mouse over an event
18721 * @param {Calendar} this
18722 * @param {event} Event
18724 'evententer': true,
18726 * @event eventleave
18727 * Fires when the mouse leaves an
18728 * @param {Calendar} this
18731 'eventleave': true,
18733 * @event eventclick
18734 * Fires when the mouse click an
18735 * @param {Calendar} this
18744 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
18747 * @cfg {Number} startDay
18748 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
18756 getAutoCreate : function(){
18759 var fc_button = function(name, corner, style, content ) {
18760 return Roo.apply({},{
18762 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
18764 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
18767 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
18778 style : 'width:100%',
18785 cls : 'fc-header-left',
18787 fc_button('prev', 'left', 'arrow', '‹' ),
18788 fc_button('next', 'right', 'arrow', '›' ),
18789 { tag: 'span', cls: 'fc-header-space' },
18790 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
18798 cls : 'fc-header-center',
18802 cls: 'fc-header-title',
18805 html : 'month / year'
18813 cls : 'fc-header-right',
18815 /* fc_button('month', 'left', '', 'month' ),
18816 fc_button('week', '', '', 'week' ),
18817 fc_button('day', 'right', '', 'day' )
18829 header = this.header;
18832 var cal_heads = function() {
18834 // fixme - handle this.
18836 for (var i =0; i < Date.dayNames.length; i++) {
18837 var d = Date.dayNames[i];
18840 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18841 html : d.substring(0,3)
18845 ret[0].cls += ' fc-first';
18846 ret[6].cls += ' fc-last';
18849 var cal_cell = function(n) {
18852 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18857 cls: 'fc-day-number',
18861 cls: 'fc-day-content',
18865 style: 'position: relative;' // height: 17px;
18877 var cal_rows = function() {
18880 for (var r = 0; r < 6; r++) {
18887 for (var i =0; i < Date.dayNames.length; i++) {
18888 var d = Date.dayNames[i];
18889 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18892 row.cn[0].cls+=' fc-first';
18893 row.cn[0].cn[0].style = 'min-height:90px';
18894 row.cn[6].cls+=' fc-last';
18898 ret[0].cls += ' fc-first';
18899 ret[4].cls += ' fc-prev-last';
18900 ret[5].cls += ' fc-last';
18907 cls: 'fc-border-separate',
18908 style : 'width:100%',
18916 cls : 'fc-first fc-last',
18934 cls : 'fc-content',
18935 style : "position: relative;",
18938 cls : 'fc-view fc-view-month fc-grid',
18939 style : 'position: relative',
18940 unselectable : 'on',
18943 cls : 'fc-event-container',
18944 style : 'position:absolute;z-index:8;top:0;left:0;'
18962 initEvents : function()
18965 throw "can not find store for calendar";
18971 style: "text-align:center",
18975 style: "background-color:white;width:50%;margin:250 auto",
18979 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18990 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18992 var size = this.el.select('.fc-content', true).first().getSize();
18993 this.maskEl.setSize(size.width, size.height);
18994 this.maskEl.enableDisplayMode("block");
18995 if(!this.loadMask){
18996 this.maskEl.hide();
18999 this.store = Roo.factory(this.store, Roo.data);
19000 this.store.on('load', this.onLoad, this);
19001 this.store.on('beforeload', this.onBeforeLoad, this);
19005 this.cells = this.el.select('.fc-day',true);
19006 //Roo.log(this.cells);
19007 this.textNodes = this.el.query('.fc-day-number');
19008 this.cells.addClassOnOver('fc-state-hover');
19010 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
19011 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
19012 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
19013 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
19015 this.on('monthchange', this.onMonthChange, this);
19017 this.update(new Date().clearTime());
19020 resize : function() {
19021 var sz = this.el.getSize();
19023 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
19024 this.el.select('.fc-day-content div',true).setHeight(34);
19029 showPrevMonth : function(e){
19030 this.update(this.activeDate.add("mo", -1));
19032 showToday : function(e){
19033 this.update(new Date().clearTime());
19036 showNextMonth : function(e){
19037 this.update(this.activeDate.add("mo", 1));
19041 showPrevYear : function(){
19042 this.update(this.activeDate.add("y", -1));
19046 showNextYear : function(){
19047 this.update(this.activeDate.add("y", 1));
19052 update : function(date)
19054 var vd = this.activeDate;
19055 this.activeDate = date;
19056 // if(vd && this.el){
19057 // var t = date.getTime();
19058 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
19059 // Roo.log('using add remove');
19061 // this.fireEvent('monthchange', this, date);
19063 // this.cells.removeClass("fc-state-highlight");
19064 // this.cells.each(function(c){
19065 // if(c.dateValue == t){
19066 // c.addClass("fc-state-highlight");
19067 // setTimeout(function(){
19068 // try{c.dom.firstChild.focus();}catch(e){}
19078 var days = date.getDaysInMonth();
19080 var firstOfMonth = date.getFirstDateOfMonth();
19081 var startingPos = firstOfMonth.getDay()-this.startDay;
19083 if(startingPos < this.startDay){
19087 var pm = date.add(Date.MONTH, -1);
19088 var prevStart = pm.getDaysInMonth()-startingPos;
19090 this.cells = this.el.select('.fc-day',true);
19091 this.textNodes = this.el.query('.fc-day-number');
19092 this.cells.addClassOnOver('fc-state-hover');
19094 var cells = this.cells.elements;
19095 var textEls = this.textNodes;
19097 Roo.each(cells, function(cell){
19098 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
19101 days += startingPos;
19103 // convert everything to numbers so it's fast
19104 var day = 86400000;
19105 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
19108 //Roo.log(prevStart);
19110 var today = new Date().clearTime().getTime();
19111 var sel = date.clearTime().getTime();
19112 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
19113 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
19114 var ddMatch = this.disabledDatesRE;
19115 var ddText = this.disabledDatesText;
19116 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
19117 var ddaysText = this.disabledDaysText;
19118 var format = this.format;
19120 var setCellClass = function(cal, cell){
19124 //Roo.log('set Cell Class');
19126 var t = d.getTime();
19130 cell.dateValue = t;
19132 cell.className += " fc-today";
19133 cell.className += " fc-state-highlight";
19134 cell.title = cal.todayText;
19137 // disable highlight in other month..
19138 //cell.className += " fc-state-highlight";
19143 cell.className = " fc-state-disabled";
19144 cell.title = cal.minText;
19148 cell.className = " fc-state-disabled";
19149 cell.title = cal.maxText;
19153 if(ddays.indexOf(d.getDay()) != -1){
19154 cell.title = ddaysText;
19155 cell.className = " fc-state-disabled";
19158 if(ddMatch && format){
19159 var fvalue = d.dateFormat(format);
19160 if(ddMatch.test(fvalue)){
19161 cell.title = ddText.replace("%0", fvalue);
19162 cell.className = " fc-state-disabled";
19166 if (!cell.initialClassName) {
19167 cell.initialClassName = cell.dom.className;
19170 cell.dom.className = cell.initialClassName + ' ' + cell.className;
19175 for(; i < startingPos; i++) {
19176 textEls[i].innerHTML = (++prevStart);
19177 d.setDate(d.getDate()+1);
19179 cells[i].className = "fc-past fc-other-month";
19180 setCellClass(this, cells[i]);
19185 for(; i < days; i++){
19186 intDay = i - startingPos + 1;
19187 textEls[i].innerHTML = (intDay);
19188 d.setDate(d.getDate()+1);
19190 cells[i].className = ''; // "x-date-active";
19191 setCellClass(this, cells[i]);
19195 for(; i < 42; i++) {
19196 textEls[i].innerHTML = (++extraDays);
19197 d.setDate(d.getDate()+1);
19199 cells[i].className = "fc-future fc-other-month";
19200 setCellClass(this, cells[i]);
19203 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
19205 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
19207 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
19208 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
19210 if(totalRows != 6){
19211 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
19212 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
19215 this.fireEvent('monthchange', this, date);
19219 if(!this.internalRender){
19220 var main = this.el.dom.firstChild;
19221 var w = main.offsetWidth;
19222 this.el.setWidth(w + this.el.getBorderWidth("lr"));
19223 Roo.fly(main).setWidth(w);
19224 this.internalRender = true;
19225 // opera does not respect the auto grow header center column
19226 // then, after it gets a width opera refuses to recalculate
19227 // without a second pass
19228 if(Roo.isOpera && !this.secondPass){
19229 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
19230 this.secondPass = true;
19231 this.update.defer(10, this, [date]);
19238 findCell : function(dt) {
19239 dt = dt.clearTime().getTime();
19241 this.cells.each(function(c){
19242 //Roo.log("check " +c.dateValue + '?=' + dt);
19243 if(c.dateValue == dt){
19253 findCells : function(ev) {
19254 var s = ev.start.clone().clearTime().getTime();
19256 var e= ev.end.clone().clearTime().getTime();
19259 this.cells.each(function(c){
19260 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
19262 if(c.dateValue > e){
19265 if(c.dateValue < s){
19274 // findBestRow: function(cells)
19278 // for (var i =0 ; i < cells.length;i++) {
19279 // ret = Math.max(cells[i].rows || 0,ret);
19286 addItem : function(ev)
19288 // look for vertical location slot in
19289 var cells = this.findCells(ev);
19291 // ev.row = this.findBestRow(cells);
19293 // work out the location.
19297 for(var i =0; i < cells.length; i++) {
19299 cells[i].row = cells[0].row;
19302 cells[i].row = cells[i].row + 1;
19312 if (crow.start.getY() == cells[i].getY()) {
19314 crow.end = cells[i];
19331 cells[0].events.push(ev);
19333 this.calevents.push(ev);
19336 clearEvents: function() {
19338 if(!this.calevents){
19342 Roo.each(this.cells.elements, function(c){
19348 Roo.each(this.calevents, function(e) {
19349 Roo.each(e.els, function(el) {
19350 el.un('mouseenter' ,this.onEventEnter, this);
19351 el.un('mouseleave' ,this.onEventLeave, this);
19356 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
19362 renderEvents: function()
19366 this.cells.each(function(c) {
19375 if(c.row != c.events.length){
19376 r = 4 - (4 - (c.row - c.events.length));
19379 c.events = ev.slice(0, r);
19380 c.more = ev.slice(r);
19382 if(c.more.length && c.more.length == 1){
19383 c.events.push(c.more.pop());
19386 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
19390 this.cells.each(function(c) {
19392 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
19395 for (var e = 0; e < c.events.length; e++){
19396 var ev = c.events[e];
19397 var rows = ev.rows;
19399 for(var i = 0; i < rows.length; i++) {
19401 // how many rows should it span..
19404 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
19405 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
19407 unselectable : "on",
19410 cls: 'fc-event-inner',
19414 // cls: 'fc-event-time',
19415 // html : cells.length > 1 ? '' : ev.time
19419 cls: 'fc-event-title',
19420 html : String.format('{0}', ev.title)
19427 cls: 'ui-resizable-handle ui-resizable-e',
19428 html : '  '
19435 cfg.cls += ' fc-event-start';
19437 if ((i+1) == rows.length) {
19438 cfg.cls += ' fc-event-end';
19441 var ctr = _this.el.select('.fc-event-container',true).first();
19442 var cg = ctr.createChild(cfg);
19444 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
19445 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
19447 var r = (c.more.length) ? 1 : 0;
19448 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
19449 cg.setWidth(ebox.right - sbox.x -2);
19451 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
19452 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
19453 cg.on('click', _this.onEventClick, _this, ev);
19464 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
19465 style : 'position: absolute',
19466 unselectable : "on",
19469 cls: 'fc-event-inner',
19473 cls: 'fc-event-title',
19481 cls: 'ui-resizable-handle ui-resizable-e',
19482 html : '  '
19488 var ctr = _this.el.select('.fc-event-container',true).first();
19489 var cg = ctr.createChild(cfg);
19491 var sbox = c.select('.fc-day-content',true).first().getBox();
19492 var ebox = c.select('.fc-day-content',true).first().getBox();
19494 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
19495 cg.setWidth(ebox.right - sbox.x -2);
19497 cg.on('click', _this.onMoreEventClick, _this, c.more);
19507 onEventEnter: function (e, el,event,d) {
19508 this.fireEvent('evententer', this, el, event);
19511 onEventLeave: function (e, el,event,d) {
19512 this.fireEvent('eventleave', this, el, event);
19515 onEventClick: function (e, el,event,d) {
19516 this.fireEvent('eventclick', this, el, event);
19519 onMonthChange: function () {
19523 onMoreEventClick: function(e, el, more)
19527 this.calpopover.placement = 'right';
19528 this.calpopover.setTitle('More');
19530 this.calpopover.setContent('');
19532 var ctr = this.calpopover.el.select('.popover-content', true).first();
19534 Roo.each(more, function(m){
19536 cls : 'fc-event-hori fc-event-draggable',
19539 var cg = ctr.createChild(cfg);
19541 cg.on('click', _this.onEventClick, _this, m);
19544 this.calpopover.show(el);
19549 onLoad: function ()
19551 this.calevents = [];
19554 if(this.store.getCount() > 0){
19555 this.store.data.each(function(d){
19558 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
19559 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
19560 time : d.data.start_time,
19561 title : d.data.title,
19562 description : d.data.description,
19563 venue : d.data.venue
19568 this.renderEvents();
19570 if(this.calevents.length && this.loadMask){
19571 this.maskEl.hide();
19575 onBeforeLoad: function()
19577 this.clearEvents();
19579 this.maskEl.show();
19593 * @class Roo.bootstrap.Popover
19594 * @extends Roo.bootstrap.Component
19595 * Bootstrap Popover class
19596 * @cfg {String} html contents of the popover (or false to use children..)
19597 * @cfg {String} title of popover (or false to hide)
19598 * @cfg {String} placement how it is placed
19599 * @cfg {String} trigger click || hover (or false to trigger manually)
19600 * @cfg {String} over what (parent or false to trigger manually.)
19601 * @cfg {Number} delay - delay before showing
19604 * Create a new Popover
19605 * @param {Object} config The config object
19608 Roo.bootstrap.Popover = function(config){
19609 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
19615 * After the popover show
19617 * @param {Roo.bootstrap.Popover} this
19622 * After the popover hide
19624 * @param {Roo.bootstrap.Popover} this
19630 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
19632 title: 'Fill in a title',
19635 placement : 'right',
19636 trigger : 'hover', // hover
19642 can_build_overlaid : false,
19644 getChildContainer : function()
19646 return this.el.select('.popover-content',true).first();
19649 getAutoCreate : function(){
19652 cls : 'popover roo-dynamic',
19653 style: 'display:block',
19659 cls : 'popover-inner',
19663 cls: 'popover-title popover-header',
19667 cls : 'popover-content popover-body',
19678 setTitle: function(str)
19681 this.el.select('.popover-title',true).first().dom.innerHTML = str;
19683 setContent: function(str)
19686 this.el.select('.popover-content',true).first().dom.innerHTML = str;
19688 // as it get's added to the bottom of the page.
19689 onRender : function(ct, position)
19691 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19693 var cfg = Roo.apply({}, this.getAutoCreate());
19697 cfg.cls += ' ' + this.cls;
19700 cfg.style = this.style;
19702 //Roo.log("adding to ");
19703 this.el = Roo.get(document.body).createChild(cfg, position);
19704 // Roo.log(this.el);
19709 initEvents : function()
19711 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
19712 this.el.enableDisplayMode('block');
19714 if (this.over === false) {
19717 if (this.triggers === false) {
19720 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19721 var triggers = this.trigger ? this.trigger.split(' ') : [];
19722 Roo.each(triggers, function(trigger) {
19724 if (trigger == 'click') {
19725 on_el.on('click', this.toggle, this);
19726 } else if (trigger != 'manual') {
19727 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
19728 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
19730 on_el.on(eventIn ,this.enter, this);
19731 on_el.on(eventOut, this.leave, this);
19742 toggle : function () {
19743 this.hoverState == 'in' ? this.leave() : this.enter();
19746 enter : function () {
19748 clearTimeout(this.timeout);
19750 this.hoverState = 'in';
19752 if (!this.delay || !this.delay.show) {
19757 this.timeout = setTimeout(function () {
19758 if (_t.hoverState == 'in') {
19761 }, this.delay.show)
19764 leave : function() {
19765 clearTimeout(this.timeout);
19767 this.hoverState = 'out';
19769 if (!this.delay || !this.delay.hide) {
19774 this.timeout = setTimeout(function () {
19775 if (_t.hoverState == 'out') {
19778 }, this.delay.hide)
19781 show : function (on_el)
19784 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19788 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
19789 if (this.html !== false) {
19790 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
19792 this.el.removeClass([
19793 'fade','top','bottom', 'left', 'right','in',
19794 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
19796 if (!this.title.length) {
19797 this.el.select('.popover-title',true).hide();
19800 var placement = typeof this.placement == 'function' ?
19801 this.placement.call(this, this.el, on_el) :
19804 var autoToken = /\s?auto?\s?/i;
19805 var autoPlace = autoToken.test(placement);
19807 placement = placement.replace(autoToken, '') || 'top';
19811 //this.el.setXY([0,0]);
19813 this.el.dom.style.display='block';
19814 this.el.addClass(placement);
19816 //this.el.appendTo(on_el);
19818 var p = this.getPosition();
19819 var box = this.el.getBox();
19824 var align = Roo.bootstrap.Popover.alignment[placement];
19827 this.el.alignTo(on_el, align[0],align[1]);
19828 //var arrow = this.el.select('.arrow',true).first();
19829 //arrow.set(align[2],
19831 this.el.addClass('in');
19834 if (this.el.hasClass('fade')) {
19838 this.hoverState = 'in';
19840 this.fireEvent('show', this);
19845 this.el.setXY([0,0]);
19846 this.el.removeClass('in');
19848 this.hoverState = null;
19850 this.fireEvent('hide', this);
19855 Roo.bootstrap.Popover.alignment = {
19856 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19857 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19858 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19859 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19870 * @class Roo.bootstrap.Progress
19871 * @extends Roo.bootstrap.Component
19872 * Bootstrap Progress class
19873 * @cfg {Boolean} striped striped of the progress bar
19874 * @cfg {Boolean} active animated of the progress bar
19878 * Create a new Progress
19879 * @param {Object} config The config object
19882 Roo.bootstrap.Progress = function(config){
19883 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19886 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19891 getAutoCreate : function(){
19899 cfg.cls += ' progress-striped';
19903 cfg.cls += ' active';
19922 * @class Roo.bootstrap.ProgressBar
19923 * @extends Roo.bootstrap.Component
19924 * Bootstrap ProgressBar class
19925 * @cfg {Number} aria_valuenow aria-value now
19926 * @cfg {Number} aria_valuemin aria-value min
19927 * @cfg {Number} aria_valuemax aria-value max
19928 * @cfg {String} label label for the progress bar
19929 * @cfg {String} panel (success | info | warning | danger )
19930 * @cfg {String} role role of the progress bar
19931 * @cfg {String} sr_only text
19935 * Create a new ProgressBar
19936 * @param {Object} config The config object
19939 Roo.bootstrap.ProgressBar = function(config){
19940 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19943 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19947 aria_valuemax : 100,
19953 getAutoCreate : function()
19958 cls: 'progress-bar',
19959 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19971 cfg.role = this.role;
19974 if(this.aria_valuenow){
19975 cfg['aria-valuenow'] = this.aria_valuenow;
19978 if(this.aria_valuemin){
19979 cfg['aria-valuemin'] = this.aria_valuemin;
19982 if(this.aria_valuemax){
19983 cfg['aria-valuemax'] = this.aria_valuemax;
19986 if(this.label && !this.sr_only){
19987 cfg.html = this.label;
19991 cfg.cls += ' progress-bar-' + this.panel;
19997 update : function(aria_valuenow)
19999 this.aria_valuenow = aria_valuenow;
20001 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
20016 * @class Roo.bootstrap.TabGroup
20017 * @extends Roo.bootstrap.Column
20018 * Bootstrap Column class
20019 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
20020 * @cfg {Boolean} carousel true to make the group behave like a carousel
20021 * @cfg {Boolean} bullets show bullets for the panels
20022 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
20023 * @cfg {Number} timer auto slide timer .. default 0 millisecond
20024 * @cfg {Boolean} showarrow (true|false) show arrow default true
20027 * Create a new TabGroup
20028 * @param {Object} config The config object
20031 Roo.bootstrap.TabGroup = function(config){
20032 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
20034 this.navId = Roo.id();
20037 Roo.bootstrap.TabGroup.register(this);
20041 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
20044 transition : false,
20049 slideOnTouch : false,
20052 getAutoCreate : function()
20054 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
20056 cfg.cls += ' tab-content';
20058 if (this.carousel) {
20059 cfg.cls += ' carousel slide';
20062 cls : 'carousel-inner',
20066 if(this.bullets && !Roo.isTouch){
20069 cls : 'carousel-bullets',
20073 if(this.bullets_cls){
20074 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
20081 cfg.cn[0].cn.push(bullets);
20084 if(this.showarrow){
20085 cfg.cn[0].cn.push({
20087 class : 'carousel-arrow',
20091 class : 'carousel-prev',
20095 class : 'fa fa-chevron-left'
20101 class : 'carousel-next',
20105 class : 'fa fa-chevron-right'
20118 initEvents: function()
20120 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
20121 // this.el.on("touchstart", this.onTouchStart, this);
20124 if(this.autoslide){
20127 this.slideFn = window.setInterval(function() {
20128 _this.showPanelNext();
20132 if(this.showarrow){
20133 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
20134 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
20140 // onTouchStart : function(e, el, o)
20142 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
20146 // this.showPanelNext();
20150 getChildContainer : function()
20152 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
20156 * register a Navigation item
20157 * @param {Roo.bootstrap.NavItem} the navitem to add
20159 register : function(item)
20161 this.tabs.push( item);
20162 item.navId = this.navId; // not really needed..
20167 getActivePanel : function()
20170 Roo.each(this.tabs, function(t) {
20180 getPanelByName : function(n)
20183 Roo.each(this.tabs, function(t) {
20184 if (t.tabId == n) {
20192 indexOfPanel : function(p)
20195 Roo.each(this.tabs, function(t,i) {
20196 if (t.tabId == p.tabId) {
20205 * show a specific panel
20206 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
20207 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
20209 showPanel : function (pan)
20211 if(this.transition || typeof(pan) == 'undefined'){
20212 Roo.log("waiting for the transitionend");
20216 if (typeof(pan) == 'number') {
20217 pan = this.tabs[pan];
20220 if (typeof(pan) == 'string') {
20221 pan = this.getPanelByName(pan);
20224 var cur = this.getActivePanel();
20227 Roo.log('pan or acitve pan is undefined');
20231 if (pan.tabId == this.getActivePanel().tabId) {
20235 if (false === cur.fireEvent('beforedeactivate')) {
20239 if(this.bullets > 0 && !Roo.isTouch){
20240 this.setActiveBullet(this.indexOfPanel(pan));
20243 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
20245 //class="carousel-item carousel-item-next carousel-item-left"
20247 this.transition = true;
20248 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
20249 var lr = dir == 'next' ? 'left' : 'right';
20250 pan.el.addClass(dir); // or prev
20251 pan.el.addClass('carousel-item-' + dir); // or prev
20252 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
20253 cur.el.addClass(lr); // or right
20254 pan.el.addClass(lr);
20255 cur.el.addClass('carousel-item-' +lr); // or right
20256 pan.el.addClass('carousel-item-' +lr);
20260 cur.el.on('transitionend', function() {
20261 Roo.log("trans end?");
20263 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
20264 pan.setActive(true);
20266 cur.el.removeClass([lr, 'carousel-item-' + lr]);
20267 cur.setActive(false);
20269 _this.transition = false;
20271 }, this, { single: true } );
20276 cur.setActive(false);
20277 pan.setActive(true);
20282 showPanelNext : function()
20284 var i = this.indexOfPanel(this.getActivePanel());
20286 if (i >= this.tabs.length - 1 && !this.autoslide) {
20290 if (i >= this.tabs.length - 1 && this.autoslide) {
20294 this.showPanel(this.tabs[i+1]);
20297 showPanelPrev : function()
20299 var i = this.indexOfPanel(this.getActivePanel());
20301 if (i < 1 && !this.autoslide) {
20305 if (i < 1 && this.autoslide) {
20306 i = this.tabs.length;
20309 this.showPanel(this.tabs[i-1]);
20313 addBullet: function()
20315 if(!this.bullets || Roo.isTouch){
20318 var ctr = this.el.select('.carousel-bullets',true).first();
20319 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
20320 var bullet = ctr.createChild({
20321 cls : 'bullet bullet-' + i
20322 },ctr.dom.lastChild);
20327 bullet.on('click', (function(e, el, o, ii, t){
20329 e.preventDefault();
20331 this.showPanel(ii);
20333 if(this.autoslide && this.slideFn){
20334 clearInterval(this.slideFn);
20335 this.slideFn = window.setInterval(function() {
20336 _this.showPanelNext();
20340 }).createDelegate(this, [i, bullet], true));
20345 setActiveBullet : function(i)
20351 Roo.each(this.el.select('.bullet', true).elements, function(el){
20352 el.removeClass('selected');
20355 var bullet = this.el.select('.bullet-' + i, true).first();
20361 bullet.addClass('selected');
20372 Roo.apply(Roo.bootstrap.TabGroup, {
20376 * register a Navigation Group
20377 * @param {Roo.bootstrap.NavGroup} the navgroup to add
20379 register : function(navgrp)
20381 this.groups[navgrp.navId] = navgrp;
20385 * fetch a Navigation Group based on the navigation ID
20386 * if one does not exist , it will get created.
20387 * @param {string} the navgroup to add
20388 * @returns {Roo.bootstrap.NavGroup} the navgroup
20390 get: function(navId) {
20391 if (typeof(this.groups[navId]) == 'undefined') {
20392 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
20394 return this.groups[navId] ;
20409 * @class Roo.bootstrap.TabPanel
20410 * @extends Roo.bootstrap.Component
20411 * Bootstrap TabPanel class
20412 * @cfg {Boolean} active panel active
20413 * @cfg {String} html panel content
20414 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
20415 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
20416 * @cfg {String} href click to link..
20417 * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
20421 * Create a new TabPanel
20422 * @param {Object} config The config object
20425 Roo.bootstrap.TabPanel = function(config){
20426 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
20430 * Fires when the active status changes
20431 * @param {Roo.bootstrap.TabPanel} this
20432 * @param {Boolean} state the new state
20437 * @event beforedeactivate
20438 * Fires before a tab is de-activated - can be used to do validation on a form.
20439 * @param {Roo.bootstrap.TabPanel} this
20440 * @return {Boolean} false if there is an error
20443 'beforedeactivate': true
20446 this.tabId = this.tabId || Roo.id();
20450 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
20457 touchSlide : false,
20458 getAutoCreate : function(){
20463 // item is needed for carousel - not sure if it has any effect otherwise
20464 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
20465 html: this.html || ''
20469 cfg.cls += ' active';
20473 cfg.tabId = this.tabId;
20481 initEvents: function()
20483 var p = this.parent();
20485 this.navId = this.navId || p.navId;
20487 if (typeof(this.navId) != 'undefined') {
20488 // not really needed.. but just in case.. parent should be a NavGroup.
20489 var tg = Roo.bootstrap.TabGroup.get(this.navId);
20493 var i = tg.tabs.length - 1;
20495 if(this.active && tg.bullets > 0 && i < tg.bullets){
20496 tg.setActiveBullet(i);
20500 this.el.on('click', this.onClick, this);
20502 if(Roo.isTouch && this.touchSlide){
20503 this.el.on("touchstart", this.onTouchStart, this);
20504 this.el.on("touchmove", this.onTouchMove, this);
20505 this.el.on("touchend", this.onTouchEnd, this);
20510 onRender : function(ct, position)
20512 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
20515 setActive : function(state)
20517 Roo.log("panel - set active " + this.tabId + "=" + state);
20519 this.active = state;
20521 this.el.removeClass('active');
20523 } else if (!this.el.hasClass('active')) {
20524 this.el.addClass('active');
20527 this.fireEvent('changed', this, state);
20530 onClick : function(e)
20532 e.preventDefault();
20534 if(!this.href.length){
20538 window.location.href = this.href;
20547 onTouchStart : function(e)
20549 this.swiping = false;
20551 this.startX = e.browserEvent.touches[0].clientX;
20552 this.startY = e.browserEvent.touches[0].clientY;
20555 onTouchMove : function(e)
20557 this.swiping = true;
20559 this.endX = e.browserEvent.touches[0].clientX;
20560 this.endY = e.browserEvent.touches[0].clientY;
20563 onTouchEnd : function(e)
20570 var tabGroup = this.parent();
20572 if(this.endX > this.startX){ // swiping right
20573 tabGroup.showPanelPrev();
20577 if(this.startX > this.endX){ // swiping left
20578 tabGroup.showPanelNext();
20597 * @class Roo.bootstrap.DateField
20598 * @extends Roo.bootstrap.Input
20599 * Bootstrap DateField class
20600 * @cfg {Number} weekStart default 0
20601 * @cfg {String} viewMode default empty, (months|years)
20602 * @cfg {String} minViewMode default empty, (months|years)
20603 * @cfg {Number} startDate default -Infinity
20604 * @cfg {Number} endDate default Infinity
20605 * @cfg {Boolean} todayHighlight default false
20606 * @cfg {Boolean} todayBtn default false
20607 * @cfg {Boolean} calendarWeeks default false
20608 * @cfg {Object} daysOfWeekDisabled default empty
20609 * @cfg {Boolean} singleMode default false (true | false)
20611 * @cfg {Boolean} keyboardNavigation default true
20612 * @cfg {String} language default en
20615 * Create a new DateField
20616 * @param {Object} config The config object
20619 Roo.bootstrap.DateField = function(config){
20620 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
20624 * Fires when this field show.
20625 * @param {Roo.bootstrap.DateField} this
20626 * @param {Mixed} date The date value
20631 * Fires when this field hide.
20632 * @param {Roo.bootstrap.DateField} this
20633 * @param {Mixed} date The date value
20638 * Fires when select a date.
20639 * @param {Roo.bootstrap.DateField} this
20640 * @param {Mixed} date The date value
20644 * @event beforeselect
20645 * Fires when before select a date.
20646 * @param {Roo.bootstrap.DateField} this
20647 * @param {Mixed} date The date value
20649 beforeselect : true
20653 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
20656 * @cfg {String} format
20657 * The default date format string which can be overriden for localization support. The format must be
20658 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
20662 * @cfg {String} altFormats
20663 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
20664 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
20666 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
20674 todayHighlight : false,
20680 keyboardNavigation: true,
20682 calendarWeeks: false,
20684 startDate: -Infinity,
20688 daysOfWeekDisabled: [],
20692 singleMode : false,
20694 UTCDate: function()
20696 return new Date(Date.UTC.apply(Date, arguments));
20699 UTCToday: function()
20701 var today = new Date();
20702 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
20705 getDate: function() {
20706 var d = this.getUTCDate();
20707 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
20710 getUTCDate: function() {
20714 setDate: function(d) {
20715 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
20718 setUTCDate: function(d) {
20720 this.setValue(this.formatDate(this.date));
20723 onRender: function(ct, position)
20726 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
20728 this.language = this.language || 'en';
20729 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
20730 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
20732 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
20733 this.format = this.format || 'm/d/y';
20734 this.isInline = false;
20735 this.isInput = true;
20736 this.component = this.el.select('.add-on', true).first() || false;
20737 this.component = (this.component && this.component.length === 0) ? false : this.component;
20738 this.hasInput = this.component && this.inputEl().length;
20740 if (typeof(this.minViewMode === 'string')) {
20741 switch (this.minViewMode) {
20743 this.minViewMode = 1;
20746 this.minViewMode = 2;
20749 this.minViewMode = 0;
20754 if (typeof(this.viewMode === 'string')) {
20755 switch (this.viewMode) {
20768 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
20770 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
20772 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20774 this.picker().on('mousedown', this.onMousedown, this);
20775 this.picker().on('click', this.onClick, this);
20777 this.picker().addClass('datepicker-dropdown');
20779 this.startViewMode = this.viewMode;
20781 if(this.singleMode){
20782 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
20783 v.setVisibilityMode(Roo.Element.DISPLAY);
20787 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20788 v.setStyle('width', '189px');
20792 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
20793 if(!this.calendarWeeks){
20798 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20799 v.attr('colspan', function(i, val){
20800 return parseInt(val) + 1;
20805 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20807 this.setStartDate(this.startDate);
20808 this.setEndDate(this.endDate);
20810 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20817 if(this.isInline) {
20822 picker : function()
20824 return this.pickerEl;
20825 // return this.el.select('.datepicker', true).first();
20828 fillDow: function()
20830 var dowCnt = this.weekStart;
20839 if(this.calendarWeeks){
20847 while (dowCnt < this.weekStart + 7) {
20851 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20855 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20858 fillMonths: function()
20861 var months = this.picker().select('>.datepicker-months td', true).first();
20863 months.dom.innerHTML = '';
20869 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20872 months.createChild(month);
20879 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;
20881 if (this.date < this.startDate) {
20882 this.viewDate = new Date(this.startDate);
20883 } else if (this.date > this.endDate) {
20884 this.viewDate = new Date(this.endDate);
20886 this.viewDate = new Date(this.date);
20894 var d = new Date(this.viewDate),
20895 year = d.getUTCFullYear(),
20896 month = d.getUTCMonth(),
20897 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20898 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20899 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20900 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20901 currentDate = this.date && this.date.valueOf(),
20902 today = this.UTCToday();
20904 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20906 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20908 // this.picker.select('>tfoot th.today').
20909 // .text(dates[this.language].today)
20910 // .toggle(this.todayBtn !== false);
20912 this.updateNavArrows();
20915 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20917 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20919 prevMonth.setUTCDate(day);
20921 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20923 var nextMonth = new Date(prevMonth);
20925 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20927 nextMonth = nextMonth.valueOf();
20929 var fillMonths = false;
20931 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20933 while(prevMonth.valueOf() <= nextMonth) {
20936 if (prevMonth.getUTCDay() === this.weekStart) {
20938 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20946 if(this.calendarWeeks){
20947 // ISO 8601: First week contains first thursday.
20948 // ISO also states week starts on Monday, but we can be more abstract here.
20950 // Start of current week: based on weekstart/current date
20951 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20952 // Thursday of this week
20953 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20954 // First Thursday of year, year from thursday
20955 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20956 // Calendar week: ms between thursdays, div ms per day, div 7 days
20957 calWeek = (th - yth) / 864e5 / 7 + 1;
20959 fillMonths.cn.push({
20967 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20969 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20972 if (this.todayHighlight &&
20973 prevMonth.getUTCFullYear() == today.getFullYear() &&
20974 prevMonth.getUTCMonth() == today.getMonth() &&
20975 prevMonth.getUTCDate() == today.getDate()) {
20976 clsName += ' today';
20979 if (currentDate && prevMonth.valueOf() === currentDate) {
20980 clsName += ' active';
20983 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20984 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20985 clsName += ' disabled';
20988 fillMonths.cn.push({
20990 cls: 'day ' + clsName,
20991 html: prevMonth.getDate()
20994 prevMonth.setDate(prevMonth.getDate()+1);
20997 var currentYear = this.date && this.date.getUTCFullYear();
20998 var currentMonth = this.date && this.date.getUTCMonth();
21000 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
21002 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
21003 v.removeClass('active');
21005 if(currentYear === year && k === currentMonth){
21006 v.addClass('active');
21009 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
21010 v.addClass('disabled');
21016 year = parseInt(year/10, 10) * 10;
21018 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
21020 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
21023 for (var i = -1; i < 11; i++) {
21024 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
21026 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
21034 showMode: function(dir)
21037 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
21040 Roo.each(this.picker().select('>div',true).elements, function(v){
21041 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21044 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
21049 if(this.isInline) {
21053 this.picker().removeClass(['bottom', 'top']);
21055 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
21057 * place to the top of element!
21061 this.picker().addClass('top');
21062 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
21067 this.picker().addClass('bottom');
21069 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
21072 parseDate : function(value)
21074 if(!value || value instanceof Date){
21077 var v = Date.parseDate(value, this.format);
21078 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
21079 v = Date.parseDate(value, 'Y-m-d');
21081 if(!v && this.altFormats){
21082 if(!this.altFormatsArray){
21083 this.altFormatsArray = this.altFormats.split("|");
21085 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
21086 v = Date.parseDate(value, this.altFormatsArray[i]);
21092 formatDate : function(date, fmt)
21094 return (!date || !(date instanceof Date)) ?
21095 date : date.dateFormat(fmt || this.format);
21098 onFocus : function()
21100 Roo.bootstrap.DateField.superclass.onFocus.call(this);
21104 onBlur : function()
21106 Roo.bootstrap.DateField.superclass.onBlur.call(this);
21108 var d = this.inputEl().getValue();
21115 showPopup : function()
21117 this.picker().show();
21121 this.fireEvent('showpopup', this, this.date);
21124 hidePopup : function()
21126 if(this.isInline) {
21129 this.picker().hide();
21130 this.viewMode = this.startViewMode;
21133 this.fireEvent('hidepopup', this, this.date);
21137 onMousedown: function(e)
21139 e.stopPropagation();
21140 e.preventDefault();
21145 Roo.bootstrap.DateField.superclass.keyup.call(this);
21149 setValue: function(v)
21151 if(this.fireEvent('beforeselect', this, v) !== false){
21152 var d = new Date(this.parseDate(v) ).clearTime();
21154 if(isNaN(d.getTime())){
21155 this.date = this.viewDate = '';
21156 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21160 v = this.formatDate(d);
21162 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
21164 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
21168 this.fireEvent('select', this, this.date);
21172 getValue: function()
21174 return this.formatDate(this.date);
21177 fireKey: function(e)
21179 if (!this.picker().isVisible()){
21180 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21186 var dateChanged = false,
21188 newDate, newViewDate;
21193 e.preventDefault();
21197 if (!this.keyboardNavigation) {
21200 dir = e.keyCode == 37 ? -1 : 1;
21203 newDate = this.moveYear(this.date, dir);
21204 newViewDate = this.moveYear(this.viewDate, dir);
21205 } else if (e.shiftKey){
21206 newDate = this.moveMonth(this.date, dir);
21207 newViewDate = this.moveMonth(this.viewDate, dir);
21209 newDate = new Date(this.date);
21210 newDate.setUTCDate(this.date.getUTCDate() + dir);
21211 newViewDate = new Date(this.viewDate);
21212 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
21214 if (this.dateWithinRange(newDate)){
21215 this.date = newDate;
21216 this.viewDate = newViewDate;
21217 this.setValue(this.formatDate(this.date));
21219 e.preventDefault();
21220 dateChanged = true;
21225 if (!this.keyboardNavigation) {
21228 dir = e.keyCode == 38 ? -1 : 1;
21230 newDate = this.moveYear(this.date, dir);
21231 newViewDate = this.moveYear(this.viewDate, dir);
21232 } else if (e.shiftKey){
21233 newDate = this.moveMonth(this.date, dir);
21234 newViewDate = this.moveMonth(this.viewDate, dir);
21236 newDate = new Date(this.date);
21237 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
21238 newViewDate = new Date(this.viewDate);
21239 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
21241 if (this.dateWithinRange(newDate)){
21242 this.date = newDate;
21243 this.viewDate = newViewDate;
21244 this.setValue(this.formatDate(this.date));
21246 e.preventDefault();
21247 dateChanged = true;
21251 this.setValue(this.formatDate(this.date));
21253 e.preventDefault();
21256 this.setValue(this.formatDate(this.date));
21270 onClick: function(e)
21272 e.stopPropagation();
21273 e.preventDefault();
21275 var target = e.getTarget();
21277 if(target.nodeName.toLowerCase() === 'i'){
21278 target = Roo.get(target).dom.parentNode;
21281 var nodeName = target.nodeName;
21282 var className = target.className;
21283 var html = target.innerHTML;
21284 //Roo.log(nodeName);
21286 switch(nodeName.toLowerCase()) {
21288 switch(className) {
21294 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
21295 switch(this.viewMode){
21297 this.viewDate = this.moveMonth(this.viewDate, dir);
21301 this.viewDate = this.moveYear(this.viewDate, dir);
21307 var date = new Date();
21308 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
21310 this.setValue(this.formatDate(this.date));
21317 if (className.indexOf('disabled') < 0) {
21318 this.viewDate.setUTCDate(1);
21319 if (className.indexOf('month') > -1) {
21320 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
21322 var year = parseInt(html, 10) || 0;
21323 this.viewDate.setUTCFullYear(year);
21327 if(this.singleMode){
21328 this.setValue(this.formatDate(this.viewDate));
21339 //Roo.log(className);
21340 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
21341 var day = parseInt(html, 10) || 1;
21342 var year = this.viewDate.getUTCFullYear(),
21343 month = this.viewDate.getUTCMonth();
21345 if (className.indexOf('old') > -1) {
21352 } else if (className.indexOf('new') > -1) {
21360 //Roo.log([year,month,day]);
21361 this.date = this.UTCDate(year, month, day,0,0,0,0);
21362 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
21364 //Roo.log(this.formatDate(this.date));
21365 this.setValue(this.formatDate(this.date));
21372 setStartDate: function(startDate)
21374 this.startDate = startDate || -Infinity;
21375 if (this.startDate !== -Infinity) {
21376 this.startDate = this.parseDate(this.startDate);
21379 this.updateNavArrows();
21382 setEndDate: function(endDate)
21384 this.endDate = endDate || Infinity;
21385 if (this.endDate !== Infinity) {
21386 this.endDate = this.parseDate(this.endDate);
21389 this.updateNavArrows();
21392 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
21394 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
21395 if (typeof(this.daysOfWeekDisabled) !== 'object') {
21396 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
21398 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
21399 return parseInt(d, 10);
21402 this.updateNavArrows();
21405 updateNavArrows: function()
21407 if(this.singleMode){
21411 var d = new Date(this.viewDate),
21412 year = d.getUTCFullYear(),
21413 month = d.getUTCMonth();
21415 Roo.each(this.picker().select('.prev', true).elements, function(v){
21417 switch (this.viewMode) {
21420 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
21426 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
21433 Roo.each(this.picker().select('.next', true).elements, function(v){
21435 switch (this.viewMode) {
21438 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
21444 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
21452 moveMonth: function(date, dir)
21457 var new_date = new Date(date.valueOf()),
21458 day = new_date.getUTCDate(),
21459 month = new_date.getUTCMonth(),
21460 mag = Math.abs(dir),
21462 dir = dir > 0 ? 1 : -1;
21465 // If going back one month, make sure month is not current month
21466 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
21468 return new_date.getUTCMonth() == month;
21470 // If going forward one month, make sure month is as expected
21471 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
21473 return new_date.getUTCMonth() != new_month;
21475 new_month = month + dir;
21476 new_date.setUTCMonth(new_month);
21477 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
21478 if (new_month < 0 || new_month > 11) {
21479 new_month = (new_month + 12) % 12;
21482 // For magnitudes >1, move one month at a time...
21483 for (var i=0; i<mag; i++) {
21484 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
21485 new_date = this.moveMonth(new_date, dir);
21487 // ...then reset the day, keeping it in the new month
21488 new_month = new_date.getUTCMonth();
21489 new_date.setUTCDate(day);
21491 return new_month != new_date.getUTCMonth();
21494 // Common date-resetting loop -- if date is beyond end of month, make it
21497 new_date.setUTCDate(--day);
21498 new_date.setUTCMonth(new_month);
21503 moveYear: function(date, dir)
21505 return this.moveMonth(date, dir*12);
21508 dateWithinRange: function(date)
21510 return date >= this.startDate && date <= this.endDate;
21516 this.picker().remove();
21519 validateValue : function(value)
21521 if(this.getVisibilityEl().hasClass('hidden')){
21525 if(value.length < 1) {
21526 if(this.allowBlank){
21532 if(value.length < this.minLength){
21535 if(value.length > this.maxLength){
21539 var vt = Roo.form.VTypes;
21540 if(!vt[this.vtype](value, this)){
21544 if(typeof this.validator == "function"){
21545 var msg = this.validator(value);
21551 if(this.regex && !this.regex.test(value)){
21555 if(typeof(this.parseDate(value)) == 'undefined'){
21559 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
21563 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
21573 this.date = this.viewDate = '';
21575 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21580 Roo.apply(Roo.bootstrap.DateField, {
21591 html: '<i class="fa fa-arrow-left"/>'
21601 html: '<i class="fa fa-arrow-right"/>'
21643 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
21644 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
21645 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
21646 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21647 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
21660 navFnc: 'FullYear',
21665 navFnc: 'FullYear',
21670 Roo.apply(Roo.bootstrap.DateField, {
21674 cls: 'datepicker dropdown-menu roo-dynamic',
21678 cls: 'datepicker-days',
21682 cls: 'table-condensed',
21684 Roo.bootstrap.DateField.head,
21688 Roo.bootstrap.DateField.footer
21695 cls: 'datepicker-months',
21699 cls: 'table-condensed',
21701 Roo.bootstrap.DateField.head,
21702 Roo.bootstrap.DateField.content,
21703 Roo.bootstrap.DateField.footer
21710 cls: 'datepicker-years',
21714 cls: 'table-condensed',
21716 Roo.bootstrap.DateField.head,
21717 Roo.bootstrap.DateField.content,
21718 Roo.bootstrap.DateField.footer
21737 * @class Roo.bootstrap.TimeField
21738 * @extends Roo.bootstrap.Input
21739 * Bootstrap DateField class
21743 * Create a new TimeField
21744 * @param {Object} config The config object
21747 Roo.bootstrap.TimeField = function(config){
21748 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
21752 * Fires when this field show.
21753 * @param {Roo.bootstrap.DateField} thisthis
21754 * @param {Mixed} date The date value
21759 * Fires when this field hide.
21760 * @param {Roo.bootstrap.DateField} this
21761 * @param {Mixed} date The date value
21766 * Fires when select a date.
21767 * @param {Roo.bootstrap.DateField} this
21768 * @param {Mixed} date The date value
21774 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
21777 * @cfg {String} format
21778 * The default time format string which can be overriden for localization support. The format must be
21779 * valid according to {@link Date#parseDate} (defaults to 'H:i').
21783 onRender: function(ct, position)
21786 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
21788 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
21790 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21792 this.pop = this.picker().select('>.datepicker-time',true).first();
21793 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21795 this.picker().on('mousedown', this.onMousedown, this);
21796 this.picker().on('click', this.onClick, this);
21798 this.picker().addClass('datepicker-dropdown');
21803 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21804 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21805 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21806 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21807 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21808 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21812 fireKey: function(e){
21813 if (!this.picker().isVisible()){
21814 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21820 e.preventDefault();
21828 this.onTogglePeriod();
21831 this.onIncrementMinutes();
21834 this.onDecrementMinutes();
21843 onClick: function(e) {
21844 e.stopPropagation();
21845 e.preventDefault();
21848 picker : function()
21850 return this.el.select('.datepicker', true).first();
21853 fillTime: function()
21855 var time = this.pop.select('tbody', true).first();
21857 time.dom.innerHTML = '';
21872 cls: 'hours-up glyphicon glyphicon-chevron-up'
21892 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21913 cls: 'timepicker-hour',
21928 cls: 'timepicker-minute',
21943 cls: 'btn btn-primary period',
21965 cls: 'hours-down glyphicon glyphicon-chevron-down'
21985 cls: 'minutes-down glyphicon glyphicon-chevron-down'
22003 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
22010 var hours = this.time.getHours();
22011 var minutes = this.time.getMinutes();
22024 hours = hours - 12;
22028 hours = '0' + hours;
22032 minutes = '0' + minutes;
22035 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
22036 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
22037 this.pop.select('button', true).first().dom.innerHTML = period;
22043 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
22045 var cls = ['bottom'];
22047 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
22054 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
22059 this.picker().addClass(cls.join('-'));
22063 Roo.each(cls, function(c){
22065 _this.picker().setTop(_this.inputEl().getHeight());
22069 _this.picker().setTop(0 - _this.picker().getHeight());
22074 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
22078 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
22085 onFocus : function()
22087 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
22091 onBlur : function()
22093 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
22099 this.picker().show();
22104 this.fireEvent('show', this, this.date);
22109 this.picker().hide();
22112 this.fireEvent('hide', this, this.date);
22115 setTime : function()
22118 this.setValue(this.time.format(this.format));
22120 this.fireEvent('select', this, this.date);
22125 onMousedown: function(e){
22126 e.stopPropagation();
22127 e.preventDefault();
22130 onIncrementHours: function()
22132 Roo.log('onIncrementHours');
22133 this.time = this.time.add(Date.HOUR, 1);
22138 onDecrementHours: function()
22140 Roo.log('onDecrementHours');
22141 this.time = this.time.add(Date.HOUR, -1);
22145 onIncrementMinutes: function()
22147 Roo.log('onIncrementMinutes');
22148 this.time = this.time.add(Date.MINUTE, 1);
22152 onDecrementMinutes: function()
22154 Roo.log('onDecrementMinutes');
22155 this.time = this.time.add(Date.MINUTE, -1);
22159 onTogglePeriod: function()
22161 Roo.log('onTogglePeriod');
22162 this.time = this.time.add(Date.HOUR, 12);
22169 Roo.apply(Roo.bootstrap.TimeField, {
22199 cls: 'btn btn-info ok',
22211 Roo.apply(Roo.bootstrap.TimeField, {
22215 cls: 'datepicker dropdown-menu',
22219 cls: 'datepicker-time',
22223 cls: 'table-condensed',
22225 Roo.bootstrap.TimeField.content,
22226 Roo.bootstrap.TimeField.footer
22245 * @class Roo.bootstrap.MonthField
22246 * @extends Roo.bootstrap.Input
22247 * Bootstrap MonthField class
22249 * @cfg {String} language default en
22252 * Create a new MonthField
22253 * @param {Object} config The config object
22256 Roo.bootstrap.MonthField = function(config){
22257 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
22262 * Fires when this field show.
22263 * @param {Roo.bootstrap.MonthField} this
22264 * @param {Mixed} date The date value
22269 * Fires when this field hide.
22270 * @param {Roo.bootstrap.MonthField} this
22271 * @param {Mixed} date The date value
22276 * Fires when select a date.
22277 * @param {Roo.bootstrap.MonthField} this
22278 * @param {String} oldvalue The old value
22279 * @param {String} newvalue The new value
22285 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
22287 onRender: function(ct, position)
22290 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
22292 this.language = this.language || 'en';
22293 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
22294 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
22296 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
22297 this.isInline = false;
22298 this.isInput = true;
22299 this.component = this.el.select('.add-on', true).first() || false;
22300 this.component = (this.component && this.component.length === 0) ? false : this.component;
22301 this.hasInput = this.component && this.inputEL().length;
22303 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
22305 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22307 this.picker().on('mousedown', this.onMousedown, this);
22308 this.picker().on('click', this.onClick, this);
22310 this.picker().addClass('datepicker-dropdown');
22312 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
22313 v.setStyle('width', '189px');
22320 if(this.isInline) {
22326 setValue: function(v, suppressEvent)
22328 var o = this.getValue();
22330 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
22334 if(suppressEvent !== true){
22335 this.fireEvent('select', this, o, v);
22340 getValue: function()
22345 onClick: function(e)
22347 e.stopPropagation();
22348 e.preventDefault();
22350 var target = e.getTarget();
22352 if(target.nodeName.toLowerCase() === 'i'){
22353 target = Roo.get(target).dom.parentNode;
22356 var nodeName = target.nodeName;
22357 var className = target.className;
22358 var html = target.innerHTML;
22360 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
22364 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
22366 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22372 picker : function()
22374 return this.pickerEl;
22377 fillMonths: function()
22380 var months = this.picker().select('>.datepicker-months td', true).first();
22382 months.dom.innerHTML = '';
22388 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
22391 months.createChild(month);
22400 if(typeof(this.vIndex) == 'undefined' && this.value.length){
22401 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
22404 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
22405 e.removeClass('active');
22407 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
22408 e.addClass('active');
22415 if(this.isInline) {
22419 this.picker().removeClass(['bottom', 'top']);
22421 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
22423 * place to the top of element!
22427 this.picker().addClass('top');
22428 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
22433 this.picker().addClass('bottom');
22435 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
22438 onFocus : function()
22440 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
22444 onBlur : function()
22446 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
22448 var d = this.inputEl().getValue();
22457 this.picker().show();
22458 this.picker().select('>.datepicker-months', true).first().show();
22462 this.fireEvent('show', this, this.date);
22467 if(this.isInline) {
22470 this.picker().hide();
22471 this.fireEvent('hide', this, this.date);
22475 onMousedown: function(e)
22477 e.stopPropagation();
22478 e.preventDefault();
22483 Roo.bootstrap.MonthField.superclass.keyup.call(this);
22487 fireKey: function(e)
22489 if (!this.picker().isVisible()){
22490 if (e.keyCode == 27) {// allow escape to hide and re-show picker
22501 e.preventDefault();
22505 dir = e.keyCode == 37 ? -1 : 1;
22507 this.vIndex = this.vIndex + dir;
22509 if(this.vIndex < 0){
22513 if(this.vIndex > 11){
22517 if(isNaN(this.vIndex)){
22521 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22527 dir = e.keyCode == 38 ? -1 : 1;
22529 this.vIndex = this.vIndex + dir * 4;
22531 if(this.vIndex < 0){
22535 if(this.vIndex > 11){
22539 if(isNaN(this.vIndex)){
22543 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22548 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22549 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22553 e.preventDefault();
22556 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22557 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22573 this.picker().remove();
22578 Roo.apply(Roo.bootstrap.MonthField, {
22597 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
22598 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
22603 Roo.apply(Roo.bootstrap.MonthField, {
22607 cls: 'datepicker dropdown-menu roo-dynamic',
22611 cls: 'datepicker-months',
22615 cls: 'table-condensed',
22617 Roo.bootstrap.DateField.content
22637 * @class Roo.bootstrap.CheckBox
22638 * @extends Roo.bootstrap.Input
22639 * Bootstrap CheckBox class
22641 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
22642 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
22643 * @cfg {String} boxLabel The text that appears beside the checkbox
22644 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
22645 * @cfg {Boolean} checked initnal the element
22646 * @cfg {Boolean} inline inline the element (default false)
22647 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
22648 * @cfg {String} tooltip label tooltip
22651 * Create a new CheckBox
22652 * @param {Object} config The config object
22655 Roo.bootstrap.CheckBox = function(config){
22656 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
22661 * Fires when the element is checked or unchecked.
22662 * @param {Roo.bootstrap.CheckBox} this This input
22663 * @param {Boolean} checked The new checked value
22668 * Fires when the element is click.
22669 * @param {Roo.bootstrap.CheckBox} this This input
22676 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
22678 inputType: 'checkbox',
22687 // checkbox success does not make any sense really..
22692 getAutoCreate : function()
22694 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
22700 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
22703 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
22709 type : this.inputType,
22710 value : this.inputValue,
22711 cls : 'roo-' + this.inputType, //'form-box',
22712 placeholder : this.placeholder || ''
22716 if(this.inputType != 'radio'){
22720 cls : 'roo-hidden-value',
22721 value : this.checked ? this.inputValue : this.valueOff
22726 if (this.weight) { // Validity check?
22727 cfg.cls += " " + this.inputType + "-" + this.weight;
22730 if (this.disabled) {
22731 input.disabled=true;
22735 input.checked = this.checked;
22740 input.name = this.name;
22742 if(this.inputType != 'radio'){
22743 hidden.name = this.name;
22744 input.name = '_hidden_' + this.name;
22749 input.cls += ' input-' + this.size;
22754 ['xs','sm','md','lg'].map(function(size){
22755 if (settings[size]) {
22756 cfg.cls += ' col-' + size + '-' + settings[size];
22760 var inputblock = input;
22762 if (this.before || this.after) {
22765 cls : 'input-group',
22770 inputblock.cn.push({
22772 cls : 'input-group-addon',
22777 inputblock.cn.push(input);
22779 if(this.inputType != 'radio'){
22780 inputblock.cn.push(hidden);
22784 inputblock.cn.push({
22786 cls : 'input-group-addon',
22792 var boxLabelCfg = false;
22798 //'for': id, // box label is handled by onclick - so no for...
22800 html: this.boxLabel
22803 boxLabelCfg.tooltip = this.tooltip;
22809 if (align ==='left' && this.fieldLabel.length) {
22810 // Roo.log("left and has label");
22815 cls : 'control-label',
22816 html : this.fieldLabel
22827 cfg.cn[1].cn.push(boxLabelCfg);
22830 if(this.labelWidth > 12){
22831 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22834 if(this.labelWidth < 13 && this.labelmd == 0){
22835 this.labelmd = this.labelWidth;
22838 if(this.labellg > 0){
22839 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22840 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22843 if(this.labelmd > 0){
22844 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22845 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22848 if(this.labelsm > 0){
22849 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22850 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22853 if(this.labelxs > 0){
22854 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22855 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22858 } else if ( this.fieldLabel.length) {
22859 // Roo.log(" label");
22863 tag: this.boxLabel ? 'span' : 'label',
22865 cls: 'control-label box-input-label',
22866 //cls : 'input-group-addon',
22867 html : this.fieldLabel
22874 cfg.cn.push(boxLabelCfg);
22879 // Roo.log(" no label && no align");
22880 cfg.cn = [ inputblock ] ;
22882 cfg.cn.push(boxLabelCfg);
22890 if(this.inputType != 'radio'){
22891 cfg.cn.push(hidden);
22899 * return the real input element.
22901 inputEl: function ()
22903 return this.el.select('input.roo-' + this.inputType,true).first();
22905 hiddenEl: function ()
22907 return this.el.select('input.roo-hidden-value',true).first();
22910 labelEl: function()
22912 return this.el.select('label.control-label',true).first();
22914 /* depricated... */
22918 return this.labelEl();
22921 boxLabelEl: function()
22923 return this.el.select('label.box-label',true).first();
22926 initEvents : function()
22928 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22930 this.inputEl().on('click', this.onClick, this);
22932 if (this.boxLabel) {
22933 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22936 this.startValue = this.getValue();
22939 Roo.bootstrap.CheckBox.register(this);
22943 onClick : function(e)
22945 if(this.fireEvent('click', this, e) !== false){
22946 this.setChecked(!this.checked);
22951 setChecked : function(state,suppressEvent)
22953 this.startValue = this.getValue();
22955 if(this.inputType == 'radio'){
22957 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22958 e.dom.checked = false;
22961 this.inputEl().dom.checked = true;
22963 this.inputEl().dom.value = this.inputValue;
22965 if(suppressEvent !== true){
22966 this.fireEvent('check', this, true);
22974 this.checked = state;
22976 this.inputEl().dom.checked = state;
22979 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22981 if(suppressEvent !== true){
22982 this.fireEvent('check', this, state);
22988 getValue : function()
22990 if(this.inputType == 'radio'){
22991 return this.getGroupValue();
22994 return this.hiddenEl().dom.value;
22998 getGroupValue : function()
23000 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
23004 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
23007 setValue : function(v,suppressEvent)
23009 if(this.inputType == 'radio'){
23010 this.setGroupValue(v, suppressEvent);
23014 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
23019 setGroupValue : function(v, suppressEvent)
23021 this.startValue = this.getValue();
23023 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23024 e.dom.checked = false;
23026 if(e.dom.value == v){
23027 e.dom.checked = true;
23031 if(suppressEvent !== true){
23032 this.fireEvent('check', this, true);
23040 validate : function()
23042 if(this.getVisibilityEl().hasClass('hidden')){
23048 (this.inputType == 'radio' && this.validateRadio()) ||
23049 (this.inputType == 'checkbox' && this.validateCheckbox())
23055 this.markInvalid();
23059 validateRadio : function()
23061 if(this.getVisibilityEl().hasClass('hidden')){
23065 if(this.allowBlank){
23071 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23072 if(!e.dom.checked){
23084 validateCheckbox : function()
23087 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
23088 //return (this.getValue() == this.inputValue) ? true : false;
23091 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23099 for(var i in group){
23100 if(group[i].el.isVisible(true)){
23108 for(var i in group){
23113 r = (group[i].getValue() == group[i].inputValue) ? true : false;
23120 * Mark this field as valid
23122 markValid : function()
23126 this.fireEvent('valid', this);
23128 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23131 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23138 if(this.inputType == 'radio'){
23139 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23140 var fg = e.findParent('.form-group', false, true);
23141 if (Roo.bootstrap.version == 3) {
23142 fg.removeClass([_this.invalidClass, _this.validClass]);
23143 fg.addClass(_this.validClass);
23145 fg.removeClass(['is-valid', 'is-invalid']);
23146 fg.addClass('is-valid');
23154 var fg = this.el.findParent('.form-group', false, true);
23155 if (Roo.bootstrap.version == 3) {
23156 fg.removeClass([this.invalidClass, this.validClass]);
23157 fg.addClass(this.validClass);
23159 fg.removeClass(['is-valid', 'is-invalid']);
23160 fg.addClass('is-valid');
23165 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23171 for(var i in group){
23172 var fg = group[i].el.findParent('.form-group', false, true);
23173 if (Roo.bootstrap.version == 3) {
23174 fg.removeClass([this.invalidClass, this.validClass]);
23175 fg.addClass(this.validClass);
23177 fg.removeClass(['is-valid', 'is-invalid']);
23178 fg.addClass('is-valid');
23184 * Mark this field as invalid
23185 * @param {String} msg The validation message
23187 markInvalid : function(msg)
23189 if(this.allowBlank){
23195 this.fireEvent('invalid', this, msg);
23197 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23200 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23204 label.markInvalid();
23207 if(this.inputType == 'radio'){
23209 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23210 var fg = e.findParent('.form-group', false, true);
23211 if (Roo.bootstrap.version == 3) {
23212 fg.removeClass([_this.invalidClass, _this.validClass]);
23213 fg.addClass(_this.invalidClass);
23215 fg.removeClass(['is-invalid', 'is-valid']);
23216 fg.addClass('is-invalid');
23224 var fg = this.el.findParent('.form-group', false, true);
23225 if (Roo.bootstrap.version == 3) {
23226 fg.removeClass([_this.invalidClass, _this.validClass]);
23227 fg.addClass(_this.invalidClass);
23229 fg.removeClass(['is-invalid', 'is-valid']);
23230 fg.addClass('is-invalid');
23235 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23241 for(var i in group){
23242 var fg = group[i].el.findParent('.form-group', false, true);
23243 if (Roo.bootstrap.version == 3) {
23244 fg.removeClass([_this.invalidClass, _this.validClass]);
23245 fg.addClass(_this.invalidClass);
23247 fg.removeClass(['is-invalid', 'is-valid']);
23248 fg.addClass('is-invalid');
23254 clearInvalid : function()
23256 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
23258 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
23260 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23262 if (label && label.iconEl) {
23263 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
23264 label.iconEl.removeClass(['is-invalid', 'is-valid']);
23268 disable : function()
23270 if(this.inputType != 'radio'){
23271 Roo.bootstrap.CheckBox.superclass.disable.call(this);
23278 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23279 _this.getActionEl().addClass(this.disabledClass);
23280 e.dom.disabled = true;
23284 this.disabled = true;
23285 this.fireEvent("disable", this);
23289 enable : function()
23291 if(this.inputType != 'radio'){
23292 Roo.bootstrap.CheckBox.superclass.enable.call(this);
23299 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23300 _this.getActionEl().removeClass(this.disabledClass);
23301 e.dom.disabled = false;
23305 this.disabled = false;
23306 this.fireEvent("enable", this);
23310 setBoxLabel : function(v)
23315 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23321 Roo.apply(Roo.bootstrap.CheckBox, {
23326 * register a CheckBox Group
23327 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
23329 register : function(checkbox)
23331 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
23332 this.groups[checkbox.groupId] = {};
23335 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
23339 this.groups[checkbox.groupId][checkbox.name] = checkbox;
23343 * fetch a CheckBox Group based on the group ID
23344 * @param {string} the group ID
23345 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
23347 get: function(groupId) {
23348 if (typeof(this.groups[groupId]) == 'undefined') {
23352 return this.groups[groupId] ;
23365 * @class Roo.bootstrap.Radio
23366 * @extends Roo.bootstrap.Component
23367 * Bootstrap Radio class
23368 * @cfg {String} boxLabel - the label associated
23369 * @cfg {String} value - the value of radio
23372 * Create a new Radio
23373 * @param {Object} config The config object
23375 Roo.bootstrap.Radio = function(config){
23376 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
23380 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
23386 getAutoCreate : function()
23390 cls : 'form-group radio',
23395 html : this.boxLabel
23403 initEvents : function()
23405 this.parent().register(this);
23407 this.el.on('click', this.onClick, this);
23411 onClick : function(e)
23413 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
23414 this.setChecked(true);
23418 setChecked : function(state, suppressEvent)
23420 this.parent().setValue(this.value, suppressEvent);
23424 setBoxLabel : function(v)
23429 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23444 * @class Roo.bootstrap.SecurePass
23445 * @extends Roo.bootstrap.Input
23446 * Bootstrap SecurePass class
23450 * Create a new SecurePass
23451 * @param {Object} config The config object
23454 Roo.bootstrap.SecurePass = function (config) {
23455 // these go here, so the translation tool can replace them..
23457 PwdEmpty: "Please type a password, and then retype it to confirm.",
23458 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23459 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23460 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23461 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23462 FNInPwd: "Your password can't contain your first name. Please type a different password.",
23463 LNInPwd: "Your password can't contain your last name. Please type a different password.",
23464 TooWeak: "Your password is Too Weak."
23466 this.meterLabel = "Password strength:";
23467 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
23468 this.meterClass = [
23469 "roo-password-meter-tooweak",
23470 "roo-password-meter-weak",
23471 "roo-password-meter-medium",
23472 "roo-password-meter-strong",
23473 "roo-password-meter-grey"
23478 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
23481 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
23483 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
23485 * PwdEmpty: "Please type a password, and then retype it to confirm.",
23486 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23487 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23488 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23489 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23490 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
23491 * LNInPwd: "Your password can't contain your last name. Please type a different password."
23501 * @cfg {String/Object} Label for the strength meter (defaults to
23502 * 'Password strength:')
23507 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
23508 * ['Weak', 'Medium', 'Strong'])
23511 pwdStrengths: false,
23524 initEvents: function ()
23526 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
23528 if (this.el.is('input[type=password]') && Roo.isSafari) {
23529 this.el.on('keydown', this.SafariOnKeyDown, this);
23532 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
23535 onRender: function (ct, position)
23537 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
23538 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
23539 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
23541 this.trigger.createChild({
23546 cls: 'roo-password-meter-grey col-xs-12',
23549 //width: this.meterWidth + 'px'
23553 cls: 'roo-password-meter-text'
23559 if (this.hideTrigger) {
23560 this.trigger.setDisplayed(false);
23562 this.setSize(this.width || '', this.height || '');
23565 onDestroy: function ()
23567 if (this.trigger) {
23568 this.trigger.removeAllListeners();
23569 this.trigger.remove();
23572 this.wrap.remove();
23574 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
23577 checkStrength: function ()
23579 var pwd = this.inputEl().getValue();
23580 if (pwd == this._lastPwd) {
23585 if (this.ClientSideStrongPassword(pwd)) {
23587 } else if (this.ClientSideMediumPassword(pwd)) {
23589 } else if (this.ClientSideWeakPassword(pwd)) {
23595 Roo.log('strength1: ' + strength);
23597 //var pm = this.trigger.child('div/div/div').dom;
23598 var pm = this.trigger.child('div/div');
23599 pm.removeClass(this.meterClass);
23600 pm.addClass(this.meterClass[strength]);
23603 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23605 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23607 this._lastPwd = pwd;
23611 Roo.bootstrap.SecurePass.superclass.reset.call(this);
23613 this._lastPwd = '';
23615 var pm = this.trigger.child('div/div');
23616 pm.removeClass(this.meterClass);
23617 pm.addClass('roo-password-meter-grey');
23620 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23623 this.inputEl().dom.type='password';
23626 validateValue: function (value)
23628 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
23631 if (value.length == 0) {
23632 if (this.allowBlank) {
23633 this.clearInvalid();
23637 this.markInvalid(this.errors.PwdEmpty);
23638 this.errorMsg = this.errors.PwdEmpty;
23646 if (!value.match(/[\x21-\x7e]+/)) {
23647 this.markInvalid(this.errors.PwdBadChar);
23648 this.errorMsg = this.errors.PwdBadChar;
23651 if (value.length < 6) {
23652 this.markInvalid(this.errors.PwdShort);
23653 this.errorMsg = this.errors.PwdShort;
23656 if (value.length > 16) {
23657 this.markInvalid(this.errors.PwdLong);
23658 this.errorMsg = this.errors.PwdLong;
23662 if (this.ClientSideStrongPassword(value)) {
23664 } else if (this.ClientSideMediumPassword(value)) {
23666 } else if (this.ClientSideWeakPassword(value)) {
23673 if (strength < 2) {
23674 //this.markInvalid(this.errors.TooWeak);
23675 this.errorMsg = this.errors.TooWeak;
23680 console.log('strength2: ' + strength);
23682 //var pm = this.trigger.child('div/div/div').dom;
23684 var pm = this.trigger.child('div/div');
23685 pm.removeClass(this.meterClass);
23686 pm.addClass(this.meterClass[strength]);
23688 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23690 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23692 this.errorMsg = '';
23696 CharacterSetChecks: function (type)
23699 this.fResult = false;
23702 isctype: function (character, type)
23705 case this.kCapitalLetter:
23706 if (character >= 'A' && character <= 'Z') {
23711 case this.kSmallLetter:
23712 if (character >= 'a' && character <= 'z') {
23718 if (character >= '0' && character <= '9') {
23723 case this.kPunctuation:
23724 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
23735 IsLongEnough: function (pwd, size)
23737 return !(pwd == null || isNaN(size) || pwd.length < size);
23740 SpansEnoughCharacterSets: function (word, nb)
23742 if (!this.IsLongEnough(word, nb))
23747 var characterSetChecks = new Array(
23748 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
23749 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
23752 for (var index = 0; index < word.length; ++index) {
23753 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23754 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
23755 characterSetChecks[nCharSet].fResult = true;
23762 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23763 if (characterSetChecks[nCharSet].fResult) {
23768 if (nCharSets < nb) {
23774 ClientSideStrongPassword: function (pwd)
23776 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
23779 ClientSideMediumPassword: function (pwd)
23781 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
23784 ClientSideWeakPassword: function (pwd)
23786 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
23789 })//<script type="text/javascript">
23792 * Based Ext JS Library 1.1.1
23793 * Copyright(c) 2006-2007, Ext JS, LLC.
23799 * @class Roo.HtmlEditorCore
23800 * @extends Roo.Component
23801 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23803 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23806 Roo.HtmlEditorCore = function(config){
23809 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23814 * @event initialize
23815 * Fires when the editor is fully initialized (including the iframe)
23816 * @param {Roo.HtmlEditorCore} this
23821 * Fires when the editor is first receives the focus. Any insertion must wait
23822 * until after this event.
23823 * @param {Roo.HtmlEditorCore} this
23827 * @event beforesync
23828 * Fires before the textarea is updated with content from the editor iframe. Return false
23829 * to cancel the sync.
23830 * @param {Roo.HtmlEditorCore} this
23831 * @param {String} html
23835 * @event beforepush
23836 * Fires before the iframe editor is updated with content from the textarea. Return false
23837 * to cancel the push.
23838 * @param {Roo.HtmlEditorCore} this
23839 * @param {String} html
23844 * Fires when the textarea is updated with content from the editor iframe.
23845 * @param {Roo.HtmlEditorCore} this
23846 * @param {String} html
23851 * Fires when the iframe editor is updated with content from the textarea.
23852 * @param {Roo.HtmlEditorCore} this
23853 * @param {String} html
23858 * @event editorevent
23859 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23860 * @param {Roo.HtmlEditorCore} this
23866 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23868 // defaults : white / black...
23869 this.applyBlacklists();
23876 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23880 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23886 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23891 * @cfg {Number} height (in pixels)
23895 * @cfg {Number} width (in pixels)
23900 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23903 stylesheets: false,
23908 // private properties
23909 validationEvent : false,
23911 initialized : false,
23913 sourceEditMode : false,
23914 onFocus : Roo.emptyFn,
23916 hideMode:'offsets',
23920 // blacklist + whitelisted elements..
23927 * Protected method that will not generally be called directly. It
23928 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23929 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23931 getDocMarkup : function(){
23935 // inherit styels from page...??
23936 if (this.stylesheets === false) {
23938 Roo.get(document.head).select('style').each(function(node) {
23939 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23942 Roo.get(document.head).select('link').each(function(node) {
23943 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23946 } else if (!this.stylesheets.length) {
23948 st = '<style type="text/css">' +
23949 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23952 for (var i in this.stylesheets) {
23953 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
23958 st += '<style type="text/css">' +
23959 'IMG { cursor: pointer } ' +
23962 var cls = 'roo-htmleditor-body';
23964 if(this.bodyCls.length){
23965 cls += ' ' + this.bodyCls;
23968 return '<html><head>' + st +
23969 //<style type="text/css">' +
23970 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23972 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23976 onRender : function(ct, position)
23979 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23980 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23983 this.el.dom.style.border = '0 none';
23984 this.el.dom.setAttribute('tabIndex', -1);
23985 this.el.addClass('x-hidden hide');
23989 if(Roo.isIE){ // fix IE 1px bogus margin
23990 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23994 this.frameId = Roo.id();
23998 var iframe = this.owner.wrap.createChild({
24000 cls: 'form-control', // bootstrap..
24002 name: this.frameId,
24003 frameBorder : 'no',
24004 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24009 this.iframe = iframe.dom;
24011 this.assignDocWin();
24013 this.doc.designMode = 'on';
24016 this.doc.write(this.getDocMarkup());
24020 var task = { // must defer to wait for browser to be ready
24022 //console.log("run task?" + this.doc.readyState);
24023 this.assignDocWin();
24024 if(this.doc.body || this.doc.readyState == 'complete'){
24026 this.doc.designMode="on";
24030 Roo.TaskMgr.stop(task);
24031 this.initEditor.defer(10, this);
24038 Roo.TaskMgr.start(task);
24043 onResize : function(w, h)
24045 Roo.log('resize: ' +w + ',' + h );
24046 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
24050 if(typeof w == 'number'){
24052 this.iframe.style.width = w + 'px';
24054 if(typeof h == 'number'){
24056 this.iframe.style.height = h + 'px';
24058 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
24065 * Toggles the editor between standard and source edit mode.
24066 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24068 toggleSourceEdit : function(sourceEditMode){
24070 this.sourceEditMode = sourceEditMode === true;
24072 if(this.sourceEditMode){
24074 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
24077 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
24078 //this.iframe.className = '';
24081 //this.setSize(this.owner.wrap.getSize());
24082 //this.fireEvent('editmodechange', this, this.sourceEditMode);
24089 * Protected method that will not generally be called directly. If you need/want
24090 * custom HTML cleanup, this is the method you should override.
24091 * @param {String} html The HTML to be cleaned
24092 * return {String} The cleaned HTML
24094 cleanHtml : function(html){
24095 html = String(html);
24096 if(html.length > 5){
24097 if(Roo.isSafari){ // strip safari nonsense
24098 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24101 if(html == ' '){
24108 * HTML Editor -> Textarea
24109 * Protected method that will not generally be called directly. Syncs the contents
24110 * of the editor iframe with the textarea.
24112 syncValue : function(){
24113 if(this.initialized){
24114 var bd = (this.doc.body || this.doc.documentElement);
24115 //this.cleanUpPaste(); -- this is done else where and causes havoc..
24116 var html = bd.innerHTML;
24118 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24119 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
24121 html = '<div style="'+m[0]+'">' + html + '</div>';
24124 html = this.cleanHtml(html);
24125 // fix up the special chars.. normaly like back quotes in word...
24126 // however we do not want to do this with chinese..
24127 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
24129 var cc = match.charCodeAt();
24131 // Get the character value, handling surrogate pairs
24132 if (match.length == 2) {
24133 // It's a surrogate pair, calculate the Unicode code point
24134 var high = match.charCodeAt(0) - 0xD800;
24135 var low = match.charCodeAt(1) - 0xDC00;
24136 cc = (high * 0x400) + low + 0x10000;
24138 (cc >= 0x4E00 && cc < 0xA000 ) ||
24139 (cc >= 0x3400 && cc < 0x4E00 ) ||
24140 (cc >= 0xf900 && cc < 0xfb00 )
24145 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
24146 return "&#" + cc + ";";
24153 if(this.owner.fireEvent('beforesync', this, html) !== false){
24154 this.el.dom.value = html;
24155 this.owner.fireEvent('sync', this, html);
24161 * Protected method that will not generally be called directly. Pushes the value of the textarea
24162 * into the iframe editor.
24164 pushValue : function(){
24165 if(this.initialized){
24166 var v = this.el.dom.value.trim();
24168 // if(v.length < 1){
24172 if(this.owner.fireEvent('beforepush', this, v) !== false){
24173 var d = (this.doc.body || this.doc.documentElement);
24175 this.cleanUpPaste();
24176 this.el.dom.value = d.innerHTML;
24177 this.owner.fireEvent('push', this, v);
24183 deferFocus : function(){
24184 this.focus.defer(10, this);
24188 focus : function(){
24189 if(this.win && !this.sourceEditMode){
24196 assignDocWin: function()
24198 var iframe = this.iframe;
24201 this.doc = iframe.contentWindow.document;
24202 this.win = iframe.contentWindow;
24204 // if (!Roo.get(this.frameId)) {
24207 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24208 // this.win = Roo.get(this.frameId).dom.contentWindow;
24210 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
24214 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24215 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
24220 initEditor : function(){
24221 //console.log("INIT EDITOR");
24222 this.assignDocWin();
24226 this.doc.designMode="on";
24228 this.doc.write(this.getDocMarkup());
24231 var dbody = (this.doc.body || this.doc.documentElement);
24232 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24233 // this copies styles from the containing element into thsi one..
24234 // not sure why we need all of this..
24235 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24237 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
24238 //ss['background-attachment'] = 'fixed'; // w3c
24239 dbody.bgProperties = 'fixed'; // ie
24240 //Roo.DomHelper.applyStyles(dbody, ss);
24241 Roo.EventManager.on(this.doc, {
24242 //'mousedown': this.onEditorEvent,
24243 'mouseup': this.onEditorEvent,
24244 'dblclick': this.onEditorEvent,
24245 'click': this.onEditorEvent,
24246 'keyup': this.onEditorEvent,
24251 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24253 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24254 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24256 this.initialized = true;
24258 this.owner.fireEvent('initialize', this);
24263 onDestroy : function(){
24269 //for (var i =0; i < this.toolbars.length;i++) {
24270 // // fixme - ask toolbars for heights?
24271 // this.toolbars[i].onDestroy();
24274 //this.wrap.dom.innerHTML = '';
24275 //this.wrap.remove();
24280 onFirstFocus : function(){
24282 this.assignDocWin();
24285 this.activated = true;
24288 if(Roo.isGecko){ // prevent silly gecko errors
24290 var s = this.win.getSelection();
24291 if(!s.focusNode || s.focusNode.nodeType != 3){
24292 var r = s.getRangeAt(0);
24293 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24298 this.execCmd('useCSS', true);
24299 this.execCmd('styleWithCSS', false);
24302 this.owner.fireEvent('activate', this);
24306 adjustFont: function(btn){
24307 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24308 //if(Roo.isSafari){ // safari
24311 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24312 if(Roo.isSafari){ // safari
24313 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24314 v = (v < 10) ? 10 : v;
24315 v = (v > 48) ? 48 : v;
24316 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24321 v = Math.max(1, v+adjust);
24323 this.execCmd('FontSize', v );
24326 onEditorEvent : function(e)
24328 this.owner.fireEvent('editorevent', this, e);
24329 // this.updateToolbar();
24330 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
24333 insertTag : function(tg)
24335 // could be a bit smarter... -> wrap the current selected tRoo..
24336 if (tg.toLowerCase() == 'span' ||
24337 tg.toLowerCase() == 'code' ||
24338 tg.toLowerCase() == 'sup' ||
24339 tg.toLowerCase() == 'sub'
24342 range = this.createRange(this.getSelection());
24343 var wrappingNode = this.doc.createElement(tg.toLowerCase());
24344 wrappingNode.appendChild(range.extractContents());
24345 range.insertNode(wrappingNode);
24352 this.execCmd("formatblock", tg);
24356 insertText : function(txt)
24360 var range = this.createRange();
24361 range.deleteContents();
24362 //alert(Sender.getAttribute('label'));
24364 range.insertNode(this.doc.createTextNode(txt));
24370 * Executes a Midas editor command on the editor document and performs necessary focus and
24371 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24372 * @param {String} cmd The Midas command
24373 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24375 relayCmd : function(cmd, value){
24377 this.execCmd(cmd, value);
24378 this.owner.fireEvent('editorevent', this);
24379 //this.updateToolbar();
24380 this.owner.deferFocus();
24384 * Executes a Midas editor command directly on the editor document.
24385 * For visual commands, you should use {@link #relayCmd} instead.
24386 * <b>This should only be called after the editor is initialized.</b>
24387 * @param {String} cmd The Midas command
24388 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24390 execCmd : function(cmd, value){
24391 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24398 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24400 * @param {String} text | dom node..
24402 insertAtCursor : function(text)
24405 if(!this.activated){
24411 var r = this.doc.selection.createRange();
24422 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24426 // from jquery ui (MIT licenced)
24428 var win = this.win;
24430 if (win.getSelection && win.getSelection().getRangeAt) {
24431 range = win.getSelection().getRangeAt(0);
24432 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
24433 range.insertNode(node);
24434 } else if (win.document.selection && win.document.selection.createRange) {
24435 // no firefox support
24436 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24437 win.document.selection.createRange().pasteHTML(txt);
24439 // no firefox support
24440 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24441 this.execCmd('InsertHTML', txt);
24450 mozKeyPress : function(e){
24452 var c = e.getCharCode(), cmd;
24455 c = String.fromCharCode(c).toLowerCase();
24469 this.cleanUpPaste.defer(100, this);
24477 e.preventDefault();
24485 fixKeys : function(){ // load time branching for fastest keydown performance
24487 return function(e){
24488 var k = e.getKey(), r;
24491 r = this.doc.selection.createRange();
24494 r.pasteHTML('    ');
24501 r = this.doc.selection.createRange();
24503 var target = r.parentElement();
24504 if(!target || target.tagName.toLowerCase() != 'li'){
24506 r.pasteHTML('<br />');
24512 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24513 this.cleanUpPaste.defer(100, this);
24519 }else if(Roo.isOpera){
24520 return function(e){
24521 var k = e.getKey();
24525 this.execCmd('InsertHTML','    ');
24528 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24529 this.cleanUpPaste.defer(100, this);
24534 }else if(Roo.isSafari){
24535 return function(e){
24536 var k = e.getKey();
24540 this.execCmd('InsertText','\t');
24544 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24545 this.cleanUpPaste.defer(100, this);
24553 getAllAncestors: function()
24555 var p = this.getSelectedNode();
24558 a.push(p); // push blank onto stack..
24559 p = this.getParentElement();
24563 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24567 a.push(this.doc.body);
24571 lastSelNode : false,
24574 getSelection : function()
24576 this.assignDocWin();
24577 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24580 getSelectedNode: function()
24582 // this may only work on Gecko!!!
24584 // should we cache this!!!!
24589 var range = this.createRange(this.getSelection()).cloneRange();
24592 var parent = range.parentElement();
24594 var testRange = range.duplicate();
24595 testRange.moveToElementText(parent);
24596 if (testRange.inRange(range)) {
24599 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24602 parent = parent.parentElement;
24607 // is ancestor a text element.
24608 var ac = range.commonAncestorContainer;
24609 if (ac.nodeType == 3) {
24610 ac = ac.parentNode;
24613 var ar = ac.childNodes;
24616 var other_nodes = [];
24617 var has_other_nodes = false;
24618 for (var i=0;i<ar.length;i++) {
24619 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24622 // fullly contained node.
24624 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24629 // probably selected..
24630 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24631 other_nodes.push(ar[i]);
24635 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24640 has_other_nodes = true;
24642 if (!nodes.length && other_nodes.length) {
24643 nodes= other_nodes;
24645 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24651 createRange: function(sel)
24653 // this has strange effects when using with
24654 // top toolbar - not sure if it's a great idea.
24655 //this.editor.contentWindow.focus();
24656 if (typeof sel != "undefined") {
24658 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24660 return this.doc.createRange();
24663 return this.doc.createRange();
24666 getParentElement: function()
24669 this.assignDocWin();
24670 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24672 var range = this.createRange(sel);
24675 var p = range.commonAncestorContainer;
24676 while (p.nodeType == 3) { // text node
24687 * Range intersection.. the hard stuff...
24691 * [ -- selected range --- ]
24695 * if end is before start or hits it. fail.
24696 * if start is after end or hits it fail.
24698 * if either hits (but other is outside. - then it's not
24704 // @see http://www.thismuchiknow.co.uk/?p=64.
24705 rangeIntersectsNode : function(range, node)
24707 var nodeRange = node.ownerDocument.createRange();
24709 nodeRange.selectNode(node);
24711 nodeRange.selectNodeContents(node);
24714 var rangeStartRange = range.cloneRange();
24715 rangeStartRange.collapse(true);
24717 var rangeEndRange = range.cloneRange();
24718 rangeEndRange.collapse(false);
24720 var nodeStartRange = nodeRange.cloneRange();
24721 nodeStartRange.collapse(true);
24723 var nodeEndRange = nodeRange.cloneRange();
24724 nodeEndRange.collapse(false);
24726 return rangeStartRange.compareBoundaryPoints(
24727 Range.START_TO_START, nodeEndRange) == -1 &&
24728 rangeEndRange.compareBoundaryPoints(
24729 Range.START_TO_START, nodeStartRange) == 1;
24733 rangeCompareNode : function(range, node)
24735 var nodeRange = node.ownerDocument.createRange();
24737 nodeRange.selectNode(node);
24739 nodeRange.selectNodeContents(node);
24743 range.collapse(true);
24745 nodeRange.collapse(true);
24747 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
24748 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
24750 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
24752 var nodeIsBefore = ss == 1;
24753 var nodeIsAfter = ee == -1;
24755 if (nodeIsBefore && nodeIsAfter) {
24758 if (!nodeIsBefore && nodeIsAfter) {
24759 return 1; //right trailed.
24762 if (nodeIsBefore && !nodeIsAfter) {
24763 return 2; // left trailed.
24769 // private? - in a new class?
24770 cleanUpPaste : function()
24772 // cleans up the whole document..
24773 Roo.log('cleanuppaste');
24775 this.cleanUpChildren(this.doc.body);
24776 var clean = this.cleanWordChars(this.doc.body.innerHTML);
24777 if (clean != this.doc.body.innerHTML) {
24778 this.doc.body.innerHTML = clean;
24783 cleanWordChars : function(input) {// change the chars to hex code
24784 var he = Roo.HtmlEditorCore;
24786 var output = input;
24787 Roo.each(he.swapCodes, function(sw) {
24788 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
24790 output = output.replace(swapper, sw[1]);
24797 cleanUpChildren : function (n)
24799 if (!n.childNodes.length) {
24802 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24803 this.cleanUpChild(n.childNodes[i]);
24810 cleanUpChild : function (node)
24813 //console.log(node);
24814 if (node.nodeName == "#text") {
24815 // clean up silly Windows -- stuff?
24818 if (node.nodeName == "#comment") {
24819 node.parentNode.removeChild(node);
24820 // clean up silly Windows -- stuff?
24823 var lcname = node.tagName.toLowerCase();
24824 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24825 // whitelist of tags..
24827 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24829 node.parentNode.removeChild(node);
24834 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24836 // spans with no attributes - just remove them..
24837 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24838 remove_keep_children = true;
24841 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24842 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24844 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24845 // remove_keep_children = true;
24848 if (remove_keep_children) {
24849 this.cleanUpChildren(node);
24850 // inserts everything just before this node...
24851 while (node.childNodes.length) {
24852 var cn = node.childNodes[0];
24853 node.removeChild(cn);
24854 node.parentNode.insertBefore(cn, node);
24856 node.parentNode.removeChild(node);
24860 if (!node.attributes || !node.attributes.length) {
24865 this.cleanUpChildren(node);
24869 function cleanAttr(n,v)
24872 if (v.match(/^\./) || v.match(/^\//)) {
24875 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24878 if (v.match(/^#/)) {
24881 if (v.match(/^\{/)) { // allow template editing.
24884 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24885 node.removeAttribute(n);
24889 var cwhite = this.cwhite;
24890 var cblack = this.cblack;
24892 function cleanStyle(n,v)
24894 if (v.match(/expression/)) { //XSS?? should we even bother..
24895 node.removeAttribute(n);
24899 var parts = v.split(/;/);
24902 Roo.each(parts, function(p) {
24903 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24907 var l = p.split(':').shift().replace(/\s+/g,'');
24908 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24910 if ( cwhite.length && cblack.indexOf(l) > -1) {
24911 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24912 //node.removeAttribute(n);
24916 // only allow 'c whitelisted system attributes'
24917 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24918 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24919 //node.removeAttribute(n);
24929 if (clean.length) {
24930 node.setAttribute(n, clean.join(';'));
24932 node.removeAttribute(n);
24938 for (var i = node.attributes.length-1; i > -1 ; i--) {
24939 var a = node.attributes[i];
24942 if (a.name.toLowerCase().substr(0,2)=='on') {
24943 node.removeAttribute(a.name);
24946 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24947 node.removeAttribute(a.name);
24950 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24951 cleanAttr(a.name,a.value); // fixme..
24954 if (a.name == 'style') {
24955 cleanStyle(a.name,a.value);
24958 /// clean up MS crap..
24959 // tecnically this should be a list of valid class'es..
24962 if (a.name == 'class') {
24963 if (a.value.match(/^Mso/)) {
24964 node.removeAttribute('class');
24967 if (a.value.match(/^body$/)) {
24968 node.removeAttribute('class');
24979 this.cleanUpChildren(node);
24985 * Clean up MS wordisms...
24987 cleanWord : function(node)
24990 this.cleanWord(this.doc.body);
24995 node.nodeName == 'SPAN' &&
24996 !node.hasAttributes() &&
24997 node.childNodes.length == 1 &&
24998 node.firstChild.nodeName == "#text"
25000 var textNode = node.firstChild;
25001 node.removeChild(textNode);
25002 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
25003 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
25005 node.parentNode.insertBefore(textNode, node);
25006 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
25007 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
25009 node.parentNode.removeChild(node);
25012 if (node.nodeName == "#text") {
25013 // clean up silly Windows -- stuff?
25016 if (node.nodeName == "#comment") {
25017 node.parentNode.removeChild(node);
25018 // clean up silly Windows -- stuff?
25022 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
25023 node.parentNode.removeChild(node);
25026 //Roo.log(node.tagName);
25027 // remove - but keep children..
25028 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
25029 //Roo.log('-- removed');
25030 while (node.childNodes.length) {
25031 var cn = node.childNodes[0];
25032 node.removeChild(cn);
25033 node.parentNode.insertBefore(cn, node);
25034 // move node to parent - and clean it..
25035 this.cleanWord(cn);
25037 node.parentNode.removeChild(node);
25038 /// no need to iterate chidlren = it's got none..
25039 //this.iterateChildren(node, this.cleanWord);
25043 if (node.className.length) {
25045 var cn = node.className.split(/\W+/);
25047 Roo.each(cn, function(cls) {
25048 if (cls.match(/Mso[a-zA-Z]+/)) {
25053 node.className = cna.length ? cna.join(' ') : '';
25055 node.removeAttribute("class");
25059 if (node.hasAttribute("lang")) {
25060 node.removeAttribute("lang");
25063 if (node.hasAttribute("style")) {
25065 var styles = node.getAttribute("style").split(";");
25067 Roo.each(styles, function(s) {
25068 if (!s.match(/:/)) {
25071 var kv = s.split(":");
25072 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
25075 // what ever is left... we allow.
25078 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25079 if (!nstyle.length) {
25080 node.removeAttribute('style');
25083 this.iterateChildren(node, this.cleanWord);
25089 * iterateChildren of a Node, calling fn each time, using this as the scole..
25090 * @param {DomNode} node node to iterate children of.
25091 * @param {Function} fn method of this class to call on each item.
25093 iterateChildren : function(node, fn)
25095 if (!node.childNodes.length) {
25098 for (var i = node.childNodes.length-1; i > -1 ; i--) {
25099 fn.call(this, node.childNodes[i])
25105 * cleanTableWidths.
25107 * Quite often pasting from word etc.. results in tables with column and widths.
25108 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
25111 cleanTableWidths : function(node)
25116 this.cleanTableWidths(this.doc.body);
25121 if (node.nodeName == "#text" || node.nodeName == "#comment") {
25124 Roo.log(node.tagName);
25125 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
25126 this.iterateChildren(node, this.cleanTableWidths);
25129 if (node.hasAttribute('width')) {
25130 node.removeAttribute('width');
25134 if (node.hasAttribute("style")) {
25137 var styles = node.getAttribute("style").split(";");
25139 Roo.each(styles, function(s) {
25140 if (!s.match(/:/)) {
25143 var kv = s.split(":");
25144 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
25147 // what ever is left... we allow.
25150 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25151 if (!nstyle.length) {
25152 node.removeAttribute('style');
25156 this.iterateChildren(node, this.cleanTableWidths);
25164 domToHTML : function(currentElement, depth, nopadtext) {
25166 depth = depth || 0;
25167 nopadtext = nopadtext || false;
25169 if (!currentElement) {
25170 return this.domToHTML(this.doc.body);
25173 //Roo.log(currentElement);
25175 var allText = false;
25176 var nodeName = currentElement.nodeName;
25177 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
25179 if (nodeName == '#text') {
25181 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
25186 if (nodeName != 'BODY') {
25189 // Prints the node tagName, such as <A>, <IMG>, etc
25192 for(i = 0; i < currentElement.attributes.length;i++) {
25194 var aname = currentElement.attributes.item(i).name;
25195 if (!currentElement.attributes.item(i).value.length) {
25198 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
25201 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
25210 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
25213 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
25218 // Traverse the tree
25220 var currentElementChild = currentElement.childNodes.item(i);
25221 var allText = true;
25222 var innerHTML = '';
25224 while (currentElementChild) {
25225 // Formatting code (indent the tree so it looks nice on the screen)
25226 var nopad = nopadtext;
25227 if (lastnode == 'SPAN') {
25231 if (currentElementChild.nodeName == '#text') {
25232 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
25233 toadd = nopadtext ? toadd : toadd.trim();
25234 if (!nopad && toadd.length > 80) {
25235 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
25237 innerHTML += toadd;
25240 currentElementChild = currentElement.childNodes.item(i);
25246 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
25248 // Recursively traverse the tree structure of the child node
25249 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
25250 lastnode = currentElementChild.nodeName;
25252 currentElementChild=currentElement.childNodes.item(i);
25258 // The remaining code is mostly for formatting the tree
25259 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
25264 ret+= "</"+tagName+">";
25270 applyBlacklists : function()
25272 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
25273 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
25277 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
25278 if (b.indexOf(tag) > -1) {
25281 this.white.push(tag);
25285 Roo.each(w, function(tag) {
25286 if (b.indexOf(tag) > -1) {
25289 if (this.white.indexOf(tag) > -1) {
25292 this.white.push(tag);
25297 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
25298 if (w.indexOf(tag) > -1) {
25301 this.black.push(tag);
25305 Roo.each(b, function(tag) {
25306 if (w.indexOf(tag) > -1) {
25309 if (this.black.indexOf(tag) > -1) {
25312 this.black.push(tag);
25317 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
25318 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
25322 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
25323 if (b.indexOf(tag) > -1) {
25326 this.cwhite.push(tag);
25330 Roo.each(w, function(tag) {
25331 if (b.indexOf(tag) > -1) {
25334 if (this.cwhite.indexOf(tag) > -1) {
25337 this.cwhite.push(tag);
25342 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
25343 if (w.indexOf(tag) > -1) {
25346 this.cblack.push(tag);
25350 Roo.each(b, function(tag) {
25351 if (w.indexOf(tag) > -1) {
25354 if (this.cblack.indexOf(tag) > -1) {
25357 this.cblack.push(tag);
25362 setStylesheets : function(stylesheets)
25364 if(typeof(stylesheets) == 'string'){
25365 Roo.get(this.iframe.contentDocument.head).createChild({
25367 rel : 'stylesheet',
25376 Roo.each(stylesheets, function(s) {
25381 Roo.get(_this.iframe.contentDocument.head).createChild({
25383 rel : 'stylesheet',
25392 removeStylesheets : function()
25396 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
25401 setStyle : function(style)
25403 Roo.get(this.iframe.contentDocument.head).createChild({
25412 // hide stuff that is not compatible
25426 * @event specialkey
25430 * @cfg {String} fieldClass @hide
25433 * @cfg {String} focusClass @hide
25436 * @cfg {String} autoCreate @hide
25439 * @cfg {String} inputType @hide
25442 * @cfg {String} invalidClass @hide
25445 * @cfg {String} invalidText @hide
25448 * @cfg {String} msgFx @hide
25451 * @cfg {String} validateOnBlur @hide
25455 Roo.HtmlEditorCore.white = [
25456 'area', 'br', 'img', 'input', 'hr', 'wbr',
25458 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
25459 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
25460 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
25461 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
25462 'table', 'ul', 'xmp',
25464 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
25467 'dir', 'menu', 'ol', 'ul', 'dl',
25473 Roo.HtmlEditorCore.black = [
25474 // 'embed', 'object', // enable - backend responsiblity to clean thiese
25476 'base', 'basefont', 'bgsound', 'blink', 'body',
25477 'frame', 'frameset', 'head', 'html', 'ilayer',
25478 'iframe', 'layer', 'link', 'meta', 'object',
25479 'script', 'style' ,'title', 'xml' // clean later..
25481 Roo.HtmlEditorCore.clean = [
25482 'script', 'style', 'title', 'xml'
25484 Roo.HtmlEditorCore.remove = [
25489 Roo.HtmlEditorCore.ablack = [
25493 Roo.HtmlEditorCore.aclean = [
25494 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
25498 Roo.HtmlEditorCore.pwhite= [
25499 'http', 'https', 'mailto'
25502 // white listed style attributes.
25503 Roo.HtmlEditorCore.cwhite= [
25504 // 'text-align', /// default is to allow most things..
25510 // black listed style attributes.
25511 Roo.HtmlEditorCore.cblack= [
25512 // 'font-size' -- this can be set by the project
25516 Roo.HtmlEditorCore.swapCodes =[
25535 * @class Roo.bootstrap.HtmlEditor
25536 * @extends Roo.bootstrap.TextArea
25537 * Bootstrap HtmlEditor class
25540 * Create a new HtmlEditor
25541 * @param {Object} config The config object
25544 Roo.bootstrap.HtmlEditor = function(config){
25545 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
25546 if (!this.toolbars) {
25547 this.toolbars = [];
25550 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
25553 * @event initialize
25554 * Fires when the editor is fully initialized (including the iframe)
25555 * @param {HtmlEditor} this
25560 * Fires when the editor is first receives the focus. Any insertion must wait
25561 * until after this event.
25562 * @param {HtmlEditor} this
25566 * @event beforesync
25567 * Fires before the textarea is updated with content from the editor iframe. Return false
25568 * to cancel the sync.
25569 * @param {HtmlEditor} this
25570 * @param {String} html
25574 * @event beforepush
25575 * Fires before the iframe editor is updated with content from the textarea. Return false
25576 * to cancel the push.
25577 * @param {HtmlEditor} this
25578 * @param {String} html
25583 * Fires when the textarea is updated with content from the editor iframe.
25584 * @param {HtmlEditor} this
25585 * @param {String} html
25590 * Fires when the iframe editor is updated with content from the textarea.
25591 * @param {HtmlEditor} this
25592 * @param {String} html
25596 * @event editmodechange
25597 * Fires when the editor switches edit modes
25598 * @param {HtmlEditor} this
25599 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
25601 editmodechange: true,
25603 * @event editorevent
25604 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
25605 * @param {HtmlEditor} this
25609 * @event firstfocus
25610 * Fires when on first focus - needed by toolbars..
25611 * @param {HtmlEditor} this
25616 * Auto save the htmlEditor value as a file into Events
25617 * @param {HtmlEditor} this
25621 * @event savedpreview
25622 * preview the saved version of htmlEditor
25623 * @param {HtmlEditor} this
25630 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
25634 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
25639 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
25644 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
25649 * @cfg {Number} height (in pixels)
25653 * @cfg {Number} width (in pixels)
25658 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
25661 stylesheets: false,
25666 // private properties
25667 validationEvent : false,
25669 initialized : false,
25672 onFocus : Roo.emptyFn,
25674 hideMode:'offsets',
25676 tbContainer : false,
25680 toolbarContainer :function() {
25681 return this.wrap.select('.x-html-editor-tb',true).first();
25685 * Protected method that will not generally be called directly. It
25686 * is called when the editor creates its toolbar. Override this method if you need to
25687 * add custom toolbar buttons.
25688 * @param {HtmlEditor} editor
25690 createToolbar : function(){
25691 Roo.log('renewing');
25692 Roo.log("create toolbars");
25694 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
25695 this.toolbars[0].render(this.toolbarContainer());
25699 // if (!editor.toolbars || !editor.toolbars.length) {
25700 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
25703 // for (var i =0 ; i < editor.toolbars.length;i++) {
25704 // editor.toolbars[i] = Roo.factory(
25705 // typeof(editor.toolbars[i]) == 'string' ?
25706 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
25707 // Roo.bootstrap.HtmlEditor);
25708 // editor.toolbars[i].init(editor);
25714 onRender : function(ct, position)
25716 // Roo.log("Call onRender: " + this.xtype);
25718 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
25720 this.wrap = this.inputEl().wrap({
25721 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
25724 this.editorcore.onRender(ct, position);
25726 if (this.resizable) {
25727 this.resizeEl = new Roo.Resizable(this.wrap, {
25731 minHeight : this.height,
25732 height: this.height,
25733 handles : this.resizable,
25736 resize : function(r, w, h) {
25737 _t.onResize(w,h); // -something
25743 this.createToolbar(this);
25746 if(!this.width && this.resizable){
25747 this.setSize(this.wrap.getSize());
25749 if (this.resizeEl) {
25750 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
25751 // should trigger onReize..
25757 onResize : function(w, h)
25759 Roo.log('resize: ' +w + ',' + h );
25760 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
25764 if(this.inputEl() ){
25765 if(typeof w == 'number'){
25766 var aw = w - this.wrap.getFrameWidth('lr');
25767 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
25770 if(typeof h == 'number'){
25771 var tbh = -11; // fixme it needs to tool bar size!
25772 for (var i =0; i < this.toolbars.length;i++) {
25773 // fixme - ask toolbars for heights?
25774 tbh += this.toolbars[i].el.getHeight();
25775 //if (this.toolbars[i].footer) {
25776 // tbh += this.toolbars[i].footer.el.getHeight();
25784 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
25785 ah -= 5; // knock a few pixes off for look..
25786 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
25790 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
25791 this.editorcore.onResize(ew,eh);
25796 * Toggles the editor between standard and source edit mode.
25797 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
25799 toggleSourceEdit : function(sourceEditMode)
25801 this.editorcore.toggleSourceEdit(sourceEditMode);
25803 if(this.editorcore.sourceEditMode){
25804 Roo.log('editor - showing textarea');
25807 // Roo.log(this.syncValue());
25809 this.inputEl().removeClass(['hide', 'x-hidden']);
25810 this.inputEl().dom.removeAttribute('tabIndex');
25811 this.inputEl().focus();
25813 Roo.log('editor - hiding textarea');
25815 // Roo.log(this.pushValue());
25818 this.inputEl().addClass(['hide', 'x-hidden']);
25819 this.inputEl().dom.setAttribute('tabIndex', -1);
25820 //this.deferFocus();
25823 if(this.resizable){
25824 this.setSize(this.wrap.getSize());
25827 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25830 // private (for BoxComponent)
25831 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25833 // private (for BoxComponent)
25834 getResizeEl : function(){
25838 // private (for BoxComponent)
25839 getPositionEl : function(){
25844 initEvents : function(){
25845 this.originalValue = this.getValue();
25849 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25852 // markInvalid : Roo.emptyFn,
25854 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25857 // clearInvalid : Roo.emptyFn,
25859 setValue : function(v){
25860 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25861 this.editorcore.pushValue();
25866 deferFocus : function(){
25867 this.focus.defer(10, this);
25871 focus : function(){
25872 this.editorcore.focus();
25878 onDestroy : function(){
25884 for (var i =0; i < this.toolbars.length;i++) {
25885 // fixme - ask toolbars for heights?
25886 this.toolbars[i].onDestroy();
25889 this.wrap.dom.innerHTML = '';
25890 this.wrap.remove();
25895 onFirstFocus : function(){
25896 //Roo.log("onFirstFocus");
25897 this.editorcore.onFirstFocus();
25898 for (var i =0; i < this.toolbars.length;i++) {
25899 this.toolbars[i].onFirstFocus();
25905 syncValue : function()
25907 this.editorcore.syncValue();
25910 pushValue : function()
25912 this.editorcore.pushValue();
25916 // hide stuff that is not compatible
25930 * @event specialkey
25934 * @cfg {String} fieldClass @hide
25937 * @cfg {String} focusClass @hide
25940 * @cfg {String} autoCreate @hide
25943 * @cfg {String} inputType @hide
25947 * @cfg {String} invalidText @hide
25950 * @cfg {String} msgFx @hide
25953 * @cfg {String} validateOnBlur @hide
25962 Roo.namespace('Roo.bootstrap.htmleditor');
25964 * @class Roo.bootstrap.HtmlEditorToolbar1
25970 new Roo.bootstrap.HtmlEditor({
25973 new Roo.bootstrap.HtmlEditorToolbar1({
25974 disable : { fonts: 1 , format: 1, ..., ... , ...],
25980 * @cfg {Object} disable List of elements to disable..
25981 * @cfg {Array} btns List of additional buttons.
25985 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25988 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25991 Roo.apply(this, config);
25993 // default disabled, based on 'good practice'..
25994 this.disable = this.disable || {};
25995 Roo.applyIf(this.disable, {
25998 specialElements : true
26000 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
26002 this.editor = config.editor;
26003 this.editorcore = config.editor.editorcore;
26005 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
26007 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
26008 // dont call parent... till later.
26010 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
26015 editorcore : false,
26020 "h1","h2","h3","h4","h5","h6",
26022 "abbr", "acronym", "address", "cite", "samp", "var",
26026 onRender : function(ct, position)
26028 // Roo.log("Call onRender: " + this.xtype);
26030 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
26032 this.el.dom.style.marginBottom = '0';
26034 var editorcore = this.editorcore;
26035 var editor= this.editor;
26038 var btn = function(id,cmd , toggle, handler, html){
26040 var event = toggle ? 'toggle' : 'click';
26045 xns: Roo.bootstrap,
26049 enableToggle:toggle !== false,
26051 pressed : toggle ? false : null,
26054 a.listeners[toggle ? 'toggle' : 'click'] = function() {
26055 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
26061 // var cb_box = function...
26066 xns: Roo.bootstrap,
26071 xns: Roo.bootstrap,
26075 Roo.each(this.formats, function(f) {
26076 style.menu.items.push({
26078 xns: Roo.bootstrap,
26079 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
26084 editorcore.insertTag(this.tagname);
26091 children.push(style);
26093 btn('bold',false,true);
26094 btn('italic',false,true);
26095 btn('align-left', 'justifyleft',true);
26096 btn('align-center', 'justifycenter',true);
26097 btn('align-right' , 'justifyright',true);
26098 btn('link', false, false, function(btn) {
26099 //Roo.log("create link?");
26100 var url = prompt(this.createLinkText, this.defaultLinkValue);
26101 if(url && url != 'http:/'+'/'){
26102 this.editorcore.relayCmd('createlink', url);
26105 btn('list','insertunorderedlist',true);
26106 btn('pencil', false,true, function(btn){
26108 this.toggleSourceEdit(btn.pressed);
26111 if (this.editor.btns.length > 0) {
26112 for (var i = 0; i<this.editor.btns.length; i++) {
26113 children.push(this.editor.btns[i]);
26121 xns: Roo.bootstrap,
26126 xns: Roo.bootstrap,
26131 cog.menu.items.push({
26133 xns: Roo.bootstrap,
26134 html : Clean styles,
26139 editorcore.insertTag(this.tagname);
26148 this.xtype = 'NavSimplebar';
26150 for(var i=0;i< children.length;i++) {
26152 this.buttons.add(this.addxtypeChild(children[i]));
26156 editor.on('editorevent', this.updateToolbar, this);
26158 onBtnClick : function(id)
26160 this.editorcore.relayCmd(id);
26161 this.editorcore.focus();
26165 * Protected method that will not generally be called directly. It triggers
26166 * a toolbar update by reading the markup state of the current selection in the editor.
26168 updateToolbar: function(){
26170 if(!this.editorcore.activated){
26171 this.editor.onFirstFocus(); // is this neeed?
26175 var btns = this.buttons;
26176 var doc = this.editorcore.doc;
26177 btns.get('bold').setActive(doc.queryCommandState('bold'));
26178 btns.get('italic').setActive(doc.queryCommandState('italic'));
26179 //btns.get('underline').setActive(doc.queryCommandState('underline'));
26181 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
26182 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
26183 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
26185 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
26186 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
26189 var ans = this.editorcore.getAllAncestors();
26190 if (this.formatCombo) {
26193 var store = this.formatCombo.store;
26194 this.formatCombo.setValue("");
26195 for (var i =0; i < ans.length;i++) {
26196 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
26198 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
26206 // hides menus... - so this cant be on a menu...
26207 Roo.bootstrap.MenuMgr.hideAll();
26209 Roo.bootstrap.MenuMgr.hideAll();
26210 //this.editorsyncValue();
26212 onFirstFocus: function() {
26213 this.buttons.each(function(item){
26217 toggleSourceEdit : function(sourceEditMode){
26220 if(sourceEditMode){
26221 Roo.log("disabling buttons");
26222 this.buttons.each( function(item){
26223 if(item.cmd != 'pencil'){
26229 Roo.log("enabling buttons");
26230 if(this.editorcore.initialized){
26231 this.buttons.each( function(item){
26237 Roo.log("calling toggole on editor");
26238 // tell the editor that it's been pressed..
26239 this.editor.toggleSourceEdit(sourceEditMode);
26253 * @class Roo.bootstrap.Markdown
26254 * @extends Roo.bootstrap.TextArea
26255 * Bootstrap Showdown editable area
26256 * @cfg {string} content
26259 * Create a new Showdown
26262 Roo.bootstrap.Markdown = function(config){
26263 Roo.bootstrap.Markdown.superclass.constructor.call(this, config);
26267 Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea, {
26271 initEvents : function()
26274 Roo.bootstrap.TextArea.prototype.initEvents.call(this);
26275 this.markdownEl = this.el.createChild({
26276 cls : 'roo-markdown-area'
26278 this.inputEl().addClass('d-none');
26279 if (this.getValue() == '') {
26280 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26283 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26285 this.markdownEl.on('click', this.toggleTextEdit, this);
26286 this.on('blur', this.toggleTextEdit, this);
26287 this.on('specialkey', this.resizeTextArea, this);
26290 toggleTextEdit : function()
26292 var sh = this.markdownEl.getHeight();
26293 this.inputEl().addClass('d-none');
26294 this.markdownEl.addClass('d-none');
26295 if (!this.editing) {
26297 this.inputEl().setHeight(Math.min(500, Math.max(sh,(this.getValue().split("\n").length+1) * 30)));
26298 this.inputEl().removeClass('d-none');
26299 this.inputEl().focus();
26300 this.editing = true;
26303 // show showdown...
26304 this.updateMarkdown();
26305 this.markdownEl.removeClass('d-none');
26306 this.editing = false;
26309 updateMarkdown : function()
26311 if (this.getValue() == '') {
26312 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26316 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26319 resizeTextArea: function () {
26322 Roo.log([sh, this.getValue().split("\n").length * 30]);
26323 this.inputEl().setHeight(Math.min(500, Math.max(sh, (this.getValue().split("\n").length +1) * 30)));
26325 setValue : function(val)
26327 Roo.bootstrap.TextArea.prototype.setValue.call(this,val);
26328 if (!this.editing) {
26329 this.updateMarkdown();
26335 if (!this.editing) {
26336 this.toggleTextEdit();
26344 * @class Roo.bootstrap.Table.AbstractSelectionModel
26345 * @extends Roo.util.Observable
26346 * Abstract base class for grid SelectionModels. It provides the interface that should be
26347 * implemented by descendant classes. This class should not be directly instantiated.
26350 Roo.bootstrap.Table.AbstractSelectionModel = function(){
26351 this.locked = false;
26352 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
26356 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
26357 /** @ignore Called by the grid automatically. Do not call directly. */
26358 init : function(grid){
26364 * Locks the selections.
26367 this.locked = true;
26371 * Unlocks the selections.
26373 unlock : function(){
26374 this.locked = false;
26378 * Returns true if the selections are locked.
26379 * @return {Boolean}
26381 isLocked : function(){
26382 return this.locked;
26386 initEvents : function ()
26392 * @extends Roo.bootstrap.Table.AbstractSelectionModel
26393 * @class Roo.bootstrap.Table.RowSelectionModel
26394 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
26395 * It supports multiple selections and keyboard selection/navigation.
26397 * @param {Object} config
26400 Roo.bootstrap.Table.RowSelectionModel = function(config){
26401 Roo.apply(this, config);
26402 this.selections = new Roo.util.MixedCollection(false, function(o){
26407 this.lastActive = false;
26411 * @event selectionchange
26412 * Fires when the selection changes
26413 * @param {SelectionModel} this
26415 "selectionchange" : true,
26417 * @event afterselectionchange
26418 * Fires after the selection changes (eg. by key press or clicking)
26419 * @param {SelectionModel} this
26421 "afterselectionchange" : true,
26423 * @event beforerowselect
26424 * Fires when a row is selected being selected, return false to cancel.
26425 * @param {SelectionModel} this
26426 * @param {Number} rowIndex The selected index
26427 * @param {Boolean} keepExisting False if other selections will be cleared
26429 "beforerowselect" : true,
26432 * Fires when a row is selected.
26433 * @param {SelectionModel} this
26434 * @param {Number} rowIndex The selected index
26435 * @param {Roo.data.Record} r The record
26437 "rowselect" : true,
26439 * @event rowdeselect
26440 * Fires when a row is deselected.
26441 * @param {SelectionModel} this
26442 * @param {Number} rowIndex The selected index
26444 "rowdeselect" : true
26446 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
26447 this.locked = false;
26450 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
26452 * @cfg {Boolean} singleSelect
26453 * True to allow selection of only one row at a time (defaults to false)
26455 singleSelect : false,
26458 initEvents : function()
26461 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
26462 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
26463 //}else{ // allow click to work like normal
26464 // this.grid.on("rowclick", this.handleDragableRowClick, this);
26466 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
26467 this.grid.on("rowclick", this.handleMouseDown, this);
26469 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
26470 "up" : function(e){
26472 this.selectPrevious(e.shiftKey);
26473 }else if(this.last !== false && this.lastActive !== false){
26474 var last = this.last;
26475 this.selectRange(this.last, this.lastActive-1);
26476 this.grid.getView().focusRow(this.lastActive);
26477 if(last !== false){
26481 this.selectFirstRow();
26483 this.fireEvent("afterselectionchange", this);
26485 "down" : function(e){
26487 this.selectNext(e.shiftKey);
26488 }else if(this.last !== false && this.lastActive !== false){
26489 var last = this.last;
26490 this.selectRange(this.last, this.lastActive+1);
26491 this.grid.getView().focusRow(this.lastActive);
26492 if(last !== false){
26496 this.selectFirstRow();
26498 this.fireEvent("afterselectionchange", this);
26502 this.grid.store.on('load', function(){
26503 this.selections.clear();
26506 var view = this.grid.view;
26507 view.on("refresh", this.onRefresh, this);
26508 view.on("rowupdated", this.onRowUpdated, this);
26509 view.on("rowremoved", this.onRemove, this);
26514 onRefresh : function()
26516 var ds = this.grid.store, i, v = this.grid.view;
26517 var s = this.selections;
26518 s.each(function(r){
26519 if((i = ds.indexOfId(r.id)) != -1){
26528 onRemove : function(v, index, r){
26529 this.selections.remove(r);
26533 onRowUpdated : function(v, index, r){
26534 if(this.isSelected(r)){
26535 v.onRowSelect(index);
26541 * @param {Array} records The records to select
26542 * @param {Boolean} keepExisting (optional) True to keep existing selections
26544 selectRecords : function(records, keepExisting)
26547 this.clearSelections();
26549 var ds = this.grid.store;
26550 for(var i = 0, len = records.length; i < len; i++){
26551 this.selectRow(ds.indexOf(records[i]), true);
26556 * Gets the number of selected rows.
26559 getCount : function(){
26560 return this.selections.length;
26564 * Selects the first row in the grid.
26566 selectFirstRow : function(){
26571 * Select the last row.
26572 * @param {Boolean} keepExisting (optional) True to keep existing selections
26574 selectLastRow : function(keepExisting){
26575 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
26576 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
26580 * Selects the row immediately following the last selected row.
26581 * @param {Boolean} keepExisting (optional) True to keep existing selections
26583 selectNext : function(keepExisting)
26585 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
26586 this.selectRow(this.last+1, keepExisting);
26587 this.grid.getView().focusRow(this.last);
26592 * Selects the row that precedes the last selected row.
26593 * @param {Boolean} keepExisting (optional) True to keep existing selections
26595 selectPrevious : function(keepExisting){
26597 this.selectRow(this.last-1, keepExisting);
26598 this.grid.getView().focusRow(this.last);
26603 * Returns the selected records
26604 * @return {Array} Array of selected records
26606 getSelections : function(){
26607 return [].concat(this.selections.items);
26611 * Returns the first selected record.
26614 getSelected : function(){
26615 return this.selections.itemAt(0);
26620 * Clears all selections.
26622 clearSelections : function(fast)
26628 var ds = this.grid.store;
26629 var s = this.selections;
26630 s.each(function(r){
26631 this.deselectRow(ds.indexOfId(r.id));
26635 this.selections.clear();
26642 * Selects all rows.
26644 selectAll : function(){
26648 this.selections.clear();
26649 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
26650 this.selectRow(i, true);
26655 * Returns True if there is a selection.
26656 * @return {Boolean}
26658 hasSelection : function(){
26659 return this.selections.length > 0;
26663 * Returns True if the specified row is selected.
26664 * @param {Number/Record} record The record or index of the record to check
26665 * @return {Boolean}
26667 isSelected : function(index){
26668 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
26669 return (r && this.selections.key(r.id) ? true : false);
26673 * Returns True if the specified record id is selected.
26674 * @param {String} id The id of record to check
26675 * @return {Boolean}
26677 isIdSelected : function(id){
26678 return (this.selections.key(id) ? true : false);
26683 handleMouseDBClick : function(e, t){
26687 handleMouseDown : function(e, t)
26689 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
26690 if(this.isLocked() || rowIndex < 0 ){
26693 if(e.shiftKey && this.last !== false){
26694 var last = this.last;
26695 this.selectRange(last, rowIndex, e.ctrlKey);
26696 this.last = last; // reset the last
26700 var isSelected = this.isSelected(rowIndex);
26701 //Roo.log("select row:" + rowIndex);
26703 this.deselectRow(rowIndex);
26705 this.selectRow(rowIndex, true);
26709 if(e.button !== 0 && isSelected){
26710 alert('rowIndex 2: ' + rowIndex);
26711 view.focusRow(rowIndex);
26712 }else if(e.ctrlKey && isSelected){
26713 this.deselectRow(rowIndex);
26714 }else if(!isSelected){
26715 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
26716 view.focusRow(rowIndex);
26720 this.fireEvent("afterselectionchange", this);
26723 handleDragableRowClick : function(grid, rowIndex, e)
26725 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
26726 this.selectRow(rowIndex, false);
26727 grid.view.focusRow(rowIndex);
26728 this.fireEvent("afterselectionchange", this);
26733 * Selects multiple rows.
26734 * @param {Array} rows Array of the indexes of the row to select
26735 * @param {Boolean} keepExisting (optional) True to keep existing selections
26737 selectRows : function(rows, keepExisting){
26739 this.clearSelections();
26741 for(var i = 0, len = rows.length; i < len; i++){
26742 this.selectRow(rows[i], true);
26747 * Selects a range of rows. All rows in between startRow and endRow are also selected.
26748 * @param {Number} startRow The index of the first row in the range
26749 * @param {Number} endRow The index of the last row in the range
26750 * @param {Boolean} keepExisting (optional) True to retain existing selections
26752 selectRange : function(startRow, endRow, keepExisting){
26757 this.clearSelections();
26759 if(startRow <= endRow){
26760 for(var i = startRow; i <= endRow; i++){
26761 this.selectRow(i, true);
26764 for(var i = startRow; i >= endRow; i--){
26765 this.selectRow(i, true);
26771 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
26772 * @param {Number} startRow The index of the first row in the range
26773 * @param {Number} endRow The index of the last row in the range
26775 deselectRange : function(startRow, endRow, preventViewNotify){
26779 for(var i = startRow; i <= endRow; i++){
26780 this.deselectRow(i, preventViewNotify);
26786 * @param {Number} row The index of the row to select
26787 * @param {Boolean} keepExisting (optional) True to keep existing selections
26789 selectRow : function(index, keepExisting, preventViewNotify)
26791 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
26794 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
26795 if(!keepExisting || this.singleSelect){
26796 this.clearSelections();
26799 var r = this.grid.store.getAt(index);
26800 //console.log('selectRow - record id :' + r.id);
26802 this.selections.add(r);
26803 this.last = this.lastActive = index;
26804 if(!preventViewNotify){
26805 var proxy = new Roo.Element(
26806 this.grid.getRowDom(index)
26808 proxy.addClass('bg-info info');
26810 this.fireEvent("rowselect", this, index, r);
26811 this.fireEvent("selectionchange", this);
26817 * @param {Number} row The index of the row to deselect
26819 deselectRow : function(index, preventViewNotify)
26824 if(this.last == index){
26827 if(this.lastActive == index){
26828 this.lastActive = false;
26831 var r = this.grid.store.getAt(index);
26836 this.selections.remove(r);
26837 //.console.log('deselectRow - record id :' + r.id);
26838 if(!preventViewNotify){
26840 var proxy = new Roo.Element(
26841 this.grid.getRowDom(index)
26843 proxy.removeClass('bg-info info');
26845 this.fireEvent("rowdeselect", this, index);
26846 this.fireEvent("selectionchange", this);
26850 restoreLast : function(){
26852 this.last = this._last;
26857 acceptsNav : function(row, col, cm){
26858 return !cm.isHidden(col) && cm.isCellEditable(col, row);
26862 onEditorKey : function(field, e){
26863 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
26868 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
26870 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
26872 }else if(k == e.ENTER && !e.ctrlKey){
26876 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
26878 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
26880 }else if(k == e.ESC){
26884 g.startEditing(newCell[0], newCell[1]);
26890 * Ext JS Library 1.1.1
26891 * Copyright(c) 2006-2007, Ext JS, LLC.
26893 * Originally Released Under LGPL - original licence link has changed is not relivant.
26896 * <script type="text/javascript">
26900 * @class Roo.bootstrap.PagingToolbar
26901 * @extends Roo.bootstrap.NavSimplebar
26902 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26904 * Create a new PagingToolbar
26905 * @param {Object} config The config object
26906 * @param {Roo.data.Store} store
26908 Roo.bootstrap.PagingToolbar = function(config)
26910 // old args format still supported... - xtype is prefered..
26911 // created from xtype...
26913 this.ds = config.dataSource;
26915 if (config.store && !this.ds) {
26916 this.store= Roo.factory(config.store, Roo.data);
26917 this.ds = this.store;
26918 this.ds.xmodule = this.xmodule || false;
26921 this.toolbarItems = [];
26922 if (config.items) {
26923 this.toolbarItems = config.items;
26926 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26931 this.bind(this.ds);
26934 if (Roo.bootstrap.version == 4) {
26935 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26937 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26942 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26944 * @cfg {Roo.data.Store} dataSource
26945 * The underlying data store providing the paged data
26948 * @cfg {String/HTMLElement/Element} container
26949 * container The id or element that will contain the toolbar
26952 * @cfg {Boolean} displayInfo
26953 * True to display the displayMsg (defaults to false)
26956 * @cfg {Number} pageSize
26957 * The number of records to display per page (defaults to 20)
26961 * @cfg {String} displayMsg
26962 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26964 displayMsg : 'Displaying {0} - {1} of {2}',
26966 * @cfg {String} emptyMsg
26967 * The message to display when no records are found (defaults to "No data to display")
26969 emptyMsg : 'No data to display',
26971 * Customizable piece of the default paging text (defaults to "Page")
26974 beforePageText : "Page",
26976 * Customizable piece of the default paging text (defaults to "of %0")
26979 afterPageText : "of {0}",
26981 * Customizable piece of the default paging text (defaults to "First Page")
26984 firstText : "First Page",
26986 * Customizable piece of the default paging text (defaults to "Previous Page")
26989 prevText : "Previous Page",
26991 * Customizable piece of the default paging text (defaults to "Next Page")
26994 nextText : "Next Page",
26996 * Customizable piece of the default paging text (defaults to "Last Page")
26999 lastText : "Last Page",
27001 * Customizable piece of the default paging text (defaults to "Refresh")
27004 refreshText : "Refresh",
27008 onRender : function(ct, position)
27010 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
27011 this.navgroup.parentId = this.id;
27012 this.navgroup.onRender(this.el, null);
27013 // add the buttons to the navgroup
27015 if(this.displayInfo){
27016 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
27017 this.displayEl = this.el.select('.x-paging-info', true).first();
27018 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
27019 // this.displayEl = navel.el.select('span',true).first();
27025 Roo.each(_this.buttons, function(e){ // this might need to use render????
27026 Roo.factory(e).render(_this.el);
27030 Roo.each(_this.toolbarItems, function(e) {
27031 _this.navgroup.addItem(e);
27035 this.first = this.navgroup.addItem({
27036 tooltip: this.firstText,
27037 cls: "prev btn-outline-secondary",
27038 html : ' <i class="fa fa-step-backward"></i>',
27040 preventDefault: true,
27041 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
27044 this.prev = this.navgroup.addItem({
27045 tooltip: this.prevText,
27046 cls: "prev btn-outline-secondary",
27047 html : ' <i class="fa fa-backward"></i>',
27049 preventDefault: true,
27050 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
27052 //this.addSeparator();
27055 var field = this.navgroup.addItem( {
27057 cls : 'x-paging-position btn-outline-secondary',
27059 html : this.beforePageText +
27060 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
27061 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
27064 this.field = field.el.select('input', true).first();
27065 this.field.on("keydown", this.onPagingKeydown, this);
27066 this.field.on("focus", function(){this.dom.select();});
27069 this.afterTextEl = field.el.select('.x-paging-after',true).first();
27070 //this.field.setHeight(18);
27071 //this.addSeparator();
27072 this.next = this.navgroup.addItem({
27073 tooltip: this.nextText,
27074 cls: "next btn-outline-secondary",
27075 html : ' <i class="fa fa-forward"></i>',
27077 preventDefault: true,
27078 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
27080 this.last = this.navgroup.addItem({
27081 tooltip: this.lastText,
27082 html : ' <i class="fa fa-step-forward"></i>',
27083 cls: "next btn-outline-secondary",
27085 preventDefault: true,
27086 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
27088 //this.addSeparator();
27089 this.loading = this.navgroup.addItem({
27090 tooltip: this.refreshText,
27091 cls: "btn-outline-secondary",
27092 html : ' <i class="fa fa-refresh"></i>',
27093 preventDefault: true,
27094 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
27100 updateInfo : function(){
27101 if(this.displayEl){
27102 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
27103 var msg = count == 0 ?
27107 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27109 this.displayEl.update(msg);
27114 onLoad : function(ds, r, o)
27116 this.cursor = o.params.start ? o.params.start : 0;
27118 var d = this.getPageData(),
27123 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
27124 this.field.dom.value = ap;
27125 this.first.setDisabled(ap == 1);
27126 this.prev.setDisabled(ap == 1);
27127 this.next.setDisabled(ap == ps);
27128 this.last.setDisabled(ap == ps);
27129 this.loading.enable();
27134 getPageData : function(){
27135 var total = this.ds.getTotalCount();
27138 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27139 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27144 onLoadError : function(){
27145 this.loading.enable();
27149 onPagingKeydown : function(e){
27150 var k = e.getKey();
27151 var d = this.getPageData();
27153 var v = this.field.dom.value, pageNum;
27154 if(!v || isNaN(pageNum = parseInt(v, 10))){
27155 this.field.dom.value = d.activePage;
27158 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27159 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27162 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))
27164 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27165 this.field.dom.value = pageNum;
27166 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27169 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27171 var v = this.field.dom.value, pageNum;
27172 var increment = (e.shiftKey) ? 10 : 1;
27173 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
27176 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27177 this.field.dom.value = d.activePage;
27180 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27182 this.field.dom.value = parseInt(v, 10) + increment;
27183 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27184 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27191 beforeLoad : function(){
27193 this.loading.disable();
27198 onClick : function(which){
27207 ds.load({params:{start: 0, limit: this.pageSize}});
27210 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27213 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27216 var total = ds.getTotalCount();
27217 var extra = total % this.pageSize;
27218 var lastStart = extra ? (total - extra) : total-this.pageSize;
27219 ds.load({params:{start: lastStart, limit: this.pageSize}});
27222 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27228 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27229 * @param {Roo.data.Store} store The data store to unbind
27231 unbind : function(ds){
27232 ds.un("beforeload", this.beforeLoad, this);
27233 ds.un("load", this.onLoad, this);
27234 ds.un("loadexception", this.onLoadError, this);
27235 ds.un("remove", this.updateInfo, this);
27236 ds.un("add", this.updateInfo, this);
27237 this.ds = undefined;
27241 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27242 * @param {Roo.data.Store} store The data store to bind
27244 bind : function(ds){
27245 ds.on("beforeload", this.beforeLoad, this);
27246 ds.on("load", this.onLoad, this);
27247 ds.on("loadexception", this.onLoadError, this);
27248 ds.on("remove", this.updateInfo, this);
27249 ds.on("add", this.updateInfo, this);
27260 * @class Roo.bootstrap.MessageBar
27261 * @extends Roo.bootstrap.Component
27262 * Bootstrap MessageBar class
27263 * @cfg {String} html contents of the MessageBar
27264 * @cfg {String} weight (info | success | warning | danger) default info
27265 * @cfg {String} beforeClass insert the bar before the given class
27266 * @cfg {Boolean} closable (true | false) default false
27267 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
27270 * Create a new Element
27271 * @param {Object} config The config object
27274 Roo.bootstrap.MessageBar = function(config){
27275 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
27278 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
27284 beforeClass: 'bootstrap-sticky-wrap',
27286 getAutoCreate : function(){
27290 cls: 'alert alert-dismissable alert-' + this.weight,
27295 html: this.html || ''
27301 cfg.cls += ' alert-messages-fixed';
27315 onRender : function(ct, position)
27317 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
27320 var cfg = Roo.apply({}, this.getAutoCreate());
27324 cfg.cls += ' ' + this.cls;
27327 cfg.style = this.style;
27329 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
27331 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27334 this.el.select('>button.close').on('click', this.hide, this);
27340 if (!this.rendered) {
27346 this.fireEvent('show', this);
27352 if (!this.rendered) {
27358 this.fireEvent('hide', this);
27361 update : function()
27363 // var e = this.el.dom.firstChild;
27365 // if(this.closable){
27366 // e = e.nextSibling;
27369 // e.data = this.html || '';
27371 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
27387 * @class Roo.bootstrap.Graph
27388 * @extends Roo.bootstrap.Component
27389 * Bootstrap Graph class
27393 @cfg {String} graphtype bar | vbar | pie
27394 @cfg {number} g_x coodinator | centre x (pie)
27395 @cfg {number} g_y coodinator | centre y (pie)
27396 @cfg {number} g_r radius (pie)
27397 @cfg {number} g_height height of the chart (respected by all elements in the set)
27398 @cfg {number} g_width width of the chart (respected by all elements in the set)
27399 @cfg {Object} title The title of the chart
27402 -opts (object) options for the chart
27404 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
27405 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
27407 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.
27408 o stacked (boolean) whether or not to tread values as in a stacked bar chart
27410 o stretch (boolean)
27412 -opts (object) options for the pie
27415 o startAngle (number)
27416 o endAngle (number)
27420 * Create a new Input
27421 * @param {Object} config The config object
27424 Roo.bootstrap.Graph = function(config){
27425 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
27431 * The img click event for the img.
27432 * @param {Roo.EventObject} e
27438 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
27449 //g_colors: this.colors,
27456 getAutoCreate : function(){
27467 onRender : function(ct,position){
27470 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
27472 if (typeof(Raphael) == 'undefined') {
27473 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
27477 this.raphael = Raphael(this.el.dom);
27479 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27480 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27481 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27482 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
27484 r.text(160, 10, "Single Series Chart").attr(txtattr);
27485 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
27486 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
27487 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
27489 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
27490 r.barchart(330, 10, 300, 220, data1);
27491 r.barchart(10, 250, 300, 220, data2, {stacked: true});
27492 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
27495 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27496 // r.barchart(30, 30, 560, 250, xdata, {
27497 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
27498 // axis : "0 0 1 1",
27499 // axisxlabels : xdata
27500 // //yvalues : cols,
27503 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27505 // this.load(null,xdata,{
27506 // axis : "0 0 1 1",
27507 // axisxlabels : xdata
27512 load : function(graphtype,xdata,opts)
27514 this.raphael.clear();
27516 graphtype = this.graphtype;
27521 var r = this.raphael,
27522 fin = function () {
27523 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
27525 fout = function () {
27526 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
27528 pfin = function() {
27529 this.sector.stop();
27530 this.sector.scale(1.1, 1.1, this.cx, this.cy);
27533 this.label[0].stop();
27534 this.label[0].attr({ r: 7.5 });
27535 this.label[1].attr({ "font-weight": 800 });
27538 pfout = function() {
27539 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
27542 this.label[0].animate({ r: 5 }, 500, "bounce");
27543 this.label[1].attr({ "font-weight": 400 });
27549 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27552 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27555 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
27556 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
27558 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
27565 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
27570 setTitle: function(o)
27575 initEvents: function() {
27578 this.el.on('click', this.onClick, this);
27582 onClick : function(e)
27584 Roo.log('img onclick');
27585 this.fireEvent('click', this, e);
27597 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27600 * @class Roo.bootstrap.dash.NumberBox
27601 * @extends Roo.bootstrap.Component
27602 * Bootstrap NumberBox class
27603 * @cfg {String} headline Box headline
27604 * @cfg {String} content Box content
27605 * @cfg {String} icon Box icon
27606 * @cfg {String} footer Footer text
27607 * @cfg {String} fhref Footer href
27610 * Create a new NumberBox
27611 * @param {Object} config The config object
27615 Roo.bootstrap.dash.NumberBox = function(config){
27616 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
27620 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
27629 getAutoCreate : function(){
27633 cls : 'small-box ',
27641 cls : 'roo-headline',
27642 html : this.headline
27646 cls : 'roo-content',
27647 html : this.content
27661 cls : 'ion ' + this.icon
27670 cls : 'small-box-footer',
27671 href : this.fhref || '#',
27675 cfg.cn.push(footer);
27682 onRender : function(ct,position){
27683 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
27690 setHeadline: function (value)
27692 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
27695 setFooter: function (value, href)
27697 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
27700 this.el.select('a.small-box-footer',true).first().attr('href', href);
27705 setContent: function (value)
27707 this.el.select('.roo-content',true).first().dom.innerHTML = value;
27710 initEvents: function()
27724 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27727 * @class Roo.bootstrap.dash.TabBox
27728 * @extends Roo.bootstrap.Component
27729 * Bootstrap TabBox class
27730 * @cfg {String} title Title of the TabBox
27731 * @cfg {String} icon Icon of the TabBox
27732 * @cfg {Boolean} showtabs (true|false) show the tabs default true
27733 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
27736 * Create a new TabBox
27737 * @param {Object} config The config object
27741 Roo.bootstrap.dash.TabBox = function(config){
27742 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
27747 * When a pane is added
27748 * @param {Roo.bootstrap.dash.TabPane} pane
27752 * @event activatepane
27753 * When a pane is activated
27754 * @param {Roo.bootstrap.dash.TabPane} pane
27756 "activatepane" : true
27764 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
27769 tabScrollable : false,
27771 getChildContainer : function()
27773 return this.el.select('.tab-content', true).first();
27776 getAutoCreate : function(){
27780 cls: 'pull-left header',
27788 cls: 'fa ' + this.icon
27794 cls: 'nav nav-tabs pull-right',
27800 if(this.tabScrollable){
27807 cls: 'nav nav-tabs pull-right',
27818 cls: 'nav-tabs-custom',
27823 cls: 'tab-content no-padding',
27831 initEvents : function()
27833 //Roo.log('add add pane handler');
27834 this.on('addpane', this.onAddPane, this);
27837 * Updates the box title
27838 * @param {String} html to set the title to.
27840 setTitle : function(value)
27842 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
27844 onAddPane : function(pane)
27846 this.panes.push(pane);
27847 //Roo.log('addpane');
27849 // tabs are rendere left to right..
27850 if(!this.showtabs){
27854 var ctr = this.el.select('.nav-tabs', true).first();
27857 var existing = ctr.select('.nav-tab',true);
27858 var qty = existing.getCount();;
27861 var tab = ctr.createChild({
27863 cls : 'nav-tab' + (qty ? '' : ' active'),
27871 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
27874 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
27876 pane.el.addClass('active');
27881 onTabClick : function(ev,un,ob,pane)
27883 //Roo.log('tab - prev default');
27884 ev.preventDefault();
27887 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
27888 pane.tab.addClass('active');
27889 //Roo.log(pane.title);
27890 this.getChildContainer().select('.tab-pane',true).removeClass('active');
27891 // technically we should have a deactivate event.. but maybe add later.
27892 // and it should not de-activate the selected tab...
27893 this.fireEvent('activatepane', pane);
27894 pane.el.addClass('active');
27895 pane.fireEvent('activate');
27900 getActivePane : function()
27903 Roo.each(this.panes, function(p) {
27904 if(p.el.hasClass('active')){
27925 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27927 * @class Roo.bootstrap.TabPane
27928 * @extends Roo.bootstrap.Component
27929 * Bootstrap TabPane class
27930 * @cfg {Boolean} active (false | true) Default false
27931 * @cfg {String} title title of panel
27935 * Create a new TabPane
27936 * @param {Object} config The config object
27939 Roo.bootstrap.dash.TabPane = function(config){
27940 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27946 * When a pane is activated
27947 * @param {Roo.bootstrap.dash.TabPane} pane
27954 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27959 // the tabBox that this is attached to.
27962 getAutoCreate : function()
27970 cfg.cls += ' active';
27975 initEvents : function()
27977 //Roo.log('trigger add pane handler');
27978 this.parent().fireEvent('addpane', this)
27982 * Updates the tab title
27983 * @param {String} html to set the title to.
27985 setTitle: function(str)
27991 this.tab.select('a', true).first().dom.innerHTML = str;
28008 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28011 * @class Roo.bootstrap.menu.Menu
28012 * @extends Roo.bootstrap.Component
28013 * Bootstrap Menu class - container for Menu
28014 * @cfg {String} html Text of the menu
28015 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
28016 * @cfg {String} icon Font awesome icon
28017 * @cfg {String} pos Menu align to (top | bottom) default bottom
28021 * Create a new Menu
28022 * @param {Object} config The config object
28026 Roo.bootstrap.menu.Menu = function(config){
28027 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
28031 * @event beforeshow
28032 * Fires before this menu is displayed
28033 * @param {Roo.bootstrap.menu.Menu} this
28037 * @event beforehide
28038 * Fires before this menu is hidden
28039 * @param {Roo.bootstrap.menu.Menu} this
28044 * Fires after this menu is displayed
28045 * @param {Roo.bootstrap.menu.Menu} this
28050 * Fires after this menu is hidden
28051 * @param {Roo.bootstrap.menu.Menu} this
28056 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
28057 * @param {Roo.bootstrap.menu.Menu} this
28058 * @param {Roo.EventObject} e
28065 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
28069 weight : 'default',
28074 getChildContainer : function() {
28075 if(this.isSubMenu){
28079 return this.el.select('ul.dropdown-menu', true).first();
28082 getAutoCreate : function()
28087 cls : 'roo-menu-text',
28095 cls : 'fa ' + this.icon
28106 cls : 'dropdown-button btn btn-' + this.weight,
28111 cls : 'dropdown-toggle btn btn-' + this.weight,
28121 cls : 'dropdown-menu'
28127 if(this.pos == 'top'){
28128 cfg.cls += ' dropup';
28131 if(this.isSubMenu){
28134 cls : 'dropdown-menu'
28141 onRender : function(ct, position)
28143 this.isSubMenu = ct.hasClass('dropdown-submenu');
28145 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
28148 initEvents : function()
28150 if(this.isSubMenu){
28154 this.hidden = true;
28156 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
28157 this.triggerEl.on('click', this.onTriggerPress, this);
28159 this.buttonEl = this.el.select('button.dropdown-button', true).first();
28160 this.buttonEl.on('click', this.onClick, this);
28166 if(this.isSubMenu){
28170 return this.el.select('ul.dropdown-menu', true).first();
28173 onClick : function(e)
28175 this.fireEvent("click", this, e);
28178 onTriggerPress : function(e)
28180 if (this.isVisible()) {
28187 isVisible : function(){
28188 return !this.hidden;
28193 this.fireEvent("beforeshow", this);
28195 this.hidden = false;
28196 this.el.addClass('open');
28198 Roo.get(document).on("mouseup", this.onMouseUp, this);
28200 this.fireEvent("show", this);
28207 this.fireEvent("beforehide", this);
28209 this.hidden = true;
28210 this.el.removeClass('open');
28212 Roo.get(document).un("mouseup", this.onMouseUp);
28214 this.fireEvent("hide", this);
28217 onMouseUp : function()
28231 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28234 * @class Roo.bootstrap.menu.Item
28235 * @extends Roo.bootstrap.Component
28236 * Bootstrap MenuItem class
28237 * @cfg {Boolean} submenu (true | false) default false
28238 * @cfg {String} html text of the item
28239 * @cfg {String} href the link
28240 * @cfg {Boolean} disable (true | false) default false
28241 * @cfg {Boolean} preventDefault (true | false) default true
28242 * @cfg {String} icon Font awesome icon
28243 * @cfg {String} pos Submenu align to (left | right) default right
28247 * Create a new Item
28248 * @param {Object} config The config object
28252 Roo.bootstrap.menu.Item = function(config){
28253 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
28257 * Fires when the mouse is hovering over this menu
28258 * @param {Roo.bootstrap.menu.Item} this
28259 * @param {Roo.EventObject} e
28264 * Fires when the mouse exits this menu
28265 * @param {Roo.bootstrap.menu.Item} this
28266 * @param {Roo.EventObject} e
28272 * The raw click event for the entire grid.
28273 * @param {Roo.EventObject} e
28279 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
28284 preventDefault: true,
28289 getAutoCreate : function()
28294 cls : 'roo-menu-item-text',
28302 cls : 'fa ' + this.icon
28311 href : this.href || '#',
28318 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
28322 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
28324 if(this.pos == 'left'){
28325 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
28332 initEvents : function()
28334 this.el.on('mouseover', this.onMouseOver, this);
28335 this.el.on('mouseout', this.onMouseOut, this);
28337 this.el.select('a', true).first().on('click', this.onClick, this);
28341 onClick : function(e)
28343 if(this.preventDefault){
28344 e.preventDefault();
28347 this.fireEvent("click", this, e);
28350 onMouseOver : function(e)
28352 if(this.submenu && this.pos == 'left'){
28353 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
28356 this.fireEvent("mouseover", this, e);
28359 onMouseOut : function(e)
28361 this.fireEvent("mouseout", this, e);
28373 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28376 * @class Roo.bootstrap.menu.Separator
28377 * @extends Roo.bootstrap.Component
28378 * Bootstrap Separator class
28381 * Create a new Separator
28382 * @param {Object} config The config object
28386 Roo.bootstrap.menu.Separator = function(config){
28387 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
28390 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
28392 getAutoCreate : function(){
28413 * @class Roo.bootstrap.Tooltip
28414 * Bootstrap Tooltip class
28415 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
28416 * to determine which dom element triggers the tooltip.
28418 * It needs to add support for additional attributes like tooltip-position
28421 * Create a new Toolti
28422 * @param {Object} config The config object
28425 Roo.bootstrap.Tooltip = function(config){
28426 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
28428 this.alignment = Roo.bootstrap.Tooltip.alignment;
28430 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
28431 this.alignment = config.alignment;
28436 Roo.apply(Roo.bootstrap.Tooltip, {
28438 * @function init initialize tooltip monitoring.
28442 currentTip : false,
28443 currentRegion : false,
28449 Roo.get(document).on('mouseover', this.enter ,this);
28450 Roo.get(document).on('mouseout', this.leave, this);
28453 this.currentTip = new Roo.bootstrap.Tooltip();
28456 enter : function(ev)
28458 var dom = ev.getTarget();
28460 //Roo.log(['enter',dom]);
28461 var el = Roo.fly(dom);
28462 if (this.currentEl) {
28464 //Roo.log(this.currentEl);
28465 //Roo.log(this.currentEl.contains(dom));
28466 if (this.currentEl == el) {
28469 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
28475 if (this.currentTip.el) {
28476 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
28480 if(!el || el.dom == document){
28486 // you can not look for children, as if el is the body.. then everythign is the child..
28487 if (!el.attr('tooltip')) { //
28488 if (!el.select("[tooltip]").elements.length) {
28491 // is the mouse over this child...?
28492 bindEl = el.select("[tooltip]").first();
28493 var xy = ev.getXY();
28494 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
28495 //Roo.log("not in region.");
28498 //Roo.log("child element over..");
28501 this.currentEl = bindEl;
28502 this.currentTip.bind(bindEl);
28503 this.currentRegion = Roo.lib.Region.getRegion(dom);
28504 this.currentTip.enter();
28507 leave : function(ev)
28509 var dom = ev.getTarget();
28510 //Roo.log(['leave',dom]);
28511 if (!this.currentEl) {
28516 if (dom != this.currentEl.dom) {
28519 var xy = ev.getXY();
28520 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
28523 // only activate leave if mouse cursor is outside... bounding box..
28528 if (this.currentTip) {
28529 this.currentTip.leave();
28531 //Roo.log('clear currentEl');
28532 this.currentEl = false;
28537 'left' : ['r-l', [-2,0], 'right'],
28538 'right' : ['l-r', [2,0], 'left'],
28539 'bottom' : ['t-b', [0,2], 'top'],
28540 'top' : [ 'b-t', [0,-2], 'bottom']
28546 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
28551 delay : null, // can be { show : 300 , hide: 500}
28555 hoverState : null, //???
28557 placement : 'bottom',
28561 getAutoCreate : function(){
28568 cls : 'tooltip-arrow arrow'
28571 cls : 'tooltip-inner'
28578 bind : function(el)
28583 initEvents : function()
28585 this.arrowEl = this.el.select('.arrow', true).first();
28586 this.innerEl = this.el.select('.tooltip-inner', true).first();
28589 enter : function () {
28591 if (this.timeout != null) {
28592 clearTimeout(this.timeout);
28595 this.hoverState = 'in';
28596 //Roo.log("enter - show");
28597 if (!this.delay || !this.delay.show) {
28602 this.timeout = setTimeout(function () {
28603 if (_t.hoverState == 'in') {
28606 }, this.delay.show);
28610 clearTimeout(this.timeout);
28612 this.hoverState = 'out';
28613 if (!this.delay || !this.delay.hide) {
28619 this.timeout = setTimeout(function () {
28620 //Roo.log("leave - timeout");
28622 if (_t.hoverState == 'out') {
28624 Roo.bootstrap.Tooltip.currentEl = false;
28629 show : function (msg)
28632 this.render(document.body);
28635 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
28637 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
28639 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
28641 this.el.removeClass(['fade','top','bottom', 'left', 'right','in',
28642 'bs-tooltip-top','bs-tooltip-bottom', 'bs-tooltip-left', 'bs-tooltip-right']);
28644 var placement = typeof this.placement == 'function' ?
28645 this.placement.call(this, this.el, on_el) :
28648 var autoToken = /\s?auto?\s?/i;
28649 var autoPlace = autoToken.test(placement);
28651 placement = placement.replace(autoToken, '') || 'top';
28655 //this.el.setXY([0,0]);
28657 //this.el.dom.style.display='block';
28659 //this.el.appendTo(on_el);
28661 var p = this.getPosition();
28662 var box = this.el.getBox();
28668 var align = this.alignment[placement];
28670 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
28672 if(placement == 'top' || placement == 'bottom'){
28674 placement = 'right';
28677 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
28678 placement = 'left';
28681 var scroll = Roo.select('body', true).first().getScroll();
28683 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
28687 align = this.alignment[placement];
28689 this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
28693 this.el.alignTo(this.bindEl, align[0],align[1]);
28694 //var arrow = this.el.select('.arrow',true).first();
28695 //arrow.set(align[2],
28697 this.el.addClass(placement);
28698 this.el.addClass("bs-tooltip-"+ placement);
28700 this.el.addClass('in fade show');
28702 this.hoverState = null;
28704 if (this.el.hasClass('fade')) {
28719 //this.el.setXY([0,0]);
28720 this.el.removeClass(['show', 'in']);
28736 * @class Roo.bootstrap.LocationPicker
28737 * @extends Roo.bootstrap.Component
28738 * Bootstrap LocationPicker class
28739 * @cfg {Number} latitude Position when init default 0
28740 * @cfg {Number} longitude Position when init default 0
28741 * @cfg {Number} zoom default 15
28742 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
28743 * @cfg {Boolean} mapTypeControl default false
28744 * @cfg {Boolean} disableDoubleClickZoom default false
28745 * @cfg {Boolean} scrollwheel default true
28746 * @cfg {Boolean} streetViewControl default false
28747 * @cfg {Number} radius default 0
28748 * @cfg {String} locationName
28749 * @cfg {Boolean} draggable default true
28750 * @cfg {Boolean} enableAutocomplete default false
28751 * @cfg {Boolean} enableReverseGeocode default true
28752 * @cfg {String} markerTitle
28755 * Create a new LocationPicker
28756 * @param {Object} config The config object
28760 Roo.bootstrap.LocationPicker = function(config){
28762 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
28767 * Fires when the picker initialized.
28768 * @param {Roo.bootstrap.LocationPicker} this
28769 * @param {Google Location} location
28773 * @event positionchanged
28774 * Fires when the picker position changed.
28775 * @param {Roo.bootstrap.LocationPicker} this
28776 * @param {Google Location} location
28778 positionchanged : true,
28781 * Fires when the map resize.
28782 * @param {Roo.bootstrap.LocationPicker} this
28787 * Fires when the map show.
28788 * @param {Roo.bootstrap.LocationPicker} this
28793 * Fires when the map hide.
28794 * @param {Roo.bootstrap.LocationPicker} this
28799 * Fires when click the map.
28800 * @param {Roo.bootstrap.LocationPicker} this
28801 * @param {Map event} e
28805 * @event mapRightClick
28806 * Fires when right click the map.
28807 * @param {Roo.bootstrap.LocationPicker} this
28808 * @param {Map event} e
28810 mapRightClick : true,
28812 * @event markerClick
28813 * Fires when click the marker.
28814 * @param {Roo.bootstrap.LocationPicker} this
28815 * @param {Map event} e
28817 markerClick : true,
28819 * @event markerRightClick
28820 * Fires when right click the marker.
28821 * @param {Roo.bootstrap.LocationPicker} this
28822 * @param {Map event} e
28824 markerRightClick : true,
28826 * @event OverlayViewDraw
28827 * Fires when OverlayView Draw
28828 * @param {Roo.bootstrap.LocationPicker} this
28830 OverlayViewDraw : true,
28832 * @event OverlayViewOnAdd
28833 * Fires when OverlayView Draw
28834 * @param {Roo.bootstrap.LocationPicker} this
28836 OverlayViewOnAdd : true,
28838 * @event OverlayViewOnRemove
28839 * Fires when OverlayView Draw
28840 * @param {Roo.bootstrap.LocationPicker} this
28842 OverlayViewOnRemove : true,
28844 * @event OverlayViewShow
28845 * Fires when OverlayView Draw
28846 * @param {Roo.bootstrap.LocationPicker} this
28847 * @param {Pixel} cpx
28849 OverlayViewShow : true,
28851 * @event OverlayViewHide
28852 * Fires when OverlayView Draw
28853 * @param {Roo.bootstrap.LocationPicker} this
28855 OverlayViewHide : true,
28857 * @event loadexception
28858 * Fires when load google lib failed.
28859 * @param {Roo.bootstrap.LocationPicker} this
28861 loadexception : true
28866 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
28868 gMapContext: false,
28874 mapTypeControl: false,
28875 disableDoubleClickZoom: false,
28877 streetViewControl: false,
28881 enableAutocomplete: false,
28882 enableReverseGeocode: true,
28885 getAutoCreate: function()
28890 cls: 'roo-location-picker'
28896 initEvents: function(ct, position)
28898 if(!this.el.getWidth() || this.isApplied()){
28902 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28907 initial: function()
28909 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
28910 this.fireEvent('loadexception', this);
28914 if(!this.mapTypeId){
28915 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28918 this.gMapContext = this.GMapContext();
28920 this.initOverlayView();
28922 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28926 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28927 _this.setPosition(_this.gMapContext.marker.position);
28930 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28931 _this.fireEvent('mapClick', this, event);
28935 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28936 _this.fireEvent('mapRightClick', this, event);
28940 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28941 _this.fireEvent('markerClick', this, event);
28945 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28946 _this.fireEvent('markerRightClick', this, event);
28950 this.setPosition(this.gMapContext.location);
28952 this.fireEvent('initial', this, this.gMapContext.location);
28955 initOverlayView: function()
28959 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28963 _this.fireEvent('OverlayViewDraw', _this);
28968 _this.fireEvent('OverlayViewOnAdd', _this);
28971 onRemove: function()
28973 _this.fireEvent('OverlayViewOnRemove', _this);
28976 show: function(cpx)
28978 _this.fireEvent('OverlayViewShow', _this, cpx);
28983 _this.fireEvent('OverlayViewHide', _this);
28989 fromLatLngToContainerPixel: function(event)
28991 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28994 isApplied: function()
28996 return this.getGmapContext() == false ? false : true;
28999 getGmapContext: function()
29001 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
29004 GMapContext: function()
29006 var position = new google.maps.LatLng(this.latitude, this.longitude);
29008 var _map = new google.maps.Map(this.el.dom, {
29011 mapTypeId: this.mapTypeId,
29012 mapTypeControl: this.mapTypeControl,
29013 disableDoubleClickZoom: this.disableDoubleClickZoom,
29014 scrollwheel: this.scrollwheel,
29015 streetViewControl: this.streetViewControl,
29016 locationName: this.locationName,
29017 draggable: this.draggable,
29018 enableAutocomplete: this.enableAutocomplete,
29019 enableReverseGeocode: this.enableReverseGeocode
29022 var _marker = new google.maps.Marker({
29023 position: position,
29025 title: this.markerTitle,
29026 draggable: this.draggable
29033 location: position,
29034 radius: this.radius,
29035 locationName: this.locationName,
29036 addressComponents: {
29037 formatted_address: null,
29038 addressLine1: null,
29039 addressLine2: null,
29041 streetNumber: null,
29045 stateOrProvince: null
29048 domContainer: this.el.dom,
29049 geodecoder: new google.maps.Geocoder()
29053 drawCircle: function(center, radius, options)
29055 if (this.gMapContext.circle != null) {
29056 this.gMapContext.circle.setMap(null);
29060 options = Roo.apply({}, options, {
29061 strokeColor: "#0000FF",
29062 strokeOpacity: .35,
29064 fillColor: "#0000FF",
29068 options.map = this.gMapContext.map;
29069 options.radius = radius;
29070 options.center = center;
29071 this.gMapContext.circle = new google.maps.Circle(options);
29072 return this.gMapContext.circle;
29078 setPosition: function(location)
29080 this.gMapContext.location = location;
29081 this.gMapContext.marker.setPosition(location);
29082 this.gMapContext.map.panTo(location);
29083 this.drawCircle(location, this.gMapContext.radius, {});
29087 if (this.gMapContext.settings.enableReverseGeocode) {
29088 this.gMapContext.geodecoder.geocode({
29089 latLng: this.gMapContext.location
29090 }, function(results, status) {
29092 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
29093 _this.gMapContext.locationName = results[0].formatted_address;
29094 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
29096 _this.fireEvent('positionchanged', this, location);
29103 this.fireEvent('positionchanged', this, location);
29108 google.maps.event.trigger(this.gMapContext.map, "resize");
29110 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
29112 this.fireEvent('resize', this);
29115 setPositionByLatLng: function(latitude, longitude)
29117 this.setPosition(new google.maps.LatLng(latitude, longitude));
29120 getCurrentPosition: function()
29123 latitude: this.gMapContext.location.lat(),
29124 longitude: this.gMapContext.location.lng()
29128 getAddressName: function()
29130 return this.gMapContext.locationName;
29133 getAddressComponents: function()
29135 return this.gMapContext.addressComponents;
29138 address_component_from_google_geocode: function(address_components)
29142 for (var i = 0; i < address_components.length; i++) {
29143 var component = address_components[i];
29144 if (component.types.indexOf("postal_code") >= 0) {
29145 result.postalCode = component.short_name;
29146 } else if (component.types.indexOf("street_number") >= 0) {
29147 result.streetNumber = component.short_name;
29148 } else if (component.types.indexOf("route") >= 0) {
29149 result.streetName = component.short_name;
29150 } else if (component.types.indexOf("neighborhood") >= 0) {
29151 result.city = component.short_name;
29152 } else if (component.types.indexOf("locality") >= 0) {
29153 result.city = component.short_name;
29154 } else if (component.types.indexOf("sublocality") >= 0) {
29155 result.district = component.short_name;
29156 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
29157 result.stateOrProvince = component.short_name;
29158 } else if (component.types.indexOf("country") >= 0) {
29159 result.country = component.short_name;
29163 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
29164 result.addressLine2 = "";
29168 setZoomLevel: function(zoom)
29170 this.gMapContext.map.setZoom(zoom);
29183 this.fireEvent('show', this);
29194 this.fireEvent('hide', this);
29199 Roo.apply(Roo.bootstrap.LocationPicker, {
29201 OverlayView : function(map, options)
29203 options = options || {};
29210 * @class Roo.bootstrap.Alert
29211 * @extends Roo.bootstrap.Component
29212 * Bootstrap Alert class - shows an alert area box
29214 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
29215 Enter a valid email address
29218 * @cfg {String} title The title of alert
29219 * @cfg {String} html The content of alert
29220 * @cfg {String} weight ( success | info | warning | danger )
29221 * @cfg {String} faicon font-awesomeicon
29224 * Create a new alert
29225 * @param {Object} config The config object
29229 Roo.bootstrap.Alert = function(config){
29230 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
29234 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
29241 getAutoCreate : function()
29250 cls : 'roo-alert-icon'
29255 cls : 'roo-alert-title',
29260 cls : 'roo-alert-text',
29267 cfg.cn[0].cls += ' fa ' + this.faicon;
29271 cfg.cls += ' alert-' + this.weight;
29277 initEvents: function()
29279 this.el.setVisibilityMode(Roo.Element.DISPLAY);
29282 setTitle : function(str)
29284 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
29287 setText : function(str)
29289 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
29292 setWeight : function(weight)
29295 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
29298 this.weight = weight;
29300 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
29303 setIcon : function(icon)
29306 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
29309 this.faicon = icon;
29311 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
29332 * @class Roo.bootstrap.UploadCropbox
29333 * @extends Roo.bootstrap.Component
29334 * Bootstrap UploadCropbox class
29335 * @cfg {String} emptyText show when image has been loaded
29336 * @cfg {String} rotateNotify show when image too small to rotate
29337 * @cfg {Number} errorTimeout default 3000
29338 * @cfg {Number} minWidth default 300
29339 * @cfg {Number} minHeight default 300
29340 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
29341 * @cfg {Boolean} isDocument (true|false) default false
29342 * @cfg {String} url action url
29343 * @cfg {String} paramName default 'imageUpload'
29344 * @cfg {String} method default POST
29345 * @cfg {Boolean} loadMask (true|false) default true
29346 * @cfg {Boolean} loadingText default 'Loading...'
29349 * Create a new UploadCropbox
29350 * @param {Object} config The config object
29353 Roo.bootstrap.UploadCropbox = function(config){
29354 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
29358 * @event beforeselectfile
29359 * Fire before select file
29360 * @param {Roo.bootstrap.UploadCropbox} this
29362 "beforeselectfile" : true,
29365 * Fire after initEvent
29366 * @param {Roo.bootstrap.UploadCropbox} this
29371 * Fire after initEvent
29372 * @param {Roo.bootstrap.UploadCropbox} this
29373 * @param {String} data
29378 * Fire when preparing the file data
29379 * @param {Roo.bootstrap.UploadCropbox} this
29380 * @param {Object} file
29385 * Fire when get exception
29386 * @param {Roo.bootstrap.UploadCropbox} this
29387 * @param {XMLHttpRequest} xhr
29389 "exception" : true,
29391 * @event beforeloadcanvas
29392 * Fire before load the canvas
29393 * @param {Roo.bootstrap.UploadCropbox} this
29394 * @param {String} src
29396 "beforeloadcanvas" : true,
29399 * Fire when trash image
29400 * @param {Roo.bootstrap.UploadCropbox} this
29405 * Fire when download the image
29406 * @param {Roo.bootstrap.UploadCropbox} this
29410 * @event footerbuttonclick
29411 * Fire when footerbuttonclick
29412 * @param {Roo.bootstrap.UploadCropbox} this
29413 * @param {String} type
29415 "footerbuttonclick" : true,
29419 * @param {Roo.bootstrap.UploadCropbox} this
29424 * Fire when rotate the image
29425 * @param {Roo.bootstrap.UploadCropbox} this
29426 * @param {String} pos
29431 * Fire when inspect the file
29432 * @param {Roo.bootstrap.UploadCropbox} this
29433 * @param {Object} file
29438 * Fire when xhr upload the file
29439 * @param {Roo.bootstrap.UploadCropbox} this
29440 * @param {Object} data
29445 * Fire when arrange the file data
29446 * @param {Roo.bootstrap.UploadCropbox} this
29447 * @param {Object} formData
29452 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
29455 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
29457 emptyText : 'Click to upload image',
29458 rotateNotify : 'Image is too small to rotate',
29459 errorTimeout : 3000,
29473 cropType : 'image/jpeg',
29475 canvasLoaded : false,
29476 isDocument : false,
29478 paramName : 'imageUpload',
29480 loadingText : 'Loading...',
29483 getAutoCreate : function()
29487 cls : 'roo-upload-cropbox',
29491 cls : 'roo-upload-cropbox-selector',
29496 cls : 'roo-upload-cropbox-body',
29497 style : 'cursor:pointer',
29501 cls : 'roo-upload-cropbox-preview'
29505 cls : 'roo-upload-cropbox-thumb'
29509 cls : 'roo-upload-cropbox-empty-notify',
29510 html : this.emptyText
29514 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
29515 html : this.rotateNotify
29521 cls : 'roo-upload-cropbox-footer',
29524 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
29534 onRender : function(ct, position)
29536 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
29538 if (this.buttons.length) {
29540 Roo.each(this.buttons, function(bb) {
29542 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
29544 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
29550 this.maskEl = this.el;
29554 initEvents : function()
29556 this.urlAPI = (window.createObjectURL && window) ||
29557 (window.URL && URL.revokeObjectURL && URL) ||
29558 (window.webkitURL && webkitURL);
29560 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
29561 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29563 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
29564 this.selectorEl.hide();
29566 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
29567 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29569 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
29570 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29571 this.thumbEl.hide();
29573 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
29574 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29576 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
29577 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29578 this.errorEl.hide();
29580 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
29581 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29582 this.footerEl.hide();
29584 this.setThumbBoxSize();
29590 this.fireEvent('initial', this);
29597 window.addEventListener("resize", function() { _this.resize(); } );
29599 this.bodyEl.on('click', this.beforeSelectFile, this);
29602 this.bodyEl.on('touchstart', this.onTouchStart, this);
29603 this.bodyEl.on('touchmove', this.onTouchMove, this);
29604 this.bodyEl.on('touchend', this.onTouchEnd, this);
29608 this.bodyEl.on('mousedown', this.onMouseDown, this);
29609 this.bodyEl.on('mousemove', this.onMouseMove, this);
29610 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
29611 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
29612 Roo.get(document).on('mouseup', this.onMouseUp, this);
29615 this.selectorEl.on('change', this.onFileSelected, this);
29621 this.baseScale = 1;
29623 this.baseRotate = 1;
29624 this.dragable = false;
29625 this.pinching = false;
29628 this.cropData = false;
29629 this.notifyEl.dom.innerHTML = this.emptyText;
29631 this.selectorEl.dom.value = '';
29635 resize : function()
29637 if(this.fireEvent('resize', this) != false){
29638 this.setThumbBoxPosition();
29639 this.setCanvasPosition();
29643 onFooterButtonClick : function(e, el, o, type)
29646 case 'rotate-left' :
29647 this.onRotateLeft(e);
29649 case 'rotate-right' :
29650 this.onRotateRight(e);
29653 this.beforeSelectFile(e);
29668 this.fireEvent('footerbuttonclick', this, type);
29671 beforeSelectFile : function(e)
29673 e.preventDefault();
29675 if(this.fireEvent('beforeselectfile', this) != false){
29676 this.selectorEl.dom.click();
29680 onFileSelected : function(e)
29682 e.preventDefault();
29684 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29688 var file = this.selectorEl.dom.files[0];
29690 if(this.fireEvent('inspect', this, file) != false){
29691 this.prepare(file);
29696 trash : function(e)
29698 this.fireEvent('trash', this);
29701 download : function(e)
29703 this.fireEvent('download', this);
29706 loadCanvas : function(src)
29708 if(this.fireEvent('beforeloadcanvas', this, src) != false){
29712 this.imageEl = document.createElement('img');
29716 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
29718 this.imageEl.src = src;
29722 onLoadCanvas : function()
29724 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
29725 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
29727 this.bodyEl.un('click', this.beforeSelectFile, this);
29729 this.notifyEl.hide();
29730 this.thumbEl.show();
29731 this.footerEl.show();
29733 this.baseRotateLevel();
29735 if(this.isDocument){
29736 this.setThumbBoxSize();
29739 this.setThumbBoxPosition();
29741 this.baseScaleLevel();
29747 this.canvasLoaded = true;
29750 this.maskEl.unmask();
29755 setCanvasPosition : function()
29757 if(!this.canvasEl){
29761 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
29762 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
29764 this.previewEl.setLeft(pw);
29765 this.previewEl.setTop(ph);
29769 onMouseDown : function(e)
29773 this.dragable = true;
29774 this.pinching = false;
29776 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
29777 this.dragable = false;
29781 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29782 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29786 onMouseMove : function(e)
29790 if(!this.canvasLoaded){
29794 if (!this.dragable){
29798 var minX = Math.ceil(this.thumbEl.getLeft(true));
29799 var minY = Math.ceil(this.thumbEl.getTop(true));
29801 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
29802 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
29804 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29805 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29807 x = x - this.mouseX;
29808 y = y - this.mouseY;
29810 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
29811 var bgY = Math.ceil(y + this.previewEl.getTop(true));
29813 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
29814 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
29816 this.previewEl.setLeft(bgX);
29817 this.previewEl.setTop(bgY);
29819 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29820 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29823 onMouseUp : function(e)
29827 this.dragable = false;
29830 onMouseWheel : function(e)
29834 this.startScale = this.scale;
29836 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
29838 if(!this.zoomable()){
29839 this.scale = this.startScale;
29848 zoomable : function()
29850 var minScale = this.thumbEl.getWidth() / this.minWidth;
29852 if(this.minWidth < this.minHeight){
29853 minScale = this.thumbEl.getHeight() / this.minHeight;
29856 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
29857 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
29861 (this.rotate == 0 || this.rotate == 180) &&
29863 width > this.imageEl.OriginWidth ||
29864 height > this.imageEl.OriginHeight ||
29865 (width < this.minWidth && height < this.minHeight)
29873 (this.rotate == 90 || this.rotate == 270) &&
29875 width > this.imageEl.OriginWidth ||
29876 height > this.imageEl.OriginHeight ||
29877 (width < this.minHeight && height < this.minWidth)
29884 !this.isDocument &&
29885 (this.rotate == 0 || this.rotate == 180) &&
29887 width < this.minWidth ||
29888 width > this.imageEl.OriginWidth ||
29889 height < this.minHeight ||
29890 height > this.imageEl.OriginHeight
29897 !this.isDocument &&
29898 (this.rotate == 90 || this.rotate == 270) &&
29900 width < this.minHeight ||
29901 width > this.imageEl.OriginWidth ||
29902 height < this.minWidth ||
29903 height > this.imageEl.OriginHeight
29913 onRotateLeft : function(e)
29915 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29917 var minScale = this.thumbEl.getWidth() / this.minWidth;
29919 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29920 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29922 this.startScale = this.scale;
29924 while (this.getScaleLevel() < minScale){
29926 this.scale = this.scale + 1;
29928 if(!this.zoomable()){
29933 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29934 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29939 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29946 this.scale = this.startScale;
29948 this.onRotateFail();
29953 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29955 if(this.isDocument){
29956 this.setThumbBoxSize();
29957 this.setThumbBoxPosition();
29958 this.setCanvasPosition();
29963 this.fireEvent('rotate', this, 'left');
29967 onRotateRight : function(e)
29969 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29971 var minScale = this.thumbEl.getWidth() / this.minWidth;
29973 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29974 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29976 this.startScale = this.scale;
29978 while (this.getScaleLevel() < minScale){
29980 this.scale = this.scale + 1;
29982 if(!this.zoomable()){
29987 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29988 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29993 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
30000 this.scale = this.startScale;
30002 this.onRotateFail();
30007 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
30009 if(this.isDocument){
30010 this.setThumbBoxSize();
30011 this.setThumbBoxPosition();
30012 this.setCanvasPosition();
30017 this.fireEvent('rotate', this, 'right');
30020 onRotateFail : function()
30022 this.errorEl.show(true);
30026 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
30031 this.previewEl.dom.innerHTML = '';
30033 var canvasEl = document.createElement("canvas");
30035 var contextEl = canvasEl.getContext("2d");
30037 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30038 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30039 var center = this.imageEl.OriginWidth / 2;
30041 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
30042 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30043 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30044 center = this.imageEl.OriginHeight / 2;
30047 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
30049 contextEl.translate(center, center);
30050 contextEl.rotate(this.rotate * Math.PI / 180);
30052 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30054 this.canvasEl = document.createElement("canvas");
30056 this.contextEl = this.canvasEl.getContext("2d");
30058 switch (this.rotate) {
30061 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30062 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30064 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30069 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30070 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30072 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30073 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);
30077 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30082 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30083 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30085 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30086 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);
30090 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);
30095 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30096 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30098 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30099 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30103 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);
30110 this.previewEl.appendChild(this.canvasEl);
30112 this.setCanvasPosition();
30117 if(!this.canvasLoaded){
30121 var imageCanvas = document.createElement("canvas");
30123 var imageContext = imageCanvas.getContext("2d");
30125 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
30126 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
30128 var center = imageCanvas.width / 2;
30130 imageContext.translate(center, center);
30132 imageContext.rotate(this.rotate * Math.PI / 180);
30134 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30136 var canvas = document.createElement("canvas");
30138 var context = canvas.getContext("2d");
30140 canvas.width = this.minWidth;
30141 canvas.height = this.minHeight;
30143 switch (this.rotate) {
30146 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30147 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30149 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30150 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30152 var targetWidth = this.minWidth - 2 * x;
30153 var targetHeight = this.minHeight - 2 * y;
30157 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30158 scale = targetWidth / width;
30161 if(x > 0 && y == 0){
30162 scale = targetHeight / height;
30165 if(x > 0 && y > 0){
30166 scale = targetWidth / width;
30168 if(width < height){
30169 scale = targetHeight / height;
30173 context.scale(scale, scale);
30175 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30176 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30178 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30179 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30181 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30186 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30187 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30189 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30190 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30192 var targetWidth = this.minWidth - 2 * x;
30193 var targetHeight = this.minHeight - 2 * y;
30197 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30198 scale = targetWidth / width;
30201 if(x > 0 && y == 0){
30202 scale = targetHeight / height;
30205 if(x > 0 && y > 0){
30206 scale = targetWidth / width;
30208 if(width < height){
30209 scale = targetHeight / height;
30213 context.scale(scale, scale);
30215 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30216 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30218 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30219 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30221 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30223 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30228 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30229 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30231 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30232 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30234 var targetWidth = this.minWidth - 2 * x;
30235 var targetHeight = this.minHeight - 2 * y;
30239 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30240 scale = targetWidth / width;
30243 if(x > 0 && y == 0){
30244 scale = targetHeight / height;
30247 if(x > 0 && y > 0){
30248 scale = targetWidth / width;
30250 if(width < height){
30251 scale = targetHeight / height;
30255 context.scale(scale, scale);
30257 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30258 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30260 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30261 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30263 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30264 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30266 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30271 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30272 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30274 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30275 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30277 var targetWidth = this.minWidth - 2 * x;
30278 var targetHeight = this.minHeight - 2 * y;
30282 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30283 scale = targetWidth / width;
30286 if(x > 0 && y == 0){
30287 scale = targetHeight / height;
30290 if(x > 0 && y > 0){
30291 scale = targetWidth / width;
30293 if(width < height){
30294 scale = targetHeight / height;
30298 context.scale(scale, scale);
30300 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30301 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30303 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30304 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30306 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30308 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30315 this.cropData = canvas.toDataURL(this.cropType);
30317 if(this.fireEvent('crop', this, this.cropData) !== false){
30318 this.process(this.file, this.cropData);
30325 setThumbBoxSize : function()
30329 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
30330 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
30331 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
30333 this.minWidth = width;
30334 this.minHeight = height;
30336 if(this.rotate == 90 || this.rotate == 270){
30337 this.minWidth = height;
30338 this.minHeight = width;
30343 width = Math.ceil(this.minWidth * height / this.minHeight);
30345 if(this.minWidth > this.minHeight){
30347 height = Math.ceil(this.minHeight * width / this.minWidth);
30350 this.thumbEl.setStyle({
30351 width : width + 'px',
30352 height : height + 'px'
30359 setThumbBoxPosition : function()
30361 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
30362 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
30364 this.thumbEl.setLeft(x);
30365 this.thumbEl.setTop(y);
30369 baseRotateLevel : function()
30371 this.baseRotate = 1;
30374 typeof(this.exif) != 'undefined' &&
30375 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
30376 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
30378 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
30381 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
30385 baseScaleLevel : function()
30389 if(this.isDocument){
30391 if(this.baseRotate == 6 || this.baseRotate == 8){
30393 height = this.thumbEl.getHeight();
30394 this.baseScale = height / this.imageEl.OriginWidth;
30396 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
30397 width = this.thumbEl.getWidth();
30398 this.baseScale = width / this.imageEl.OriginHeight;
30404 height = this.thumbEl.getHeight();
30405 this.baseScale = height / this.imageEl.OriginHeight;
30407 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
30408 width = this.thumbEl.getWidth();
30409 this.baseScale = width / this.imageEl.OriginWidth;
30415 if(this.baseRotate == 6 || this.baseRotate == 8){
30417 width = this.thumbEl.getHeight();
30418 this.baseScale = width / this.imageEl.OriginHeight;
30420 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
30421 height = this.thumbEl.getWidth();
30422 this.baseScale = height / this.imageEl.OriginHeight;
30425 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30426 height = this.thumbEl.getWidth();
30427 this.baseScale = height / this.imageEl.OriginHeight;
30429 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
30430 width = this.thumbEl.getHeight();
30431 this.baseScale = width / this.imageEl.OriginWidth;
30438 width = this.thumbEl.getWidth();
30439 this.baseScale = width / this.imageEl.OriginWidth;
30441 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
30442 height = this.thumbEl.getHeight();
30443 this.baseScale = height / this.imageEl.OriginHeight;
30446 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30448 height = this.thumbEl.getHeight();
30449 this.baseScale = height / this.imageEl.OriginHeight;
30451 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
30452 width = this.thumbEl.getWidth();
30453 this.baseScale = width / this.imageEl.OriginWidth;
30461 getScaleLevel : function()
30463 return this.baseScale * Math.pow(1.1, this.scale);
30466 onTouchStart : function(e)
30468 if(!this.canvasLoaded){
30469 this.beforeSelectFile(e);
30473 var touches = e.browserEvent.touches;
30479 if(touches.length == 1){
30480 this.onMouseDown(e);
30484 if(touches.length != 2){
30490 for(var i = 0, finger; finger = touches[i]; i++){
30491 coords.push(finger.pageX, finger.pageY);
30494 var x = Math.pow(coords[0] - coords[2], 2);
30495 var y = Math.pow(coords[1] - coords[3], 2);
30497 this.startDistance = Math.sqrt(x + y);
30499 this.startScale = this.scale;
30501 this.pinching = true;
30502 this.dragable = false;
30506 onTouchMove : function(e)
30508 if(!this.pinching && !this.dragable){
30512 var touches = e.browserEvent.touches;
30519 this.onMouseMove(e);
30525 for(var i = 0, finger; finger = touches[i]; i++){
30526 coords.push(finger.pageX, finger.pageY);
30529 var x = Math.pow(coords[0] - coords[2], 2);
30530 var y = Math.pow(coords[1] - coords[3], 2);
30532 this.endDistance = Math.sqrt(x + y);
30534 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
30536 if(!this.zoomable()){
30537 this.scale = this.startScale;
30545 onTouchEnd : function(e)
30547 this.pinching = false;
30548 this.dragable = false;
30552 process : function(file, crop)
30555 this.maskEl.mask(this.loadingText);
30558 this.xhr = new XMLHttpRequest();
30560 file.xhr = this.xhr;
30562 this.xhr.open(this.method, this.url, true);
30565 "Accept": "application/json",
30566 "Cache-Control": "no-cache",
30567 "X-Requested-With": "XMLHttpRequest"
30570 for (var headerName in headers) {
30571 var headerValue = headers[headerName];
30573 this.xhr.setRequestHeader(headerName, headerValue);
30579 this.xhr.onload = function()
30581 _this.xhrOnLoad(_this.xhr);
30584 this.xhr.onerror = function()
30586 _this.xhrOnError(_this.xhr);
30589 var formData = new FormData();
30591 formData.append('returnHTML', 'NO');
30594 formData.append('crop', crop);
30597 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
30598 formData.append(this.paramName, file, file.name);
30601 if(typeof(file.filename) != 'undefined'){
30602 formData.append('filename', file.filename);
30605 if(typeof(file.mimetype) != 'undefined'){
30606 formData.append('mimetype', file.mimetype);
30609 if(this.fireEvent('arrange', this, formData) != false){
30610 this.xhr.send(formData);
30614 xhrOnLoad : function(xhr)
30617 this.maskEl.unmask();
30620 if (xhr.readyState !== 4) {
30621 this.fireEvent('exception', this, xhr);
30625 var response = Roo.decode(xhr.responseText);
30627 if(!response.success){
30628 this.fireEvent('exception', this, xhr);
30632 var response = Roo.decode(xhr.responseText);
30634 this.fireEvent('upload', this, response);
30638 xhrOnError : function()
30641 this.maskEl.unmask();
30644 Roo.log('xhr on error');
30646 var response = Roo.decode(xhr.responseText);
30652 prepare : function(file)
30655 this.maskEl.mask(this.loadingText);
30661 if(typeof(file) === 'string'){
30662 this.loadCanvas(file);
30666 if(!file || !this.urlAPI){
30671 this.cropType = file.type;
30675 if(this.fireEvent('prepare', this, this.file) != false){
30677 var reader = new FileReader();
30679 reader.onload = function (e) {
30680 if (e.target.error) {
30681 Roo.log(e.target.error);
30685 var buffer = e.target.result,
30686 dataView = new DataView(buffer),
30688 maxOffset = dataView.byteLength - 4,
30692 if (dataView.getUint16(0) === 0xffd8) {
30693 while (offset < maxOffset) {
30694 markerBytes = dataView.getUint16(offset);
30696 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
30697 markerLength = dataView.getUint16(offset + 2) + 2;
30698 if (offset + markerLength > dataView.byteLength) {
30699 Roo.log('Invalid meta data: Invalid segment size.');
30703 if(markerBytes == 0xffe1){
30704 _this.parseExifData(
30711 offset += markerLength;
30721 var url = _this.urlAPI.createObjectURL(_this.file);
30723 _this.loadCanvas(url);
30728 reader.readAsArrayBuffer(this.file);
30734 parseExifData : function(dataView, offset, length)
30736 var tiffOffset = offset + 10,
30740 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30741 // No Exif data, might be XMP data instead
30745 // Check for the ASCII code for "Exif" (0x45786966):
30746 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30747 // No Exif data, might be XMP data instead
30750 if (tiffOffset + 8 > dataView.byteLength) {
30751 Roo.log('Invalid Exif data: Invalid segment size.');
30754 // Check for the two null bytes:
30755 if (dataView.getUint16(offset + 8) !== 0x0000) {
30756 Roo.log('Invalid Exif data: Missing byte alignment offset.');
30759 // Check the byte alignment:
30760 switch (dataView.getUint16(tiffOffset)) {
30762 littleEndian = true;
30765 littleEndian = false;
30768 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
30771 // Check for the TIFF tag marker (0x002A):
30772 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
30773 Roo.log('Invalid Exif data: Missing TIFF marker.');
30776 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
30777 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
30779 this.parseExifTags(
30782 tiffOffset + dirOffset,
30787 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
30792 if (dirOffset + 6 > dataView.byteLength) {
30793 Roo.log('Invalid Exif data: Invalid directory offset.');
30796 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
30797 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
30798 if (dirEndOffset + 4 > dataView.byteLength) {
30799 Roo.log('Invalid Exif data: Invalid directory size.');
30802 for (i = 0; i < tagsNumber; i += 1) {
30806 dirOffset + 2 + 12 * i, // tag offset
30810 // Return the offset to the next directory:
30811 return dataView.getUint32(dirEndOffset, littleEndian);
30814 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
30816 var tag = dataView.getUint16(offset, littleEndian);
30818 this.exif[tag] = this.getExifValue(
30822 dataView.getUint16(offset + 2, littleEndian), // tag type
30823 dataView.getUint32(offset + 4, littleEndian), // tag length
30828 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
30830 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
30839 Roo.log('Invalid Exif data: Invalid tag type.');
30843 tagSize = tagType.size * length;
30844 // Determine if the value is contained in the dataOffset bytes,
30845 // or if the value at the dataOffset is a pointer to the actual data:
30846 dataOffset = tagSize > 4 ?
30847 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
30848 if (dataOffset + tagSize > dataView.byteLength) {
30849 Roo.log('Invalid Exif data: Invalid data offset.');
30852 if (length === 1) {
30853 return tagType.getValue(dataView, dataOffset, littleEndian);
30856 for (i = 0; i < length; i += 1) {
30857 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
30860 if (tagType.ascii) {
30862 // Concatenate the chars:
30863 for (i = 0; i < values.length; i += 1) {
30865 // Ignore the terminating NULL byte(s):
30866 if (c === '\u0000') {
30878 Roo.apply(Roo.bootstrap.UploadCropbox, {
30880 'Orientation': 0x0112
30884 1: 0, //'top-left',
30886 3: 180, //'bottom-right',
30887 // 4: 'bottom-left',
30889 6: 90, //'right-top',
30890 // 7: 'right-bottom',
30891 8: 270 //'left-bottom'
30895 // byte, 8-bit unsigned int:
30897 getValue: function (dataView, dataOffset) {
30898 return dataView.getUint8(dataOffset);
30902 // ascii, 8-bit byte:
30904 getValue: function (dataView, dataOffset) {
30905 return String.fromCharCode(dataView.getUint8(dataOffset));
30910 // short, 16 bit int:
30912 getValue: function (dataView, dataOffset, littleEndian) {
30913 return dataView.getUint16(dataOffset, littleEndian);
30917 // long, 32 bit int:
30919 getValue: function (dataView, dataOffset, littleEndian) {
30920 return dataView.getUint32(dataOffset, littleEndian);
30924 // rational = two long values, first is numerator, second is denominator:
30926 getValue: function (dataView, dataOffset, littleEndian) {
30927 return dataView.getUint32(dataOffset, littleEndian) /
30928 dataView.getUint32(dataOffset + 4, littleEndian);
30932 // slong, 32 bit signed int:
30934 getValue: function (dataView, dataOffset, littleEndian) {
30935 return dataView.getInt32(dataOffset, littleEndian);
30939 // srational, two slongs, first is numerator, second is denominator:
30941 getValue: function (dataView, dataOffset, littleEndian) {
30942 return dataView.getInt32(dataOffset, littleEndian) /
30943 dataView.getInt32(dataOffset + 4, littleEndian);
30953 cls : 'btn-group roo-upload-cropbox-rotate-left',
30954 action : 'rotate-left',
30958 cls : 'btn btn-default',
30959 html : '<i class="fa fa-undo"></i>'
30965 cls : 'btn-group roo-upload-cropbox-picture',
30966 action : 'picture',
30970 cls : 'btn btn-default',
30971 html : '<i class="fa fa-picture-o"></i>'
30977 cls : 'btn-group roo-upload-cropbox-rotate-right',
30978 action : 'rotate-right',
30982 cls : 'btn btn-default',
30983 html : '<i class="fa fa-repeat"></i>'
30991 cls : 'btn-group roo-upload-cropbox-rotate-left',
30992 action : 'rotate-left',
30996 cls : 'btn btn-default',
30997 html : '<i class="fa fa-undo"></i>'
31003 cls : 'btn-group roo-upload-cropbox-download',
31004 action : 'download',
31008 cls : 'btn btn-default',
31009 html : '<i class="fa fa-download"></i>'
31015 cls : 'btn-group roo-upload-cropbox-crop',
31020 cls : 'btn btn-default',
31021 html : '<i class="fa fa-crop"></i>'
31027 cls : 'btn-group roo-upload-cropbox-trash',
31032 cls : 'btn btn-default',
31033 html : '<i class="fa fa-trash"></i>'
31039 cls : 'btn-group roo-upload-cropbox-rotate-right',
31040 action : 'rotate-right',
31044 cls : 'btn btn-default',
31045 html : '<i class="fa fa-repeat"></i>'
31053 cls : 'btn-group roo-upload-cropbox-rotate-left',
31054 action : 'rotate-left',
31058 cls : 'btn btn-default',
31059 html : '<i class="fa fa-undo"></i>'
31065 cls : 'btn-group roo-upload-cropbox-rotate-right',
31066 action : 'rotate-right',
31070 cls : 'btn btn-default',
31071 html : '<i class="fa fa-repeat"></i>'
31084 * @class Roo.bootstrap.DocumentManager
31085 * @extends Roo.bootstrap.Component
31086 * Bootstrap DocumentManager class
31087 * @cfg {String} paramName default 'imageUpload'
31088 * @cfg {String} toolTipName default 'filename'
31089 * @cfg {String} method default POST
31090 * @cfg {String} url action url
31091 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
31092 * @cfg {Boolean} multiple multiple upload default true
31093 * @cfg {Number} thumbSize default 300
31094 * @cfg {String} fieldLabel
31095 * @cfg {Number} labelWidth default 4
31096 * @cfg {String} labelAlign (left|top) default left
31097 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
31098 * @cfg {Number} labellg set the width of label (1-12)
31099 * @cfg {Number} labelmd set the width of label (1-12)
31100 * @cfg {Number} labelsm set the width of label (1-12)
31101 * @cfg {Number} labelxs set the width of label (1-12)
31104 * Create a new DocumentManager
31105 * @param {Object} config The config object
31108 Roo.bootstrap.DocumentManager = function(config){
31109 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
31112 this.delegates = [];
31117 * Fire when initial the DocumentManager
31118 * @param {Roo.bootstrap.DocumentManager} this
31123 * inspect selected file
31124 * @param {Roo.bootstrap.DocumentManager} this
31125 * @param {File} file
31130 * Fire when xhr load exception
31131 * @param {Roo.bootstrap.DocumentManager} this
31132 * @param {XMLHttpRequest} xhr
31134 "exception" : true,
31136 * @event afterupload
31137 * Fire when xhr load exception
31138 * @param {Roo.bootstrap.DocumentManager} this
31139 * @param {XMLHttpRequest} xhr
31141 "afterupload" : true,
31144 * prepare the form data
31145 * @param {Roo.bootstrap.DocumentManager} this
31146 * @param {Object} formData
31151 * Fire when remove the file
31152 * @param {Roo.bootstrap.DocumentManager} this
31153 * @param {Object} file
31158 * Fire after refresh the file
31159 * @param {Roo.bootstrap.DocumentManager} this
31164 * Fire after click the image
31165 * @param {Roo.bootstrap.DocumentManager} this
31166 * @param {Object} file
31171 * Fire when upload a image and editable set to true
31172 * @param {Roo.bootstrap.DocumentManager} this
31173 * @param {Object} file
31177 * @event beforeselectfile
31178 * Fire before select file
31179 * @param {Roo.bootstrap.DocumentManager} this
31181 "beforeselectfile" : true,
31184 * Fire before process file
31185 * @param {Roo.bootstrap.DocumentManager} this
31186 * @param {Object} file
31190 * @event previewrendered
31191 * Fire when preview rendered
31192 * @param {Roo.bootstrap.DocumentManager} this
31193 * @param {Object} file
31195 "previewrendered" : true,
31198 "previewResize" : true
31203 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
31212 paramName : 'imageUpload',
31213 toolTipName : 'filename',
31216 labelAlign : 'left',
31226 getAutoCreate : function()
31228 var managerWidget = {
31230 cls : 'roo-document-manager',
31234 cls : 'roo-document-manager-selector',
31239 cls : 'roo-document-manager-uploader',
31243 cls : 'roo-document-manager-upload-btn',
31244 html : '<i class="fa fa-plus"></i>'
31255 cls : 'column col-md-12',
31260 if(this.fieldLabel.length){
31265 cls : 'column col-md-12',
31266 html : this.fieldLabel
31270 cls : 'column col-md-12',
31275 if(this.labelAlign == 'left'){
31280 html : this.fieldLabel
31289 if(this.labelWidth > 12){
31290 content[0].style = "width: " + this.labelWidth + 'px';
31293 if(this.labelWidth < 13 && this.labelmd == 0){
31294 this.labelmd = this.labelWidth;
31297 if(this.labellg > 0){
31298 content[0].cls += ' col-lg-' + this.labellg;
31299 content[1].cls += ' col-lg-' + (12 - this.labellg);
31302 if(this.labelmd > 0){
31303 content[0].cls += ' col-md-' + this.labelmd;
31304 content[1].cls += ' col-md-' + (12 - this.labelmd);
31307 if(this.labelsm > 0){
31308 content[0].cls += ' col-sm-' + this.labelsm;
31309 content[1].cls += ' col-sm-' + (12 - this.labelsm);
31312 if(this.labelxs > 0){
31313 content[0].cls += ' col-xs-' + this.labelxs;
31314 content[1].cls += ' col-xs-' + (12 - this.labelxs);
31322 cls : 'row clearfix',
31330 initEvents : function()
31332 this.managerEl = this.el.select('.roo-document-manager', true).first();
31333 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31335 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
31336 this.selectorEl.hide();
31339 this.selectorEl.attr('multiple', 'multiple');
31342 this.selectorEl.on('change', this.onFileSelected, this);
31344 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
31345 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31347 this.uploader.on('click', this.onUploaderClick, this);
31349 this.renderProgressDialog();
31353 window.addEventListener("resize", function() { _this.refresh(); } );
31355 this.fireEvent('initial', this);
31358 renderProgressDialog : function()
31362 this.progressDialog = new Roo.bootstrap.Modal({
31363 cls : 'roo-document-manager-progress-dialog',
31364 allow_close : false,
31375 btnclick : function() {
31376 _this.uploadCancel();
31382 this.progressDialog.render(Roo.get(document.body));
31384 this.progress = new Roo.bootstrap.Progress({
31385 cls : 'roo-document-manager-progress',
31390 this.progress.render(this.progressDialog.getChildContainer());
31392 this.progressBar = new Roo.bootstrap.ProgressBar({
31393 cls : 'roo-document-manager-progress-bar',
31396 aria_valuemax : 12,
31400 this.progressBar.render(this.progress.getChildContainer());
31403 onUploaderClick : function(e)
31405 e.preventDefault();
31407 if(this.fireEvent('beforeselectfile', this) != false){
31408 this.selectorEl.dom.click();
31413 onFileSelected : function(e)
31415 e.preventDefault();
31417 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
31421 Roo.each(this.selectorEl.dom.files, function(file){
31422 if(this.fireEvent('inspect', this, file) != false){
31423 this.files.push(file);
31433 this.selectorEl.dom.value = '';
31435 if(!this.files || !this.files.length){
31439 if(this.boxes > 0 && this.files.length > this.boxes){
31440 this.files = this.files.slice(0, this.boxes);
31443 this.uploader.show();
31445 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31446 this.uploader.hide();
31455 Roo.each(this.files, function(file){
31457 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31458 var f = this.renderPreview(file);
31463 if(file.type.indexOf('image') != -1){
31464 this.delegates.push(
31466 _this.process(file);
31467 }).createDelegate(this)
31475 _this.process(file);
31476 }).createDelegate(this)
31481 this.files = files;
31483 this.delegates = this.delegates.concat(docs);
31485 if(!this.delegates.length){
31490 this.progressBar.aria_valuemax = this.delegates.length;
31497 arrange : function()
31499 if(!this.delegates.length){
31500 this.progressDialog.hide();
31505 var delegate = this.delegates.shift();
31507 this.progressDialog.show();
31509 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
31511 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
31516 refresh : function()
31518 this.uploader.show();
31520 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31521 this.uploader.hide();
31524 Roo.isTouch ? this.closable(false) : this.closable(true);
31526 this.fireEvent('refresh', this);
31529 onRemove : function(e, el, o)
31531 e.preventDefault();
31533 this.fireEvent('remove', this, o);
31537 remove : function(o)
31541 Roo.each(this.files, function(file){
31542 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
31551 this.files = files;
31558 Roo.each(this.files, function(file){
31563 file.target.remove();
31572 onClick : function(e, el, o)
31574 e.preventDefault();
31576 this.fireEvent('click', this, o);
31580 closable : function(closable)
31582 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
31584 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31596 xhrOnLoad : function(xhr)
31598 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31602 if (xhr.readyState !== 4) {
31604 this.fireEvent('exception', this, xhr);
31608 var response = Roo.decode(xhr.responseText);
31610 if(!response.success){
31612 this.fireEvent('exception', this, xhr);
31616 var file = this.renderPreview(response.data);
31618 this.files.push(file);
31622 this.fireEvent('afterupload', this, xhr);
31626 xhrOnError : function(xhr)
31628 Roo.log('xhr on error');
31630 var response = Roo.decode(xhr.responseText);
31637 process : function(file)
31639 if(this.fireEvent('process', this, file) !== false){
31640 if(this.editable && file.type.indexOf('image') != -1){
31641 this.fireEvent('edit', this, file);
31645 this.uploadStart(file, false);
31652 uploadStart : function(file, crop)
31654 this.xhr = new XMLHttpRequest();
31656 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31661 file.xhr = this.xhr;
31663 this.managerEl.createChild({
31665 cls : 'roo-document-manager-loading',
31669 tooltip : file.name,
31670 cls : 'roo-document-manager-thumb',
31671 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31677 this.xhr.open(this.method, this.url, true);
31680 "Accept": "application/json",
31681 "Cache-Control": "no-cache",
31682 "X-Requested-With": "XMLHttpRequest"
31685 for (var headerName in headers) {
31686 var headerValue = headers[headerName];
31688 this.xhr.setRequestHeader(headerName, headerValue);
31694 this.xhr.onload = function()
31696 _this.xhrOnLoad(_this.xhr);
31699 this.xhr.onerror = function()
31701 _this.xhrOnError(_this.xhr);
31704 var formData = new FormData();
31706 formData.append('returnHTML', 'NO');
31709 formData.append('crop', crop);
31712 formData.append(this.paramName, file, file.name);
31719 if(this.fireEvent('prepare', this, formData, options) != false){
31721 if(options.manually){
31725 this.xhr.send(formData);
31729 this.uploadCancel();
31732 uploadCancel : function()
31738 this.delegates = [];
31740 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31747 renderPreview : function(file)
31749 if(typeof(file.target) != 'undefined' && file.target){
31753 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
31755 var previewEl = this.managerEl.createChild({
31757 cls : 'roo-document-manager-preview',
31761 tooltip : file[this.toolTipName],
31762 cls : 'roo-document-manager-thumb',
31763 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
31768 html : '<i class="fa fa-times-circle"></i>'
31773 var close = previewEl.select('button.close', true).first();
31775 close.on('click', this.onRemove, this, file);
31777 file.target = previewEl;
31779 var image = previewEl.select('img', true).first();
31783 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
31785 image.on('click', this.onClick, this, file);
31787 this.fireEvent('previewrendered', this, file);
31793 onPreviewLoad : function(file, image)
31795 if(typeof(file.target) == 'undefined' || !file.target){
31799 var width = image.dom.naturalWidth || image.dom.width;
31800 var height = image.dom.naturalHeight || image.dom.height;
31802 if(!this.previewResize) {
31806 if(width > height){
31807 file.target.addClass('wide');
31811 file.target.addClass('tall');
31816 uploadFromSource : function(file, crop)
31818 this.xhr = new XMLHttpRequest();
31820 this.managerEl.createChild({
31822 cls : 'roo-document-manager-loading',
31826 tooltip : file.name,
31827 cls : 'roo-document-manager-thumb',
31828 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31834 this.xhr.open(this.method, this.url, true);
31837 "Accept": "application/json",
31838 "Cache-Control": "no-cache",
31839 "X-Requested-With": "XMLHttpRequest"
31842 for (var headerName in headers) {
31843 var headerValue = headers[headerName];
31845 this.xhr.setRequestHeader(headerName, headerValue);
31851 this.xhr.onload = function()
31853 _this.xhrOnLoad(_this.xhr);
31856 this.xhr.onerror = function()
31858 _this.xhrOnError(_this.xhr);
31861 var formData = new FormData();
31863 formData.append('returnHTML', 'NO');
31865 formData.append('crop', crop);
31867 if(typeof(file.filename) != 'undefined'){
31868 formData.append('filename', file.filename);
31871 if(typeof(file.mimetype) != 'undefined'){
31872 formData.append('mimetype', file.mimetype);
31877 if(this.fireEvent('prepare', this, formData) != false){
31878 this.xhr.send(formData);
31888 * @class Roo.bootstrap.DocumentViewer
31889 * @extends Roo.bootstrap.Component
31890 * Bootstrap DocumentViewer class
31891 * @cfg {Boolean} showDownload (true|false) show download button (default true)
31892 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
31895 * Create a new DocumentViewer
31896 * @param {Object} config The config object
31899 Roo.bootstrap.DocumentViewer = function(config){
31900 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
31905 * Fire after initEvent
31906 * @param {Roo.bootstrap.DocumentViewer} this
31912 * @param {Roo.bootstrap.DocumentViewer} this
31917 * Fire after download button
31918 * @param {Roo.bootstrap.DocumentViewer} this
31923 * Fire after trash button
31924 * @param {Roo.bootstrap.DocumentViewer} this
31931 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31933 showDownload : true,
31937 getAutoCreate : function()
31941 cls : 'roo-document-viewer',
31945 cls : 'roo-document-viewer-body',
31949 cls : 'roo-document-viewer-thumb',
31953 cls : 'roo-document-viewer-image'
31961 cls : 'roo-document-viewer-footer',
31964 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31968 cls : 'btn-group roo-document-viewer-download',
31972 cls : 'btn btn-default',
31973 html : '<i class="fa fa-download"></i>'
31979 cls : 'btn-group roo-document-viewer-trash',
31983 cls : 'btn btn-default',
31984 html : '<i class="fa fa-trash"></i>'
31997 initEvents : function()
31999 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
32000 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32002 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
32003 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32005 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
32006 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32008 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
32009 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
32011 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
32012 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
32014 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
32015 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
32017 this.bodyEl.on('click', this.onClick, this);
32018 this.downloadBtn.on('click', this.onDownload, this);
32019 this.trashBtn.on('click', this.onTrash, this);
32021 this.downloadBtn.hide();
32022 this.trashBtn.hide();
32024 if(this.showDownload){
32025 this.downloadBtn.show();
32028 if(this.showTrash){
32029 this.trashBtn.show();
32032 if(!this.showDownload && !this.showTrash) {
32033 this.footerEl.hide();
32038 initial : function()
32040 this.fireEvent('initial', this);
32044 onClick : function(e)
32046 e.preventDefault();
32048 this.fireEvent('click', this);
32051 onDownload : function(e)
32053 e.preventDefault();
32055 this.fireEvent('download', this);
32058 onTrash : function(e)
32060 e.preventDefault();
32062 this.fireEvent('trash', this);
32074 * @class Roo.bootstrap.NavProgressBar
32075 * @extends Roo.bootstrap.Component
32076 * Bootstrap NavProgressBar class
32079 * Create a new nav progress bar
32080 * @param {Object} config The config object
32083 Roo.bootstrap.NavProgressBar = function(config){
32084 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
32086 this.bullets = this.bullets || [];
32088 // Roo.bootstrap.NavProgressBar.register(this);
32092 * Fires when the active item changes
32093 * @param {Roo.bootstrap.NavProgressBar} this
32094 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
32095 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
32102 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
32107 getAutoCreate : function()
32109 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
32113 cls : 'roo-navigation-bar-group',
32117 cls : 'roo-navigation-top-bar'
32121 cls : 'roo-navigation-bullets-bar',
32125 cls : 'roo-navigation-bar'
32132 cls : 'roo-navigation-bottom-bar'
32142 initEvents: function()
32147 onRender : function(ct, position)
32149 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32151 if(this.bullets.length){
32152 Roo.each(this.bullets, function(b){
32161 addItem : function(cfg)
32163 var item = new Roo.bootstrap.NavProgressItem(cfg);
32165 item.parentId = this.id;
32166 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
32169 var top = new Roo.bootstrap.Element({
32171 cls : 'roo-navigation-bar-text'
32174 var bottom = new Roo.bootstrap.Element({
32176 cls : 'roo-navigation-bar-text'
32179 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
32180 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
32182 var topText = new Roo.bootstrap.Element({
32184 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
32187 var bottomText = new Roo.bootstrap.Element({
32189 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
32192 topText.onRender(top.el, null);
32193 bottomText.onRender(bottom.el, null);
32196 item.bottomEl = bottom;
32199 this.barItems.push(item);
32204 getActive : function()
32206 var active = false;
32208 Roo.each(this.barItems, function(v){
32210 if (!v.isActive()) {
32222 setActiveItem : function(item)
32226 Roo.each(this.barItems, function(v){
32227 if (v.rid == item.rid) {
32231 if (v.isActive()) {
32232 v.setActive(false);
32237 item.setActive(true);
32239 this.fireEvent('changed', this, item, prev);
32242 getBarItem: function(rid)
32246 Roo.each(this.barItems, function(e) {
32247 if (e.rid != rid) {
32258 indexOfItem : function(item)
32262 Roo.each(this.barItems, function(v, i){
32264 if (v.rid != item.rid) {
32275 setActiveNext : function()
32277 var i = this.indexOfItem(this.getActive());
32279 if (i > this.barItems.length) {
32283 this.setActiveItem(this.barItems[i+1]);
32286 setActivePrev : function()
32288 var i = this.indexOfItem(this.getActive());
32294 this.setActiveItem(this.barItems[i-1]);
32297 format : function()
32299 if(!this.barItems.length){
32303 var width = 100 / this.barItems.length;
32305 Roo.each(this.barItems, function(i){
32306 i.el.setStyle('width', width + '%');
32307 i.topEl.el.setStyle('width', width + '%');
32308 i.bottomEl.el.setStyle('width', width + '%');
32317 * Nav Progress Item
32322 * @class Roo.bootstrap.NavProgressItem
32323 * @extends Roo.bootstrap.Component
32324 * Bootstrap NavProgressItem class
32325 * @cfg {String} rid the reference id
32326 * @cfg {Boolean} active (true|false) Is item active default false
32327 * @cfg {Boolean} disabled (true|false) Is item active default false
32328 * @cfg {String} html
32329 * @cfg {String} position (top|bottom) text position default bottom
32330 * @cfg {String} icon show icon instead of number
32333 * Create a new NavProgressItem
32334 * @param {Object} config The config object
32336 Roo.bootstrap.NavProgressItem = function(config){
32337 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
32342 * The raw click event for the entire grid.
32343 * @param {Roo.bootstrap.NavProgressItem} this
32344 * @param {Roo.EventObject} e
32351 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
32357 position : 'bottom',
32360 getAutoCreate : function()
32362 var iconCls = 'roo-navigation-bar-item-icon';
32364 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
32368 cls: 'roo-navigation-bar-item',
32378 cfg.cls += ' active';
32381 cfg.cls += ' disabled';
32387 disable : function()
32389 this.setDisabled(true);
32392 enable : function()
32394 this.setDisabled(false);
32397 initEvents: function()
32399 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
32401 this.iconEl.on('click', this.onClick, this);
32404 onClick : function(e)
32406 e.preventDefault();
32412 if(this.fireEvent('click', this, e) === false){
32416 this.parent().setActiveItem(this);
32419 isActive: function ()
32421 return this.active;
32424 setActive : function(state)
32426 if(this.active == state){
32430 this.active = state;
32433 this.el.addClass('active');
32437 this.el.removeClass('active');
32442 setDisabled : function(state)
32444 if(this.disabled == state){
32448 this.disabled = state;
32451 this.el.addClass('disabled');
32455 this.el.removeClass('disabled');
32458 tooltipEl : function()
32460 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
32473 * @class Roo.bootstrap.FieldLabel
32474 * @extends Roo.bootstrap.Component
32475 * Bootstrap FieldLabel class
32476 * @cfg {String} html contents of the element
32477 * @cfg {String} tag tag of the element default label
32478 * @cfg {String} cls class of the element
32479 * @cfg {String} target label target
32480 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
32481 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
32482 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
32483 * @cfg {String} iconTooltip default "This field is required"
32484 * @cfg {String} indicatorpos (left|right) default left
32487 * Create a new FieldLabel
32488 * @param {Object} config The config object
32491 Roo.bootstrap.FieldLabel = function(config){
32492 Roo.bootstrap.Element.superclass.constructor.call(this, config);
32497 * Fires after the field has been marked as invalid.
32498 * @param {Roo.form.FieldLabel} this
32499 * @param {String} msg The validation message
32504 * Fires after the field has been validated with no errors.
32505 * @param {Roo.form.FieldLabel} this
32511 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
32518 invalidClass : 'has-warning',
32519 validClass : 'has-success',
32520 iconTooltip : 'This field is required',
32521 indicatorpos : 'left',
32523 getAutoCreate : function(){
32526 if (!this.allowBlank) {
32532 cls : 'roo-bootstrap-field-label ' + this.cls,
32537 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
32538 tooltip : this.iconTooltip
32547 if(this.indicatorpos == 'right'){
32550 cls : 'roo-bootstrap-field-label ' + this.cls,
32559 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
32560 tooltip : this.iconTooltip
32569 initEvents: function()
32571 Roo.bootstrap.Element.superclass.initEvents.call(this);
32573 this.indicator = this.indicatorEl();
32575 if(this.indicator){
32576 this.indicator.removeClass('visible');
32577 this.indicator.addClass('invisible');
32580 Roo.bootstrap.FieldLabel.register(this);
32583 indicatorEl : function()
32585 var indicator = this.el.select('i.roo-required-indicator',true).first();
32596 * Mark this field as valid
32598 markValid : function()
32600 if(this.indicator){
32601 this.indicator.removeClass('visible');
32602 this.indicator.addClass('invisible');
32604 if (Roo.bootstrap.version == 3) {
32605 this.el.removeClass(this.invalidClass);
32606 this.el.addClass(this.validClass);
32608 this.el.removeClass('is-invalid');
32609 this.el.addClass('is-valid');
32613 this.fireEvent('valid', this);
32617 * Mark this field as invalid
32618 * @param {String} msg The validation message
32620 markInvalid : function(msg)
32622 if(this.indicator){
32623 this.indicator.removeClass('invisible');
32624 this.indicator.addClass('visible');
32626 if (Roo.bootstrap.version == 3) {
32627 this.el.removeClass(this.validClass);
32628 this.el.addClass(this.invalidClass);
32630 this.el.removeClass('is-valid');
32631 this.el.addClass('is-invalid');
32635 this.fireEvent('invalid', this, msg);
32641 Roo.apply(Roo.bootstrap.FieldLabel, {
32646 * register a FieldLabel Group
32647 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
32649 register : function(label)
32651 if(this.groups.hasOwnProperty(label.target)){
32655 this.groups[label.target] = label;
32659 * fetch a FieldLabel Group based on the target
32660 * @param {string} target
32661 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
32663 get: function(target) {
32664 if (typeof(this.groups[target]) == 'undefined') {
32668 return this.groups[target] ;
32677 * page DateSplitField.
32683 * @class Roo.bootstrap.DateSplitField
32684 * @extends Roo.bootstrap.Component
32685 * Bootstrap DateSplitField class
32686 * @cfg {string} fieldLabel - the label associated
32687 * @cfg {Number} labelWidth set the width of label (0-12)
32688 * @cfg {String} labelAlign (top|left)
32689 * @cfg {Boolean} dayAllowBlank (true|false) default false
32690 * @cfg {Boolean} monthAllowBlank (true|false) default false
32691 * @cfg {Boolean} yearAllowBlank (true|false) default false
32692 * @cfg {string} dayPlaceholder
32693 * @cfg {string} monthPlaceholder
32694 * @cfg {string} yearPlaceholder
32695 * @cfg {string} dayFormat default 'd'
32696 * @cfg {string} monthFormat default 'm'
32697 * @cfg {string} yearFormat default 'Y'
32698 * @cfg {Number} labellg set the width of label (1-12)
32699 * @cfg {Number} labelmd set the width of label (1-12)
32700 * @cfg {Number} labelsm set the width of label (1-12)
32701 * @cfg {Number} labelxs set the width of label (1-12)
32705 * Create a new DateSplitField
32706 * @param {Object} config The config object
32709 Roo.bootstrap.DateSplitField = function(config){
32710 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
32716 * getting the data of years
32717 * @param {Roo.bootstrap.DateSplitField} this
32718 * @param {Object} years
32723 * getting the data of days
32724 * @param {Roo.bootstrap.DateSplitField} this
32725 * @param {Object} days
32730 * Fires after the field has been marked as invalid.
32731 * @param {Roo.form.Field} this
32732 * @param {String} msg The validation message
32737 * Fires after the field has been validated with no errors.
32738 * @param {Roo.form.Field} this
32744 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
32747 labelAlign : 'top',
32749 dayAllowBlank : false,
32750 monthAllowBlank : false,
32751 yearAllowBlank : false,
32752 dayPlaceholder : '',
32753 monthPlaceholder : '',
32754 yearPlaceholder : '',
32758 isFormField : true,
32764 getAutoCreate : function()
32768 cls : 'row roo-date-split-field-group',
32773 cls : 'form-hidden-field roo-date-split-field-group-value',
32779 var labelCls = 'col-md-12';
32780 var contentCls = 'col-md-4';
32782 if(this.fieldLabel){
32786 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
32790 html : this.fieldLabel
32795 if(this.labelAlign == 'left'){
32797 if(this.labelWidth > 12){
32798 label.style = "width: " + this.labelWidth + 'px';
32801 if(this.labelWidth < 13 && this.labelmd == 0){
32802 this.labelmd = this.labelWidth;
32805 if(this.labellg > 0){
32806 labelCls = ' col-lg-' + this.labellg;
32807 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
32810 if(this.labelmd > 0){
32811 labelCls = ' col-md-' + this.labelmd;
32812 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
32815 if(this.labelsm > 0){
32816 labelCls = ' col-sm-' + this.labelsm;
32817 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
32820 if(this.labelxs > 0){
32821 labelCls = ' col-xs-' + this.labelxs;
32822 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
32826 label.cls += ' ' + labelCls;
32828 cfg.cn.push(label);
32831 Roo.each(['day', 'month', 'year'], function(t){
32834 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
32841 inputEl: function ()
32843 return this.el.select('.roo-date-split-field-group-value', true).first();
32846 onRender : function(ct, position)
32850 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32852 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
32854 this.dayField = new Roo.bootstrap.ComboBox({
32855 allowBlank : this.dayAllowBlank,
32856 alwaysQuery : true,
32857 displayField : 'value',
32860 forceSelection : true,
32862 placeholder : this.dayPlaceholder,
32863 selectOnFocus : true,
32864 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32865 triggerAction : 'all',
32867 valueField : 'value',
32868 store : new Roo.data.SimpleStore({
32869 data : (function() {
32871 _this.fireEvent('days', _this, days);
32874 fields : [ 'value' ]
32877 select : function (_self, record, index)
32879 _this.setValue(_this.getValue());
32884 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
32886 this.monthField = new Roo.bootstrap.MonthField({
32887 after : '<i class=\"fa fa-calendar\"></i>',
32888 allowBlank : this.monthAllowBlank,
32889 placeholder : this.monthPlaceholder,
32892 render : function (_self)
32894 this.el.select('span.input-group-addon', true).first().on('click', function(e){
32895 e.preventDefault();
32899 select : function (_self, oldvalue, newvalue)
32901 _this.setValue(_this.getValue());
32906 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
32908 this.yearField = new Roo.bootstrap.ComboBox({
32909 allowBlank : this.yearAllowBlank,
32910 alwaysQuery : true,
32911 displayField : 'value',
32914 forceSelection : true,
32916 placeholder : this.yearPlaceholder,
32917 selectOnFocus : true,
32918 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32919 triggerAction : 'all',
32921 valueField : 'value',
32922 store : new Roo.data.SimpleStore({
32923 data : (function() {
32925 _this.fireEvent('years', _this, years);
32928 fields : [ 'value' ]
32931 select : function (_self, record, index)
32933 _this.setValue(_this.getValue());
32938 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32941 setValue : function(v, format)
32943 this.inputEl.dom.value = v;
32945 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32947 var d = Date.parseDate(v, f);
32954 this.setDay(d.format(this.dayFormat));
32955 this.setMonth(d.format(this.monthFormat));
32956 this.setYear(d.format(this.yearFormat));
32963 setDay : function(v)
32965 this.dayField.setValue(v);
32966 this.inputEl.dom.value = this.getValue();
32971 setMonth : function(v)
32973 this.monthField.setValue(v, true);
32974 this.inputEl.dom.value = this.getValue();
32979 setYear : function(v)
32981 this.yearField.setValue(v);
32982 this.inputEl.dom.value = this.getValue();
32987 getDay : function()
32989 return this.dayField.getValue();
32992 getMonth : function()
32994 return this.monthField.getValue();
32997 getYear : function()
32999 return this.yearField.getValue();
33002 getValue : function()
33004 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
33006 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
33016 this.inputEl.dom.value = '';
33021 validate : function()
33023 var d = this.dayField.validate();
33024 var m = this.monthField.validate();
33025 var y = this.yearField.validate();
33030 (!this.dayAllowBlank && !d) ||
33031 (!this.monthAllowBlank && !m) ||
33032 (!this.yearAllowBlank && !y)
33037 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
33046 this.markInvalid();
33051 markValid : function()
33054 var label = this.el.select('label', true).first();
33055 var icon = this.el.select('i.fa-star', true).first();
33061 this.fireEvent('valid', this);
33065 * Mark this field as invalid
33066 * @param {String} msg The validation message
33068 markInvalid : function(msg)
33071 var label = this.el.select('label', true).first();
33072 var icon = this.el.select('i.fa-star', true).first();
33074 if(label && !icon){
33075 this.el.select('.roo-date-split-field-label', true).createChild({
33077 cls : 'text-danger fa fa-lg fa-star',
33078 tooltip : 'This field is required',
33079 style : 'margin-right:5px;'
33083 this.fireEvent('invalid', this, msg);
33086 clearInvalid : function()
33088 var label = this.el.select('label', true).first();
33089 var icon = this.el.select('i.fa-star', true).first();
33095 this.fireEvent('valid', this);
33098 getName: function()
33108 * http://masonry.desandro.com
33110 * The idea is to render all the bricks based on vertical width...
33112 * The original code extends 'outlayer' - we might need to use that....
33118 * @class Roo.bootstrap.LayoutMasonry
33119 * @extends Roo.bootstrap.Component
33120 * Bootstrap Layout Masonry class
33123 * Create a new Element
33124 * @param {Object} config The config object
33127 Roo.bootstrap.LayoutMasonry = function(config){
33129 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
33133 Roo.bootstrap.LayoutMasonry.register(this);
33139 * Fire after layout the items
33140 * @param {Roo.bootstrap.LayoutMasonry} this
33141 * @param {Roo.EventObject} e
33148 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
33151 * @cfg {Boolean} isLayoutInstant = no animation?
33153 isLayoutInstant : false, // needed?
33156 * @cfg {Number} boxWidth width of the columns
33161 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
33166 * @cfg {Number} padWidth padding below box..
33171 * @cfg {Number} gutter gutter width..
33176 * @cfg {Number} maxCols maximum number of columns
33182 * @cfg {Boolean} isAutoInitial defalut true
33184 isAutoInitial : true,
33189 * @cfg {Boolean} isHorizontal defalut false
33191 isHorizontal : false,
33193 currentSize : null,
33199 bricks: null, //CompositeElement
33203 _isLayoutInited : false,
33205 // isAlternative : false, // only use for vertical layout...
33208 * @cfg {Number} alternativePadWidth padding below box..
33210 alternativePadWidth : 50,
33212 selectedBrick : [],
33214 getAutoCreate : function(){
33216 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
33220 cls: 'blog-masonary-wrapper ' + this.cls,
33222 cls : 'mas-boxes masonary'
33229 getChildContainer: function( )
33231 if (this.boxesEl) {
33232 return this.boxesEl;
33235 this.boxesEl = this.el.select('.mas-boxes').first();
33237 return this.boxesEl;
33241 initEvents : function()
33245 if(this.isAutoInitial){
33246 Roo.log('hook children rendered');
33247 this.on('childrenrendered', function() {
33248 Roo.log('children rendered');
33254 initial : function()
33256 this.selectedBrick = [];
33258 this.currentSize = this.el.getBox(true);
33260 Roo.EventManager.onWindowResize(this.resize, this);
33262 if(!this.isAutoInitial){
33270 //this.layout.defer(500,this);
33274 resize : function()
33276 var cs = this.el.getBox(true);
33279 this.currentSize.width == cs.width &&
33280 this.currentSize.x == cs.x &&
33281 this.currentSize.height == cs.height &&
33282 this.currentSize.y == cs.y
33284 Roo.log("no change in with or X or Y");
33288 this.currentSize = cs;
33294 layout : function()
33296 this._resetLayout();
33298 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33300 this.layoutItems( isInstant );
33302 this._isLayoutInited = true;
33304 this.fireEvent('layout', this);
33308 _resetLayout : function()
33310 if(this.isHorizontal){
33311 this.horizontalMeasureColumns();
33315 this.verticalMeasureColumns();
33319 verticalMeasureColumns : function()
33321 this.getContainerWidth();
33323 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33324 // this.colWidth = Math.floor(this.containerWidth * 0.8);
33328 var boxWidth = this.boxWidth + this.padWidth;
33330 if(this.containerWidth < this.boxWidth){
33331 boxWidth = this.containerWidth
33334 var containerWidth = this.containerWidth;
33336 var cols = Math.floor(containerWidth / boxWidth);
33338 this.cols = Math.max( cols, 1 );
33340 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33342 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
33344 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
33346 this.colWidth = boxWidth + avail - this.padWidth;
33348 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
33349 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
33352 horizontalMeasureColumns : function()
33354 this.getContainerWidth();
33356 var boxWidth = this.boxWidth;
33358 if(this.containerWidth < boxWidth){
33359 boxWidth = this.containerWidth;
33362 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
33364 this.el.setHeight(boxWidth);
33368 getContainerWidth : function()
33370 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33373 layoutItems : function( isInstant )
33375 Roo.log(this.bricks);
33377 var items = Roo.apply([], this.bricks);
33379 if(this.isHorizontal){
33380 this._horizontalLayoutItems( items , isInstant );
33384 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33385 // this._verticalAlternativeLayoutItems( items , isInstant );
33389 this._verticalLayoutItems( items , isInstant );
33393 _verticalLayoutItems : function ( items , isInstant)
33395 if ( !items || !items.length ) {
33400 ['xs', 'xs', 'xs', 'tall'],
33401 ['xs', 'xs', 'tall'],
33402 ['xs', 'xs', 'sm'],
33403 ['xs', 'xs', 'xs'],
33409 ['sm', 'xs', 'xs'],
33413 ['tall', 'xs', 'xs', 'xs'],
33414 ['tall', 'xs', 'xs'],
33426 Roo.each(items, function(item, k){
33428 switch (item.size) {
33429 // these layouts take up a full box,
33440 boxes.push([item]);
33463 var filterPattern = function(box, length)
33471 var pattern = box.slice(0, length);
33475 Roo.each(pattern, function(i){
33476 format.push(i.size);
33479 Roo.each(standard, function(s){
33481 if(String(s) != String(format)){
33490 if(!match && length == 1){
33495 filterPattern(box, length - 1);
33499 queue.push(pattern);
33501 box = box.slice(length, box.length);
33503 filterPattern(box, 4);
33509 Roo.each(boxes, function(box, k){
33515 if(box.length == 1){
33520 filterPattern(box, 4);
33524 this._processVerticalLayoutQueue( queue, isInstant );
33528 // _verticalAlternativeLayoutItems : function( items , isInstant )
33530 // if ( !items || !items.length ) {
33534 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
33538 _horizontalLayoutItems : function ( items , isInstant)
33540 if ( !items || !items.length || items.length < 3) {
33546 var eItems = items.slice(0, 3);
33548 items = items.slice(3, items.length);
33551 ['xs', 'xs', 'xs', 'wide'],
33552 ['xs', 'xs', 'wide'],
33553 ['xs', 'xs', 'sm'],
33554 ['xs', 'xs', 'xs'],
33560 ['sm', 'xs', 'xs'],
33564 ['wide', 'xs', 'xs', 'xs'],
33565 ['wide', 'xs', 'xs'],
33578 Roo.each(items, function(item, k){
33580 switch (item.size) {
33591 boxes.push([item]);
33615 var filterPattern = function(box, length)
33623 var pattern = box.slice(0, length);
33627 Roo.each(pattern, function(i){
33628 format.push(i.size);
33631 Roo.each(standard, function(s){
33633 if(String(s) != String(format)){
33642 if(!match && length == 1){
33647 filterPattern(box, length - 1);
33651 queue.push(pattern);
33653 box = box.slice(length, box.length);
33655 filterPattern(box, 4);
33661 Roo.each(boxes, function(box, k){
33667 if(box.length == 1){
33672 filterPattern(box, 4);
33679 var pos = this.el.getBox(true);
33683 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33685 var hit_end = false;
33687 Roo.each(queue, function(box){
33691 Roo.each(box, function(b){
33693 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33703 Roo.each(box, function(b){
33705 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33708 mx = Math.max(mx, b.x);
33712 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
33716 Roo.each(box, function(b){
33718 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33732 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
33735 /** Sets position of item in DOM
33736 * @param {Element} item
33737 * @param {Number} x - horizontal position
33738 * @param {Number} y - vertical position
33739 * @param {Boolean} isInstant - disables transitions
33741 _processVerticalLayoutQueue : function( queue, isInstant )
33743 var pos = this.el.getBox(true);
33748 for (var i = 0; i < this.cols; i++){
33752 Roo.each(queue, function(box, k){
33754 var col = k % this.cols;
33756 Roo.each(box, function(b,kk){
33758 b.el.position('absolute');
33760 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33761 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33763 if(b.size == 'md-left' || b.size == 'md-right'){
33764 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33765 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33768 b.el.setWidth(width);
33769 b.el.setHeight(height);
33771 b.el.select('iframe',true).setSize(width,height);
33775 for (var i = 0; i < this.cols; i++){
33777 if(maxY[i] < maxY[col]){
33782 col = Math.min(col, i);
33786 x = pos.x + col * (this.colWidth + this.padWidth);
33790 var positions = [];
33792 switch (box.length){
33794 positions = this.getVerticalOneBoxColPositions(x, y, box);
33797 positions = this.getVerticalTwoBoxColPositions(x, y, box);
33800 positions = this.getVerticalThreeBoxColPositions(x, y, box);
33803 positions = this.getVerticalFourBoxColPositions(x, y, box);
33809 Roo.each(box, function(b,kk){
33811 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33813 var sz = b.el.getSize();
33815 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
33823 for (var i = 0; i < this.cols; i++){
33824 mY = Math.max(mY, maxY[i]);
33827 this.el.setHeight(mY - pos.y);
33831 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
33833 // var pos = this.el.getBox(true);
33836 // var maxX = pos.right;
33838 // var maxHeight = 0;
33840 // Roo.each(items, function(item, k){
33844 // item.el.position('absolute');
33846 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
33848 // item.el.setWidth(width);
33850 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
33852 // item.el.setHeight(height);
33855 // item.el.setXY([x, y], isInstant ? false : true);
33857 // item.el.setXY([maxX - width, y], isInstant ? false : true);
33860 // y = y + height + this.alternativePadWidth;
33862 // maxHeight = maxHeight + height + this.alternativePadWidth;
33866 // this.el.setHeight(maxHeight);
33870 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
33872 var pos = this.el.getBox(true);
33877 var maxX = pos.right;
33879 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
33881 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33883 Roo.each(queue, function(box, k){
33885 Roo.each(box, function(b, kk){
33887 b.el.position('absolute');
33889 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33890 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33892 if(b.size == 'md-left' || b.size == 'md-right'){
33893 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33894 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33897 b.el.setWidth(width);
33898 b.el.setHeight(height);
33906 var positions = [];
33908 switch (box.length){
33910 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
33913 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33916 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33919 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33925 Roo.each(box, function(b,kk){
33927 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33929 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33937 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33939 Roo.each(eItems, function(b,k){
33941 b.size = (k == 0) ? 'sm' : 'xs';
33942 b.x = (k == 0) ? 2 : 1;
33943 b.y = (k == 0) ? 2 : 1;
33945 b.el.position('absolute');
33947 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33949 b.el.setWidth(width);
33951 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33953 b.el.setHeight(height);
33957 var positions = [];
33960 x : maxX - this.unitWidth * 2 - this.gutter,
33965 x : maxX - this.unitWidth,
33966 y : minY + (this.unitWidth + this.gutter) * 2
33970 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33974 Roo.each(eItems, function(b,k){
33976 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33982 getVerticalOneBoxColPositions : function(x, y, box)
33986 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33988 if(box[0].size == 'md-left'){
33992 if(box[0].size == 'md-right'){
33997 x : x + (this.unitWidth + this.gutter) * rand,
34004 getVerticalTwoBoxColPositions : function(x, y, box)
34008 if(box[0].size == 'xs'){
34012 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
34016 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
34030 x : x + (this.unitWidth + this.gutter) * 2,
34031 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
34038 getVerticalThreeBoxColPositions : function(x, y, box)
34042 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34050 x : x + (this.unitWidth + this.gutter) * 1,
34055 x : x + (this.unitWidth + this.gutter) * 2,
34063 if(box[0].size == 'xs' && box[1].size == 'xs'){
34072 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
34076 x : x + (this.unitWidth + this.gutter) * 1,
34090 x : x + (this.unitWidth + this.gutter) * 2,
34095 x : x + (this.unitWidth + this.gutter) * 2,
34096 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
34103 getVerticalFourBoxColPositions : function(x, y, box)
34107 if(box[0].size == 'xs'){
34116 y : y + (this.unitHeight + this.gutter) * 1
34121 y : y + (this.unitHeight + this.gutter) * 2
34125 x : x + (this.unitWidth + this.gutter) * 1,
34139 x : x + (this.unitWidth + this.gutter) * 2,
34144 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
34145 y : y + (this.unitHeight + this.gutter) * 1
34149 x : x + (this.unitWidth + this.gutter) * 2,
34150 y : y + (this.unitWidth + this.gutter) * 2
34157 getHorizontalOneBoxColPositions : function(maxX, minY, box)
34161 if(box[0].size == 'md-left'){
34163 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34170 if(box[0].size == 'md-right'){
34172 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34173 y : minY + (this.unitWidth + this.gutter) * 1
34179 var rand = Math.floor(Math.random() * (4 - box[0].y));
34182 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34183 y : minY + (this.unitWidth + this.gutter) * rand
34190 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
34194 if(box[0].size == 'xs'){
34197 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34202 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34203 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
34211 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34216 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34217 y : minY + (this.unitWidth + this.gutter) * 2
34224 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
34228 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34231 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34236 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34237 y : minY + (this.unitWidth + this.gutter) * 1
34241 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34242 y : minY + (this.unitWidth + this.gutter) * 2
34249 if(box[0].size == 'xs' && box[1].size == 'xs'){
34252 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34257 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34262 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34263 y : minY + (this.unitWidth + this.gutter) * 1
34271 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34276 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34277 y : minY + (this.unitWidth + this.gutter) * 2
34281 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34282 y : minY + (this.unitWidth + this.gutter) * 2
34289 getHorizontalFourBoxColPositions : function(maxX, minY, box)
34293 if(box[0].size == 'xs'){
34296 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34301 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34306 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),
34311 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
34312 y : minY + (this.unitWidth + this.gutter) * 1
34320 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34325 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34326 y : minY + (this.unitWidth + this.gutter) * 2
34330 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34331 y : minY + (this.unitWidth + this.gutter) * 2
34335 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),
34336 y : minY + (this.unitWidth + this.gutter) * 2
34344 * remove a Masonry Brick
34345 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
34347 removeBrick : function(brick_id)
34353 for (var i = 0; i<this.bricks.length; i++) {
34354 if (this.bricks[i].id == brick_id) {
34355 this.bricks.splice(i,1);
34356 this.el.dom.removeChild(Roo.get(brick_id).dom);
34363 * adds a Masonry Brick
34364 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34366 addBrick : function(cfg)
34368 var cn = new Roo.bootstrap.MasonryBrick(cfg);
34369 //this.register(cn);
34370 cn.parentId = this.id;
34371 cn.render(this.el);
34376 * register a Masonry Brick
34377 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34380 register : function(brick)
34382 this.bricks.push(brick);
34383 brick.masonryId = this.id;
34387 * clear all the Masonry Brick
34389 clearAll : function()
34392 //this.getChildContainer().dom.innerHTML = "";
34393 this.el.dom.innerHTML = '';
34396 getSelected : function()
34398 if (!this.selectedBrick) {
34402 return this.selectedBrick;
34406 Roo.apply(Roo.bootstrap.LayoutMasonry, {
34410 * register a Masonry Layout
34411 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
34414 register : function(layout)
34416 this.groups[layout.id] = layout;
34419 * fetch a Masonry Layout based on the masonry layout ID
34420 * @param {string} the masonry layout to add
34421 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
34424 get: function(layout_id) {
34425 if (typeof(this.groups[layout_id]) == 'undefined') {
34428 return this.groups[layout_id] ;
34440 * http://masonry.desandro.com
34442 * The idea is to render all the bricks based on vertical width...
34444 * The original code extends 'outlayer' - we might need to use that....
34450 * @class Roo.bootstrap.LayoutMasonryAuto
34451 * @extends Roo.bootstrap.Component
34452 * Bootstrap Layout Masonry class
34455 * Create a new Element
34456 * @param {Object} config The config object
34459 Roo.bootstrap.LayoutMasonryAuto = function(config){
34460 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
34463 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
34466 * @cfg {Boolean} isFitWidth - resize the width..
34468 isFitWidth : false, // options..
34470 * @cfg {Boolean} isOriginLeft = left align?
34472 isOriginLeft : true,
34474 * @cfg {Boolean} isOriginTop = top align?
34476 isOriginTop : false,
34478 * @cfg {Boolean} isLayoutInstant = no animation?
34480 isLayoutInstant : false, // needed?
34482 * @cfg {Boolean} isResizingContainer = not sure if this is used..
34484 isResizingContainer : true,
34486 * @cfg {Number} columnWidth width of the columns
34492 * @cfg {Number} maxCols maximum number of columns
34497 * @cfg {Number} padHeight padding below box..
34503 * @cfg {Boolean} isAutoInitial defalut true
34506 isAutoInitial : true,
34512 initialColumnWidth : 0,
34513 currentSize : null,
34515 colYs : null, // array.
34522 bricks: null, //CompositeElement
34523 cols : 0, // array?
34524 // element : null, // wrapped now this.el
34525 _isLayoutInited : null,
34528 getAutoCreate : function(){
34532 cls: 'blog-masonary-wrapper ' + this.cls,
34534 cls : 'mas-boxes masonary'
34541 getChildContainer: function( )
34543 if (this.boxesEl) {
34544 return this.boxesEl;
34547 this.boxesEl = this.el.select('.mas-boxes').first();
34549 return this.boxesEl;
34553 initEvents : function()
34557 if(this.isAutoInitial){
34558 Roo.log('hook children rendered');
34559 this.on('childrenrendered', function() {
34560 Roo.log('children rendered');
34567 initial : function()
34569 this.reloadItems();
34571 this.currentSize = this.el.getBox(true);
34573 /// was window resize... - let's see if this works..
34574 Roo.EventManager.onWindowResize(this.resize, this);
34576 if(!this.isAutoInitial){
34581 this.layout.defer(500,this);
34584 reloadItems: function()
34586 this.bricks = this.el.select('.masonry-brick', true);
34588 this.bricks.each(function(b) {
34589 //Roo.log(b.getSize());
34590 if (!b.attr('originalwidth')) {
34591 b.attr('originalwidth', b.getSize().width);
34596 Roo.log(this.bricks.elements.length);
34599 resize : function()
34602 var cs = this.el.getBox(true);
34604 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
34605 Roo.log("no change in with or X");
34608 this.currentSize = cs;
34612 layout : function()
34615 this._resetLayout();
34616 //this._manageStamps();
34618 // don't animate first layout
34619 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
34620 this.layoutItems( isInstant );
34622 // flag for initalized
34623 this._isLayoutInited = true;
34626 layoutItems : function( isInstant )
34628 //var items = this._getItemsForLayout( this.items );
34629 // original code supports filtering layout items.. we just ignore it..
34631 this._layoutItems( this.bricks , isInstant );
34633 this._postLayout();
34635 _layoutItems : function ( items , isInstant)
34637 //this.fireEvent( 'layout', this, items );
34640 if ( !items || !items.elements.length ) {
34641 // no items, emit event with empty array
34646 items.each(function(item) {
34647 Roo.log("layout item");
34649 // get x/y object from method
34650 var position = this._getItemLayoutPosition( item );
34652 position.item = item;
34653 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
34654 queue.push( position );
34657 this._processLayoutQueue( queue );
34659 /** Sets position of item in DOM
34660 * @param {Element} item
34661 * @param {Number} x - horizontal position
34662 * @param {Number} y - vertical position
34663 * @param {Boolean} isInstant - disables transitions
34665 _processLayoutQueue : function( queue )
34667 for ( var i=0, len = queue.length; i < len; i++ ) {
34668 var obj = queue[i];
34669 obj.item.position('absolute');
34670 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
34676 * Any logic you want to do after each layout,
34677 * i.e. size the container
34679 _postLayout : function()
34681 this.resizeContainer();
34684 resizeContainer : function()
34686 if ( !this.isResizingContainer ) {
34689 var size = this._getContainerSize();
34691 this.el.setSize(size.width,size.height);
34692 this.boxesEl.setSize(size.width,size.height);
34698 _resetLayout : function()
34700 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
34701 this.colWidth = this.el.getWidth();
34702 //this.gutter = this.el.getWidth();
34704 this.measureColumns();
34710 this.colYs.push( 0 );
34716 measureColumns : function()
34718 this.getContainerWidth();
34719 // if columnWidth is 0, default to outerWidth of first item
34720 if ( !this.columnWidth ) {
34721 var firstItem = this.bricks.first();
34722 Roo.log(firstItem);
34723 this.columnWidth = this.containerWidth;
34724 if (firstItem && firstItem.attr('originalwidth') ) {
34725 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
34727 // columnWidth fall back to item of first element
34728 Roo.log("set column width?");
34729 this.initialColumnWidth = this.columnWidth ;
34731 // if first elem has no width, default to size of container
34736 if (this.initialColumnWidth) {
34737 this.columnWidth = this.initialColumnWidth;
34742 // column width is fixed at the top - however if container width get's smaller we should
34745 // this bit calcs how man columns..
34747 var columnWidth = this.columnWidth += this.gutter;
34749 // calculate columns
34750 var containerWidth = this.containerWidth + this.gutter;
34752 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
34753 // fix rounding errors, typically with gutters
34754 var excess = columnWidth - containerWidth % columnWidth;
34757 // if overshoot is less than a pixel, round up, otherwise floor it
34758 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
34759 cols = Math[ mathMethod ]( cols );
34760 this.cols = Math.max( cols, 1 );
34761 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
34763 // padding positioning..
34764 var totalColWidth = this.cols * this.columnWidth;
34765 var padavail = this.containerWidth - totalColWidth;
34766 // so for 2 columns - we need 3 'pads'
34768 var padNeeded = (1+this.cols) * this.padWidth;
34770 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
34772 this.columnWidth += padExtra
34773 //this.padWidth = Math.floor(padavail / ( this.cols));
34775 // adjust colum width so that padding is fixed??
34777 // we have 3 columns ... total = width * 3
34778 // we have X left over... that should be used by
34780 //if (this.expandC) {
34788 getContainerWidth : function()
34790 /* // container is parent if fit width
34791 var container = this.isFitWidth ? this.element.parentNode : this.element;
34792 // check that this.size and size are there
34793 // IE8 triggers resize on body size change, so they might not be
34795 var size = getSize( container ); //FIXME
34796 this.containerWidth = size && size.innerWidth; //FIXME
34799 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
34803 _getItemLayoutPosition : function( item ) // what is item?
34805 // we resize the item to our columnWidth..
34807 item.setWidth(this.columnWidth);
34808 item.autoBoxAdjust = false;
34810 var sz = item.getSize();
34812 // how many columns does this brick span
34813 var remainder = this.containerWidth % this.columnWidth;
34815 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
34816 // round if off by 1 pixel, otherwise use ceil
34817 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
34818 colSpan = Math.min( colSpan, this.cols );
34820 // normally this should be '1' as we dont' currently allow multi width columns..
34822 var colGroup = this._getColGroup( colSpan );
34823 // get the minimum Y value from the columns
34824 var minimumY = Math.min.apply( Math, colGroup );
34825 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34827 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
34829 // position the brick
34831 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
34832 y: this.currentSize.y + minimumY + this.padHeight
34836 // apply setHeight to necessary columns
34837 var setHeight = minimumY + sz.height + this.padHeight;
34838 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34840 var setSpan = this.cols + 1 - colGroup.length;
34841 for ( var i = 0; i < setSpan; i++ ) {
34842 this.colYs[ shortColIndex + i ] = setHeight ;
34849 * @param {Number} colSpan - number of columns the element spans
34850 * @returns {Array} colGroup
34852 _getColGroup : function( colSpan )
34854 if ( colSpan < 2 ) {
34855 // if brick spans only one column, use all the column Ys
34860 // how many different places could this brick fit horizontally
34861 var groupCount = this.cols + 1 - colSpan;
34862 // for each group potential horizontal position
34863 for ( var i = 0; i < groupCount; i++ ) {
34864 // make an array of colY values for that one group
34865 var groupColYs = this.colYs.slice( i, i + colSpan );
34866 // and get the max value of the array
34867 colGroup[i] = Math.max.apply( Math, groupColYs );
34872 _manageStamp : function( stamp )
34874 var stampSize = stamp.getSize();
34875 var offset = stamp.getBox();
34876 // get the columns that this stamp affects
34877 var firstX = this.isOriginLeft ? offset.x : offset.right;
34878 var lastX = firstX + stampSize.width;
34879 var firstCol = Math.floor( firstX / this.columnWidth );
34880 firstCol = Math.max( 0, firstCol );
34882 var lastCol = Math.floor( lastX / this.columnWidth );
34883 // lastCol should not go over if multiple of columnWidth #425
34884 lastCol -= lastX % this.columnWidth ? 0 : 1;
34885 lastCol = Math.min( this.cols - 1, lastCol );
34887 // set colYs to bottom of the stamp
34888 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
34891 for ( var i = firstCol; i <= lastCol; i++ ) {
34892 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
34897 _getContainerSize : function()
34899 this.maxY = Math.max.apply( Math, this.colYs );
34904 if ( this.isFitWidth ) {
34905 size.width = this._getContainerFitWidth();
34911 _getContainerFitWidth : function()
34913 var unusedCols = 0;
34914 // count unused columns
34917 if ( this.colYs[i] !== 0 ) {
34922 // fit container to columns that have been used
34923 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34926 needsResizeLayout : function()
34928 var previousWidth = this.containerWidth;
34929 this.getContainerWidth();
34930 return previousWidth !== this.containerWidth;
34945 * @class Roo.bootstrap.MasonryBrick
34946 * @extends Roo.bootstrap.Component
34947 * Bootstrap MasonryBrick class
34950 * Create a new MasonryBrick
34951 * @param {Object} config The config object
34954 Roo.bootstrap.MasonryBrick = function(config){
34956 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34958 Roo.bootstrap.MasonryBrick.register(this);
34964 * When a MasonryBrick is clcik
34965 * @param {Roo.bootstrap.MasonryBrick} this
34966 * @param {Roo.EventObject} e
34972 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34975 * @cfg {String} title
34979 * @cfg {String} html
34983 * @cfg {String} bgimage
34987 * @cfg {String} videourl
34991 * @cfg {String} cls
34995 * @cfg {String} href
34999 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
35004 * @cfg {String} placetitle (center|bottom)
35009 * @cfg {Boolean} isFitContainer defalut true
35011 isFitContainer : true,
35014 * @cfg {Boolean} preventDefault defalut false
35016 preventDefault : false,
35019 * @cfg {Boolean} inverse defalut false
35021 maskInverse : false,
35023 getAutoCreate : function()
35025 if(!this.isFitContainer){
35026 return this.getSplitAutoCreate();
35029 var cls = 'masonry-brick masonry-brick-full';
35031 if(this.href.length){
35032 cls += ' masonry-brick-link';
35035 if(this.bgimage.length){
35036 cls += ' masonry-brick-image';
35039 if(this.maskInverse){
35040 cls += ' mask-inverse';
35043 if(!this.html.length && !this.maskInverse && !this.videourl.length){
35044 cls += ' enable-mask';
35048 cls += ' masonry-' + this.size + '-brick';
35051 if(this.placetitle.length){
35053 switch (this.placetitle) {
35055 cls += ' masonry-center-title';
35058 cls += ' masonry-bottom-title';
35065 if(!this.html.length && !this.bgimage.length){
35066 cls += ' masonry-center-title';
35069 if(!this.html.length && this.bgimage.length){
35070 cls += ' masonry-bottom-title';
35075 cls += ' ' + this.cls;
35079 tag: (this.href.length) ? 'a' : 'div',
35084 cls: 'masonry-brick-mask'
35088 cls: 'masonry-brick-paragraph',
35094 if(this.href.length){
35095 cfg.href = this.href;
35098 var cn = cfg.cn[1].cn;
35100 if(this.title.length){
35103 cls: 'masonry-brick-title',
35108 if(this.html.length){
35111 cls: 'masonry-brick-text',
35116 if (!this.title.length && !this.html.length) {
35117 cfg.cn[1].cls += ' hide';
35120 if(this.bgimage.length){
35123 cls: 'masonry-brick-image-view',
35128 if(this.videourl.length){
35129 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35130 // youtube support only?
35133 cls: 'masonry-brick-image-view',
35136 allowfullscreen : true
35144 getSplitAutoCreate : function()
35146 var cls = 'masonry-brick masonry-brick-split';
35148 if(this.href.length){
35149 cls += ' masonry-brick-link';
35152 if(this.bgimage.length){
35153 cls += ' masonry-brick-image';
35157 cls += ' masonry-' + this.size + '-brick';
35160 switch (this.placetitle) {
35162 cls += ' masonry-center-title';
35165 cls += ' masonry-bottom-title';
35168 if(!this.bgimage.length){
35169 cls += ' masonry-center-title';
35172 if(this.bgimage.length){
35173 cls += ' masonry-bottom-title';
35179 cls += ' ' + this.cls;
35183 tag: (this.href.length) ? 'a' : 'div',
35188 cls: 'masonry-brick-split-head',
35192 cls: 'masonry-brick-paragraph',
35199 cls: 'masonry-brick-split-body',
35205 if(this.href.length){
35206 cfg.href = this.href;
35209 if(this.title.length){
35210 cfg.cn[0].cn[0].cn.push({
35212 cls: 'masonry-brick-title',
35217 if(this.html.length){
35218 cfg.cn[1].cn.push({
35220 cls: 'masonry-brick-text',
35225 if(this.bgimage.length){
35226 cfg.cn[0].cn.push({
35228 cls: 'masonry-brick-image-view',
35233 if(this.videourl.length){
35234 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35235 // youtube support only?
35236 cfg.cn[0].cn.cn.push({
35238 cls: 'masonry-brick-image-view',
35241 allowfullscreen : true
35248 initEvents: function()
35250 switch (this.size) {
35283 this.el.on('touchstart', this.onTouchStart, this);
35284 this.el.on('touchmove', this.onTouchMove, this);
35285 this.el.on('touchend', this.onTouchEnd, this);
35286 this.el.on('contextmenu', this.onContextMenu, this);
35288 this.el.on('mouseenter' ,this.enter, this);
35289 this.el.on('mouseleave', this.leave, this);
35290 this.el.on('click', this.onClick, this);
35293 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
35294 this.parent().bricks.push(this);
35299 onClick: function(e, el)
35301 var time = this.endTimer - this.startTimer;
35302 // Roo.log(e.preventDefault());
35305 e.preventDefault();
35310 if(!this.preventDefault){
35314 e.preventDefault();
35316 if (this.activeClass != '') {
35317 this.selectBrick();
35320 this.fireEvent('click', this, e);
35323 enter: function(e, el)
35325 e.preventDefault();
35327 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35331 if(this.bgimage.length && this.html.length){
35332 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35336 leave: function(e, el)
35338 e.preventDefault();
35340 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35344 if(this.bgimage.length && this.html.length){
35345 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35349 onTouchStart: function(e, el)
35351 // e.preventDefault();
35353 this.touchmoved = false;
35355 if(!this.isFitContainer){
35359 if(!this.bgimage.length || !this.html.length){
35363 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35365 this.timer = new Date().getTime();
35369 onTouchMove: function(e, el)
35371 this.touchmoved = true;
35374 onContextMenu : function(e,el)
35376 e.preventDefault();
35377 e.stopPropagation();
35381 onTouchEnd: function(e, el)
35383 // e.preventDefault();
35385 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
35392 if(!this.bgimage.length || !this.html.length){
35394 if(this.href.length){
35395 window.location.href = this.href;
35401 if(!this.isFitContainer){
35405 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35407 window.location.href = this.href;
35410 //selection on single brick only
35411 selectBrick : function() {
35413 if (!this.parentId) {
35417 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
35418 var index = m.selectedBrick.indexOf(this.id);
35421 m.selectedBrick.splice(index,1);
35422 this.el.removeClass(this.activeClass);
35426 for(var i = 0; i < m.selectedBrick.length; i++) {
35427 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
35428 b.el.removeClass(b.activeClass);
35431 m.selectedBrick = [];
35433 m.selectedBrick.push(this.id);
35434 this.el.addClass(this.activeClass);
35438 isSelected : function(){
35439 return this.el.hasClass(this.activeClass);
35444 Roo.apply(Roo.bootstrap.MasonryBrick, {
35447 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
35449 * register a Masonry Brick
35450 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
35453 register : function(brick)
35455 //this.groups[brick.id] = brick;
35456 this.groups.add(brick.id, brick);
35459 * fetch a masonry brick based on the masonry brick ID
35460 * @param {string} the masonry brick to add
35461 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
35464 get: function(brick_id)
35466 // if (typeof(this.groups[brick_id]) == 'undefined') {
35469 // return this.groups[brick_id] ;
35471 if(this.groups.key(brick_id)) {
35472 return this.groups.key(brick_id);
35490 * @class Roo.bootstrap.Brick
35491 * @extends Roo.bootstrap.Component
35492 * Bootstrap Brick class
35495 * Create a new Brick
35496 * @param {Object} config The config object
35499 Roo.bootstrap.Brick = function(config){
35500 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
35506 * When a Brick is click
35507 * @param {Roo.bootstrap.Brick} this
35508 * @param {Roo.EventObject} e
35514 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
35517 * @cfg {String} title
35521 * @cfg {String} html
35525 * @cfg {String} bgimage
35529 * @cfg {String} cls
35533 * @cfg {String} href
35537 * @cfg {String} video
35541 * @cfg {Boolean} square
35545 getAutoCreate : function()
35547 var cls = 'roo-brick';
35549 if(this.href.length){
35550 cls += ' roo-brick-link';
35553 if(this.bgimage.length){
35554 cls += ' roo-brick-image';
35557 if(!this.html.length && !this.bgimage.length){
35558 cls += ' roo-brick-center-title';
35561 if(!this.html.length && this.bgimage.length){
35562 cls += ' roo-brick-bottom-title';
35566 cls += ' ' + this.cls;
35570 tag: (this.href.length) ? 'a' : 'div',
35575 cls: 'roo-brick-paragraph',
35581 if(this.href.length){
35582 cfg.href = this.href;
35585 var cn = cfg.cn[0].cn;
35587 if(this.title.length){
35590 cls: 'roo-brick-title',
35595 if(this.html.length){
35598 cls: 'roo-brick-text',
35605 if(this.bgimage.length){
35608 cls: 'roo-brick-image-view',
35616 initEvents: function()
35618 if(this.title.length || this.html.length){
35619 this.el.on('mouseenter' ,this.enter, this);
35620 this.el.on('mouseleave', this.leave, this);
35623 Roo.EventManager.onWindowResize(this.resize, this);
35625 if(this.bgimage.length){
35626 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
35627 this.imageEl.on('load', this.onImageLoad, this);
35634 onImageLoad : function()
35639 resize : function()
35641 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
35643 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
35645 if(this.bgimage.length){
35646 var image = this.el.select('.roo-brick-image-view', true).first();
35648 image.setWidth(paragraph.getWidth());
35651 image.setHeight(paragraph.getWidth());
35654 this.el.setHeight(image.getHeight());
35655 paragraph.setHeight(image.getHeight());
35661 enter: function(e, el)
35663 e.preventDefault();
35665 if(this.bgimage.length){
35666 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
35667 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
35671 leave: function(e, el)
35673 e.preventDefault();
35675 if(this.bgimage.length){
35676 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
35677 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
35692 * @class Roo.bootstrap.NumberField
35693 * @extends Roo.bootstrap.Input
35694 * Bootstrap NumberField class
35700 * Create a new NumberField
35701 * @param {Object} config The config object
35704 Roo.bootstrap.NumberField = function(config){
35705 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
35708 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
35711 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
35713 allowDecimals : true,
35715 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
35717 decimalSeparator : ".",
35719 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
35721 decimalPrecision : 2,
35723 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
35725 allowNegative : true,
35728 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
35732 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
35734 minValue : Number.NEGATIVE_INFINITY,
35736 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
35738 maxValue : Number.MAX_VALUE,
35740 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
35742 minText : "The minimum value for this field is {0}",
35744 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
35746 maxText : "The maximum value for this field is {0}",
35748 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
35749 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
35751 nanText : "{0} is not a valid number",
35753 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
35755 thousandsDelimiter : false,
35757 * @cfg {String} valueAlign alignment of value
35759 valueAlign : "left",
35761 getAutoCreate : function()
35763 var hiddenInput = {
35767 cls: 'hidden-number-input'
35771 hiddenInput.name = this.name;
35776 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
35778 this.name = hiddenInput.name;
35780 if(cfg.cn.length > 0) {
35781 cfg.cn.push(hiddenInput);
35788 initEvents : function()
35790 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
35792 var allowed = "0123456789";
35794 if(this.allowDecimals){
35795 allowed += this.decimalSeparator;
35798 if(this.allowNegative){
35802 if(this.thousandsDelimiter) {
35806 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
35808 var keyPress = function(e){
35810 var k = e.getKey();
35812 var c = e.getCharCode();
35815 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
35816 allowed.indexOf(String.fromCharCode(c)) === -1
35822 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
35826 if(allowed.indexOf(String.fromCharCode(c)) === -1){
35831 this.el.on("keypress", keyPress, this);
35834 validateValue : function(value)
35837 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
35841 var num = this.parseValue(value);
35844 this.markInvalid(String.format(this.nanText, value));
35848 if(num < this.minValue){
35849 this.markInvalid(String.format(this.minText, this.minValue));
35853 if(num > this.maxValue){
35854 this.markInvalid(String.format(this.maxText, this.maxValue));
35861 getValue : function()
35863 var v = this.hiddenEl().getValue();
35865 return this.fixPrecision(this.parseValue(v));
35868 parseValue : function(value)
35870 if(this.thousandsDelimiter) {
35872 r = new RegExp(",", "g");
35873 value = value.replace(r, "");
35876 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
35877 return isNaN(value) ? '' : value;
35880 fixPrecision : function(value)
35882 if(this.thousandsDelimiter) {
35884 r = new RegExp(",", "g");
35885 value = value.replace(r, "");
35888 var nan = isNaN(value);
35890 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
35891 return nan ? '' : value;
35893 return parseFloat(value).toFixed(this.decimalPrecision);
35896 setValue : function(v)
35898 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
35904 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
35906 this.inputEl().dom.value = (v == '') ? '' :
35907 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
35909 if(!this.allowZero && v === '0') {
35910 this.hiddenEl().dom.value = '';
35911 this.inputEl().dom.value = '';
35918 decimalPrecisionFcn : function(v)
35920 return Math.floor(v);
35923 beforeBlur : function()
35925 var v = this.parseValue(this.getRawValue());
35927 if(v || v === 0 || v === ''){
35932 hiddenEl : function()
35934 return this.el.select('input.hidden-number-input',true).first();
35946 * @class Roo.bootstrap.DocumentSlider
35947 * @extends Roo.bootstrap.Component
35948 * Bootstrap DocumentSlider class
35951 * Create a new DocumentViewer
35952 * @param {Object} config The config object
35955 Roo.bootstrap.DocumentSlider = function(config){
35956 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35963 * Fire after initEvent
35964 * @param {Roo.bootstrap.DocumentSlider} this
35969 * Fire after update
35970 * @param {Roo.bootstrap.DocumentSlider} this
35976 * @param {Roo.bootstrap.DocumentSlider} this
35982 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35988 getAutoCreate : function()
35992 cls : 'roo-document-slider',
35996 cls : 'roo-document-slider-header',
36000 cls : 'roo-document-slider-header-title'
36006 cls : 'roo-document-slider-body',
36010 cls : 'roo-document-slider-prev',
36014 cls : 'fa fa-chevron-left'
36020 cls : 'roo-document-slider-thumb',
36024 cls : 'roo-document-slider-image'
36030 cls : 'roo-document-slider-next',
36034 cls : 'fa fa-chevron-right'
36046 initEvents : function()
36048 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
36049 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
36051 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
36052 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
36054 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
36055 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
36057 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
36058 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
36060 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
36061 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
36063 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
36064 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
36066 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
36067 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
36069 this.thumbEl.on('click', this.onClick, this);
36071 this.prevIndicator.on('click', this.prev, this);
36073 this.nextIndicator.on('click', this.next, this);
36077 initial : function()
36079 if(this.files.length){
36080 this.indicator = 1;
36084 this.fireEvent('initial', this);
36087 update : function()
36089 this.imageEl.attr('src', this.files[this.indicator - 1]);
36091 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
36093 this.prevIndicator.show();
36095 if(this.indicator == 1){
36096 this.prevIndicator.hide();
36099 this.nextIndicator.show();
36101 if(this.indicator == this.files.length){
36102 this.nextIndicator.hide();
36105 this.thumbEl.scrollTo('top');
36107 this.fireEvent('update', this);
36110 onClick : function(e)
36112 e.preventDefault();
36114 this.fireEvent('click', this);
36119 e.preventDefault();
36121 this.indicator = Math.max(1, this.indicator - 1);
36128 e.preventDefault();
36130 this.indicator = Math.min(this.files.length, this.indicator + 1);
36144 * @class Roo.bootstrap.RadioSet
36145 * @extends Roo.bootstrap.Input
36146 * Bootstrap RadioSet class
36147 * @cfg {String} indicatorpos (left|right) default left
36148 * @cfg {Boolean} inline (true|false) inline the element (default true)
36149 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
36151 * Create a new RadioSet
36152 * @param {Object} config The config object
36155 Roo.bootstrap.RadioSet = function(config){
36157 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
36161 Roo.bootstrap.RadioSet.register(this);
36166 * Fires when the element is checked or unchecked.
36167 * @param {Roo.bootstrap.RadioSet} this This radio
36168 * @param {Roo.bootstrap.Radio} item The checked item
36173 * Fires when the element is click.
36174 * @param {Roo.bootstrap.RadioSet} this This radio set
36175 * @param {Roo.bootstrap.Radio} item The checked item
36176 * @param {Roo.EventObject} e The event object
36183 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
36191 indicatorpos : 'left',
36193 getAutoCreate : function()
36197 cls : 'roo-radio-set-label',
36201 html : this.fieldLabel
36205 if (Roo.bootstrap.version == 3) {
36208 if(this.indicatorpos == 'left'){
36211 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
36212 tooltip : 'This field is required'
36217 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
36218 tooltip : 'This field is required'
36224 cls : 'roo-radio-set-items'
36227 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
36229 if (align === 'left' && this.fieldLabel.length) {
36232 cls : "roo-radio-set-right",
36238 if(this.labelWidth > 12){
36239 label.style = "width: " + this.labelWidth + 'px';
36242 if(this.labelWidth < 13 && this.labelmd == 0){
36243 this.labelmd = this.labelWidth;
36246 if(this.labellg > 0){
36247 label.cls += ' col-lg-' + this.labellg;
36248 items.cls += ' col-lg-' + (12 - this.labellg);
36251 if(this.labelmd > 0){
36252 label.cls += ' col-md-' + this.labelmd;
36253 items.cls += ' col-md-' + (12 - this.labelmd);
36256 if(this.labelsm > 0){
36257 label.cls += ' col-sm-' + this.labelsm;
36258 items.cls += ' col-sm-' + (12 - this.labelsm);
36261 if(this.labelxs > 0){
36262 label.cls += ' col-xs-' + this.labelxs;
36263 items.cls += ' col-xs-' + (12 - this.labelxs);
36269 cls : 'roo-radio-set',
36273 cls : 'roo-radio-set-input',
36276 value : this.value ? this.value : ''
36283 if(this.weight.length){
36284 cfg.cls += ' roo-radio-' + this.weight;
36288 cfg.cls += ' roo-radio-set-inline';
36292 ['xs','sm','md','lg'].map(function(size){
36293 if (settings[size]) {
36294 cfg.cls += ' col-' + size + '-' + settings[size];
36302 initEvents : function()
36304 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
36305 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
36307 if(!this.fieldLabel.length){
36308 this.labelEl.hide();
36311 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
36312 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
36314 this.indicator = this.indicatorEl();
36316 if(this.indicator){
36317 this.indicator.addClass('invisible');
36320 this.originalValue = this.getValue();
36324 inputEl: function ()
36326 return this.el.select('.roo-radio-set-input', true).first();
36329 getChildContainer : function()
36331 return this.itemsEl;
36334 register : function(item)
36336 this.radioes.push(item);
36340 validate : function()
36342 if(this.getVisibilityEl().hasClass('hidden')){
36348 Roo.each(this.radioes, function(i){
36357 if(this.allowBlank) {
36361 if(this.disabled || valid){
36366 this.markInvalid();
36371 markValid : function()
36373 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36374 this.indicatorEl().removeClass('visible');
36375 this.indicatorEl().addClass('invisible');
36379 if (Roo.bootstrap.version == 3) {
36380 this.el.removeClass([this.invalidClass, this.validClass]);
36381 this.el.addClass(this.validClass);
36383 this.el.removeClass(['is-invalid','is-valid']);
36384 this.el.addClass(['is-valid']);
36386 this.fireEvent('valid', this);
36389 markInvalid : function(msg)
36391 if(this.allowBlank || this.disabled){
36395 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36396 this.indicatorEl().removeClass('invisible');
36397 this.indicatorEl().addClass('visible');
36399 if (Roo.bootstrap.version == 3) {
36400 this.el.removeClass([this.invalidClass, this.validClass]);
36401 this.el.addClass(this.invalidClass);
36403 this.el.removeClass(['is-invalid','is-valid']);
36404 this.el.addClass(['is-invalid']);
36407 this.fireEvent('invalid', this, msg);
36411 setValue : function(v, suppressEvent)
36413 if(this.value === v){
36420 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
36423 Roo.each(this.radioes, function(i){
36425 i.el.removeClass('checked');
36428 Roo.each(this.radioes, function(i){
36430 if(i.value === v || i.value.toString() === v.toString()){
36432 i.el.addClass('checked');
36434 if(suppressEvent !== true){
36435 this.fireEvent('check', this, i);
36446 clearInvalid : function(){
36448 if(!this.el || this.preventMark){
36452 this.el.removeClass([this.invalidClass]);
36454 this.fireEvent('valid', this);
36459 Roo.apply(Roo.bootstrap.RadioSet, {
36463 register : function(set)
36465 this.groups[set.name] = set;
36468 get: function(name)
36470 if (typeof(this.groups[name]) == 'undefined') {
36474 return this.groups[name] ;
36480 * Ext JS Library 1.1.1
36481 * Copyright(c) 2006-2007, Ext JS, LLC.
36483 * Originally Released Under LGPL - original licence link has changed is not relivant.
36486 * <script type="text/javascript">
36491 * @class Roo.bootstrap.SplitBar
36492 * @extends Roo.util.Observable
36493 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
36497 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
36498 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
36499 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
36500 split.minSize = 100;
36501 split.maxSize = 600;
36502 split.animate = true;
36503 split.on('moved', splitterMoved);
36506 * Create a new SplitBar
36507 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
36508 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
36509 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36510 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
36511 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
36512 position of the SplitBar).
36514 Roo.bootstrap.SplitBar = function(cfg){
36519 // dragElement : elm
36520 // resizingElement: el,
36522 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
36523 // placement : Roo.bootstrap.SplitBar.LEFT ,
36524 // existingProxy ???
36527 this.el = Roo.get(cfg.dragElement, true);
36528 this.el.dom.unselectable = "on";
36530 this.resizingEl = Roo.get(cfg.resizingElement, true);
36534 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36535 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
36538 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
36541 * The minimum size of the resizing element. (Defaults to 0)
36547 * The maximum size of the resizing element. (Defaults to 2000)
36550 this.maxSize = 2000;
36553 * Whether to animate the transition to the new size
36556 this.animate = false;
36559 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
36562 this.useShim = false;
36567 if(!cfg.existingProxy){
36569 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
36571 this.proxy = Roo.get(cfg.existingProxy).dom;
36574 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
36577 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
36580 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
36583 this.dragSpecs = {};
36586 * @private The adapter to use to positon and resize elements
36588 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36589 this.adapter.init(this);
36591 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36593 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
36594 this.el.addClass("roo-splitbar-h");
36597 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
36598 this.el.addClass("roo-splitbar-v");
36604 * Fires when the splitter is moved (alias for {@link #event-moved})
36605 * @param {Roo.bootstrap.SplitBar} this
36606 * @param {Number} newSize the new width or height
36611 * Fires when the splitter is moved
36612 * @param {Roo.bootstrap.SplitBar} this
36613 * @param {Number} newSize the new width or height
36617 * @event beforeresize
36618 * Fires before the splitter is dragged
36619 * @param {Roo.bootstrap.SplitBar} this
36621 "beforeresize" : true,
36623 "beforeapply" : true
36626 Roo.util.Observable.call(this);
36629 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
36630 onStartProxyDrag : function(x, y){
36631 this.fireEvent("beforeresize", this);
36633 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
36635 o.enableDisplayMode("block");
36636 // all splitbars share the same overlay
36637 Roo.bootstrap.SplitBar.prototype.overlay = o;
36639 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36640 this.overlay.show();
36641 Roo.get(this.proxy).setDisplayed("block");
36642 var size = this.adapter.getElementSize(this);
36643 this.activeMinSize = this.getMinimumSize();;
36644 this.activeMaxSize = this.getMaximumSize();;
36645 var c1 = size - this.activeMinSize;
36646 var c2 = Math.max(this.activeMaxSize - size, 0);
36647 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36648 this.dd.resetConstraints();
36649 this.dd.setXConstraint(
36650 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
36651 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
36653 this.dd.setYConstraint(0, 0);
36655 this.dd.resetConstraints();
36656 this.dd.setXConstraint(0, 0);
36657 this.dd.setYConstraint(
36658 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
36659 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
36662 this.dragSpecs.startSize = size;
36663 this.dragSpecs.startPoint = [x, y];
36664 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
36668 * @private Called after the drag operation by the DDProxy
36670 onEndProxyDrag : function(e){
36671 Roo.get(this.proxy).setDisplayed(false);
36672 var endPoint = Roo.lib.Event.getXY(e);
36674 this.overlay.hide();
36677 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36678 newSize = this.dragSpecs.startSize +
36679 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
36680 endPoint[0] - this.dragSpecs.startPoint[0] :
36681 this.dragSpecs.startPoint[0] - endPoint[0]
36684 newSize = this.dragSpecs.startSize +
36685 (this.placement == Roo.bootstrap.SplitBar.TOP ?
36686 endPoint[1] - this.dragSpecs.startPoint[1] :
36687 this.dragSpecs.startPoint[1] - endPoint[1]
36690 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
36691 if(newSize != this.dragSpecs.startSize){
36692 if(this.fireEvent('beforeapply', this, newSize) !== false){
36693 this.adapter.setElementSize(this, newSize);
36694 this.fireEvent("moved", this, newSize);
36695 this.fireEvent("resize", this, newSize);
36701 * Get the adapter this SplitBar uses
36702 * @return The adapter object
36704 getAdapter : function(){
36705 return this.adapter;
36709 * Set the adapter this SplitBar uses
36710 * @param {Object} adapter A SplitBar adapter object
36712 setAdapter : function(adapter){
36713 this.adapter = adapter;
36714 this.adapter.init(this);
36718 * Gets the minimum size for the resizing element
36719 * @return {Number} The minimum size
36721 getMinimumSize : function(){
36722 return this.minSize;
36726 * Sets the minimum size for the resizing element
36727 * @param {Number} minSize The minimum size
36729 setMinimumSize : function(minSize){
36730 this.minSize = minSize;
36734 * Gets the maximum size for the resizing element
36735 * @return {Number} The maximum size
36737 getMaximumSize : function(){
36738 return this.maxSize;
36742 * Sets the maximum size for the resizing element
36743 * @param {Number} maxSize The maximum size
36745 setMaximumSize : function(maxSize){
36746 this.maxSize = maxSize;
36750 * Sets the initialize size for the resizing element
36751 * @param {Number} size The initial size
36753 setCurrentSize : function(size){
36754 var oldAnimate = this.animate;
36755 this.animate = false;
36756 this.adapter.setElementSize(this, size);
36757 this.animate = oldAnimate;
36761 * Destroy this splitbar.
36762 * @param {Boolean} removeEl True to remove the element
36764 destroy : function(removeEl){
36766 this.shim.remove();
36769 this.proxy.parentNode.removeChild(this.proxy);
36777 * @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.
36779 Roo.bootstrap.SplitBar.createProxy = function(dir){
36780 var proxy = new Roo.Element(document.createElement("div"));
36781 proxy.unselectable();
36782 var cls = 'roo-splitbar-proxy';
36783 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
36784 document.body.appendChild(proxy.dom);
36789 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
36790 * Default Adapter. It assumes the splitter and resizing element are not positioned
36791 * elements and only gets/sets the width of the element. Generally used for table based layouts.
36793 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
36796 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
36797 // do nothing for now
36798 init : function(s){
36802 * Called before drag operations to get the current size of the resizing element.
36803 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36805 getElementSize : function(s){
36806 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36807 return s.resizingEl.getWidth();
36809 return s.resizingEl.getHeight();
36814 * Called after drag operations to set the size of the resizing element.
36815 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36816 * @param {Number} newSize The new size to set
36817 * @param {Function} onComplete A function to be invoked when resizing is complete
36819 setElementSize : function(s, newSize, onComplete){
36820 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36822 s.resizingEl.setWidth(newSize);
36824 onComplete(s, newSize);
36827 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
36832 s.resizingEl.setHeight(newSize);
36834 onComplete(s, newSize);
36837 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
36844 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
36845 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
36846 * Adapter that moves the splitter element to align with the resized sizing element.
36847 * Used with an absolute positioned SplitBar.
36848 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
36849 * document.body, make sure you assign an id to the body element.
36851 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
36852 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36853 this.container = Roo.get(container);
36856 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
36857 init : function(s){
36858 this.basic.init(s);
36861 getElementSize : function(s){
36862 return this.basic.getElementSize(s);
36865 setElementSize : function(s, newSize, onComplete){
36866 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
36869 moveSplitter : function(s){
36870 var yes = Roo.bootstrap.SplitBar;
36871 switch(s.placement){
36873 s.el.setX(s.resizingEl.getRight());
36876 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
36879 s.el.setY(s.resizingEl.getBottom());
36882 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
36889 * Orientation constant - Create a vertical SplitBar
36893 Roo.bootstrap.SplitBar.VERTICAL = 1;
36896 * Orientation constant - Create a horizontal SplitBar
36900 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
36903 * Placement constant - The resizing element is to the left of the splitter element
36907 Roo.bootstrap.SplitBar.LEFT = 1;
36910 * Placement constant - The resizing element is to the right of the splitter element
36914 Roo.bootstrap.SplitBar.RIGHT = 2;
36917 * Placement constant - The resizing element is positioned above the splitter element
36921 Roo.bootstrap.SplitBar.TOP = 3;
36924 * Placement constant - The resizing element is positioned under splitter element
36928 Roo.bootstrap.SplitBar.BOTTOM = 4;
36929 Roo.namespace("Roo.bootstrap.layout");/*
36931 * Ext JS Library 1.1.1
36932 * Copyright(c) 2006-2007, Ext JS, LLC.
36934 * Originally Released Under LGPL - original licence link has changed is not relivant.
36937 * <script type="text/javascript">
36941 * @class Roo.bootstrap.layout.Manager
36942 * @extends Roo.bootstrap.Component
36943 * Base class for layout managers.
36945 Roo.bootstrap.layout.Manager = function(config)
36947 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36953 /** false to disable window resize monitoring @type Boolean */
36954 this.monitorWindowResize = true;
36959 * Fires when a layout is performed.
36960 * @param {Roo.LayoutManager} this
36964 * @event regionresized
36965 * Fires when the user resizes a region.
36966 * @param {Roo.LayoutRegion} region The resized region
36967 * @param {Number} newSize The new size (width for east/west, height for north/south)
36969 "regionresized" : true,
36971 * @event regioncollapsed
36972 * Fires when a region is collapsed.
36973 * @param {Roo.LayoutRegion} region The collapsed region
36975 "regioncollapsed" : true,
36977 * @event regionexpanded
36978 * Fires when a region is expanded.
36979 * @param {Roo.LayoutRegion} region The expanded region
36981 "regionexpanded" : true
36983 this.updating = false;
36986 this.el = Roo.get(config.el);
36992 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36997 monitorWindowResize : true,
37003 onRender : function(ct, position)
37006 this.el = Roo.get(ct);
37009 //this.fireEvent('render',this);
37013 initEvents: function()
37017 // ie scrollbar fix
37018 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
37019 document.body.scroll = "no";
37020 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
37021 this.el.position('relative');
37023 this.id = this.el.id;
37024 this.el.addClass("roo-layout-container");
37025 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
37026 if(this.el.dom != document.body ) {
37027 this.el.on('resize', this.layout,this);
37028 this.el.on('show', this.layout,this);
37034 * Returns true if this layout is currently being updated
37035 * @return {Boolean}
37037 isUpdating : function(){
37038 return this.updating;
37042 * Suspend the LayoutManager from doing auto-layouts while
37043 * making multiple add or remove calls
37045 beginUpdate : function(){
37046 this.updating = true;
37050 * Restore auto-layouts and optionally disable the manager from performing a layout
37051 * @param {Boolean} noLayout true to disable a layout update
37053 endUpdate : function(noLayout){
37054 this.updating = false;
37060 layout: function(){
37064 onRegionResized : function(region, newSize){
37065 this.fireEvent("regionresized", region, newSize);
37069 onRegionCollapsed : function(region){
37070 this.fireEvent("regioncollapsed", region);
37073 onRegionExpanded : function(region){
37074 this.fireEvent("regionexpanded", region);
37078 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
37079 * performs box-model adjustments.
37080 * @return {Object} The size as an object {width: (the width), height: (the height)}
37082 getViewSize : function()
37085 if(this.el.dom != document.body){
37086 size = this.el.getSize();
37088 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
37090 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
37091 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37096 * Returns the Element this layout is bound to.
37097 * @return {Roo.Element}
37099 getEl : function(){
37104 * Returns the specified region.
37105 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
37106 * @return {Roo.LayoutRegion}
37108 getRegion : function(target){
37109 return this.regions[target.toLowerCase()];
37112 onWindowResize : function(){
37113 if(this.monitorWindowResize){
37120 * Ext JS Library 1.1.1
37121 * Copyright(c) 2006-2007, Ext JS, LLC.
37123 * Originally Released Under LGPL - original licence link has changed is not relivant.
37126 * <script type="text/javascript">
37129 * @class Roo.bootstrap.layout.Border
37130 * @extends Roo.bootstrap.layout.Manager
37131 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
37132 * please see: examples/bootstrap/nested.html<br><br>
37134 <b>The container the layout is rendered into can be either the body element or any other element.
37135 If it is not the body element, the container needs to either be an absolute positioned element,
37136 or you will need to add "position:relative" to the css of the container. You will also need to specify
37137 the container size if it is not the body element.</b>
37140 * Create a new Border
37141 * @param {Object} config Configuration options
37143 Roo.bootstrap.layout.Border = function(config){
37144 config = config || {};
37145 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
37149 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37150 if(config[region]){
37151 config[region].region = region;
37152 this.addRegion(config[region]);
37158 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
37160 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
37162 parent : false, // this might point to a 'nest' or a ???
37165 * Creates and adds a new region if it doesn't already exist.
37166 * @param {String} target The target region key (north, south, east, west or center).
37167 * @param {Object} config The regions config object
37168 * @return {BorderLayoutRegion} The new region
37170 addRegion : function(config)
37172 if(!this.regions[config.region]){
37173 var r = this.factory(config);
37174 this.bindRegion(r);
37176 return this.regions[config.region];
37180 bindRegion : function(r){
37181 this.regions[r.config.region] = r;
37183 r.on("visibilitychange", this.layout, this);
37184 r.on("paneladded", this.layout, this);
37185 r.on("panelremoved", this.layout, this);
37186 r.on("invalidated", this.layout, this);
37187 r.on("resized", this.onRegionResized, this);
37188 r.on("collapsed", this.onRegionCollapsed, this);
37189 r.on("expanded", this.onRegionExpanded, this);
37193 * Performs a layout update.
37195 layout : function()
37197 if(this.updating) {
37201 // render all the rebions if they have not been done alreayd?
37202 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37203 if(this.regions[region] && !this.regions[region].bodyEl){
37204 this.regions[region].onRender(this.el)
37208 var size = this.getViewSize();
37209 var w = size.width;
37210 var h = size.height;
37215 //var x = 0, y = 0;
37217 var rs = this.regions;
37218 var north = rs["north"];
37219 var south = rs["south"];
37220 var west = rs["west"];
37221 var east = rs["east"];
37222 var center = rs["center"];
37223 //if(this.hideOnLayout){ // not supported anymore
37224 //c.el.setStyle("display", "none");
37226 if(north && north.isVisible()){
37227 var b = north.getBox();
37228 var m = north.getMargins();
37229 b.width = w - (m.left+m.right);
37232 centerY = b.height + b.y + m.bottom;
37233 centerH -= centerY;
37234 north.updateBox(this.safeBox(b));
37236 if(south && south.isVisible()){
37237 var b = south.getBox();
37238 var m = south.getMargins();
37239 b.width = w - (m.left+m.right);
37241 var totalHeight = (b.height + m.top + m.bottom);
37242 b.y = h - totalHeight + m.top;
37243 centerH -= totalHeight;
37244 south.updateBox(this.safeBox(b));
37246 if(west && west.isVisible()){
37247 var b = west.getBox();
37248 var m = west.getMargins();
37249 b.height = centerH - (m.top+m.bottom);
37251 b.y = centerY + m.top;
37252 var totalWidth = (b.width + m.left + m.right);
37253 centerX += totalWidth;
37254 centerW -= totalWidth;
37255 west.updateBox(this.safeBox(b));
37257 if(east && east.isVisible()){
37258 var b = east.getBox();
37259 var m = east.getMargins();
37260 b.height = centerH - (m.top+m.bottom);
37261 var totalWidth = (b.width + m.left + m.right);
37262 b.x = w - totalWidth + m.left;
37263 b.y = centerY + m.top;
37264 centerW -= totalWidth;
37265 east.updateBox(this.safeBox(b));
37268 var m = center.getMargins();
37270 x: centerX + m.left,
37271 y: centerY + m.top,
37272 width: centerW - (m.left+m.right),
37273 height: centerH - (m.top+m.bottom)
37275 //if(this.hideOnLayout){
37276 //center.el.setStyle("display", "block");
37278 center.updateBox(this.safeBox(centerBox));
37281 this.fireEvent("layout", this);
37285 safeBox : function(box){
37286 box.width = Math.max(0, box.width);
37287 box.height = Math.max(0, box.height);
37292 * Adds a ContentPanel (or subclass) to this layout.
37293 * @param {String} target The target region key (north, south, east, west or center).
37294 * @param {Roo.ContentPanel} panel The panel to add
37295 * @return {Roo.ContentPanel} The added panel
37297 add : function(target, panel){
37299 target = target.toLowerCase();
37300 return this.regions[target].add(panel);
37304 * Remove a ContentPanel (or subclass) to this layout.
37305 * @param {String} target The target region key (north, south, east, west or center).
37306 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
37307 * @return {Roo.ContentPanel} The removed panel
37309 remove : function(target, panel){
37310 target = target.toLowerCase();
37311 return this.regions[target].remove(panel);
37315 * Searches all regions for a panel with the specified id
37316 * @param {String} panelId
37317 * @return {Roo.ContentPanel} The panel or null if it wasn't found
37319 findPanel : function(panelId){
37320 var rs = this.regions;
37321 for(var target in rs){
37322 if(typeof rs[target] != "function"){
37323 var p = rs[target].getPanel(panelId);
37333 * Searches all regions for a panel with the specified id and activates (shows) it.
37334 * @param {String/ContentPanel} panelId The panels id or the panel itself
37335 * @return {Roo.ContentPanel} The shown panel or null
37337 showPanel : function(panelId) {
37338 var rs = this.regions;
37339 for(var target in rs){
37340 var r = rs[target];
37341 if(typeof r != "function"){
37342 if(r.hasPanel(panelId)){
37343 return r.showPanel(panelId);
37351 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
37352 * @param {Roo.state.Provider} provider (optional) An alternate state provider
37355 restoreState : function(provider){
37357 provider = Roo.state.Manager;
37359 var sm = new Roo.LayoutStateManager();
37360 sm.init(this, provider);
37366 * Adds a xtype elements to the layout.
37370 xtype : 'ContentPanel',
37377 xtype : 'NestedLayoutPanel',
37383 items : [ ... list of content panels or nested layout panels.. ]
37387 * @param {Object} cfg Xtype definition of item to add.
37389 addxtype : function(cfg)
37391 // basically accepts a pannel...
37392 // can accept a layout region..!?!?
37393 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
37396 // theory? children can only be panels??
37398 //if (!cfg.xtype.match(/Panel$/)) {
37403 if (typeof(cfg.region) == 'undefined') {
37404 Roo.log("Failed to add Panel, region was not set");
37408 var region = cfg.region;
37414 xitems = cfg.items;
37419 if ( region == 'center') {
37420 Roo.log("Center: " + cfg.title);
37426 case 'Content': // ContentPanel (el, cfg)
37427 case 'Scroll': // ContentPanel (el, cfg)
37429 cfg.autoCreate = cfg.autoCreate || true;
37430 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37432 // var el = this.el.createChild();
37433 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
37436 this.add(region, ret);
37440 case 'TreePanel': // our new panel!
37441 cfg.el = this.el.createChild();
37442 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37443 this.add(region, ret);
37448 // create a new Layout (which is a Border Layout...
37450 var clayout = cfg.layout;
37451 clayout.el = this.el.createChild();
37452 clayout.items = clayout.items || [];
37456 // replace this exitems with the clayout ones..
37457 xitems = clayout.items;
37459 // force background off if it's in center...
37460 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
37461 cfg.background = false;
37463 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
37466 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37467 //console.log('adding nested layout panel ' + cfg.toSource());
37468 this.add(region, ret);
37469 nb = {}; /// find first...
37474 // needs grid and region
37476 //var el = this.getRegion(region).el.createChild();
37478 *var el = this.el.createChild();
37479 // create the grid first...
37480 cfg.grid.container = el;
37481 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
37484 if (region == 'center' && this.active ) {
37485 cfg.background = false;
37488 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37490 this.add(region, ret);
37492 if (cfg.background) {
37493 // render grid on panel activation (if panel background)
37494 ret.on('activate', function(gp) {
37495 if (!gp.grid.rendered) {
37496 // gp.grid.render(el);
37500 // cfg.grid.render(el);
37506 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
37507 // it was the old xcomponent building that caused this before.
37508 // espeically if border is the top element in the tree.
37518 if (typeof(Roo[cfg.xtype]) != 'undefined') {
37520 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37521 this.add(region, ret);
37525 throw "Can not add '" + cfg.xtype + "' to Border";
37531 this.beginUpdate();
37535 Roo.each(xitems, function(i) {
37536 region = nb && i.region ? i.region : false;
37538 var add = ret.addxtype(i);
37541 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
37542 if (!i.background) {
37543 abn[region] = nb[region] ;
37550 // make the last non-background panel active..
37551 //if (nb) { Roo.log(abn); }
37554 for(var r in abn) {
37555 region = this.getRegion(r);
37557 // tried using nb[r], but it does not work..
37559 region.showPanel(abn[r]);
37570 factory : function(cfg)
37573 var validRegions = Roo.bootstrap.layout.Border.regions;
37575 var target = cfg.region;
37578 var r = Roo.bootstrap.layout;
37582 return new r.North(cfg);
37584 return new r.South(cfg);
37586 return new r.East(cfg);
37588 return new r.West(cfg);
37590 return new r.Center(cfg);
37592 throw 'Layout region "'+target+'" not supported.';
37599 * Ext JS Library 1.1.1
37600 * Copyright(c) 2006-2007, Ext JS, LLC.
37602 * Originally Released Under LGPL - original licence link has changed is not relivant.
37605 * <script type="text/javascript">
37609 * @class Roo.bootstrap.layout.Basic
37610 * @extends Roo.util.Observable
37611 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
37612 * and does not have a titlebar, tabs or any other features. All it does is size and position
37613 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
37614 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37615 * @cfg {string} region the region that it inhabits..
37616 * @cfg {bool} skipConfig skip config?
37620 Roo.bootstrap.layout.Basic = function(config){
37622 this.mgr = config.mgr;
37624 this.position = config.region;
37626 var skipConfig = config.skipConfig;
37630 * @scope Roo.BasicLayoutRegion
37634 * @event beforeremove
37635 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
37636 * @param {Roo.LayoutRegion} this
37637 * @param {Roo.ContentPanel} panel The panel
37638 * @param {Object} e The cancel event object
37640 "beforeremove" : true,
37642 * @event invalidated
37643 * Fires when the layout for this region is changed.
37644 * @param {Roo.LayoutRegion} this
37646 "invalidated" : true,
37648 * @event visibilitychange
37649 * Fires when this region is shown or hidden
37650 * @param {Roo.LayoutRegion} this
37651 * @param {Boolean} visibility true or false
37653 "visibilitychange" : true,
37655 * @event paneladded
37656 * Fires when a panel is added.
37657 * @param {Roo.LayoutRegion} this
37658 * @param {Roo.ContentPanel} panel The panel
37660 "paneladded" : true,
37662 * @event panelremoved
37663 * Fires when a panel is removed.
37664 * @param {Roo.LayoutRegion} this
37665 * @param {Roo.ContentPanel} panel The panel
37667 "panelremoved" : true,
37669 * @event beforecollapse
37670 * Fires when this region before collapse.
37671 * @param {Roo.LayoutRegion} this
37673 "beforecollapse" : true,
37676 * Fires when this region is collapsed.
37677 * @param {Roo.LayoutRegion} this
37679 "collapsed" : true,
37682 * Fires when this region is expanded.
37683 * @param {Roo.LayoutRegion} this
37688 * Fires when this region is slid into view.
37689 * @param {Roo.LayoutRegion} this
37691 "slideshow" : true,
37694 * Fires when this region slides out of view.
37695 * @param {Roo.LayoutRegion} this
37697 "slidehide" : true,
37699 * @event panelactivated
37700 * Fires when a panel is activated.
37701 * @param {Roo.LayoutRegion} this
37702 * @param {Roo.ContentPanel} panel The activated panel
37704 "panelactivated" : true,
37707 * Fires when the user resizes this region.
37708 * @param {Roo.LayoutRegion} this
37709 * @param {Number} newSize The new size (width for east/west, height for north/south)
37713 /** A collection of panels in this region. @type Roo.util.MixedCollection */
37714 this.panels = new Roo.util.MixedCollection();
37715 this.panels.getKey = this.getPanelId.createDelegate(this);
37717 this.activePanel = null;
37718 // ensure listeners are added...
37720 if (config.listeners || config.events) {
37721 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
37722 listeners : config.listeners || {},
37723 events : config.events || {}
37727 if(skipConfig !== true){
37728 this.applyConfig(config);
37732 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
37734 getPanelId : function(p){
37738 applyConfig : function(config){
37739 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37740 this.config = config;
37745 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
37746 * the width, for horizontal (north, south) the height.
37747 * @param {Number} newSize The new width or height
37749 resizeTo : function(newSize){
37750 var el = this.el ? this.el :
37751 (this.activePanel ? this.activePanel.getEl() : null);
37753 switch(this.position){
37756 el.setWidth(newSize);
37757 this.fireEvent("resized", this, newSize);
37761 el.setHeight(newSize);
37762 this.fireEvent("resized", this, newSize);
37768 getBox : function(){
37769 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
37772 getMargins : function(){
37773 return this.margins;
37776 updateBox : function(box){
37778 var el = this.activePanel.getEl();
37779 el.dom.style.left = box.x + "px";
37780 el.dom.style.top = box.y + "px";
37781 this.activePanel.setSize(box.width, box.height);
37785 * Returns the container element for this region.
37786 * @return {Roo.Element}
37788 getEl : function(){
37789 return this.activePanel;
37793 * Returns true if this region is currently visible.
37794 * @return {Boolean}
37796 isVisible : function(){
37797 return this.activePanel ? true : false;
37800 setActivePanel : function(panel){
37801 panel = this.getPanel(panel);
37802 if(this.activePanel && this.activePanel != panel){
37803 this.activePanel.setActiveState(false);
37804 this.activePanel.getEl().setLeftTop(-10000,-10000);
37806 this.activePanel = panel;
37807 panel.setActiveState(true);
37809 panel.setSize(this.box.width, this.box.height);
37811 this.fireEvent("panelactivated", this, panel);
37812 this.fireEvent("invalidated");
37816 * Show the specified panel.
37817 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
37818 * @return {Roo.ContentPanel} The shown panel or null
37820 showPanel : function(panel){
37821 panel = this.getPanel(panel);
37823 this.setActivePanel(panel);
37829 * Get the active panel for this region.
37830 * @return {Roo.ContentPanel} The active panel or null
37832 getActivePanel : function(){
37833 return this.activePanel;
37837 * Add the passed ContentPanel(s)
37838 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37839 * @return {Roo.ContentPanel} The panel added (if only one was added)
37841 add : function(panel){
37842 if(arguments.length > 1){
37843 for(var i = 0, len = arguments.length; i < len; i++) {
37844 this.add(arguments[i]);
37848 if(this.hasPanel(panel)){
37849 this.showPanel(panel);
37852 var el = panel.getEl();
37853 if(el.dom.parentNode != this.mgr.el.dom){
37854 this.mgr.el.dom.appendChild(el.dom);
37856 if(panel.setRegion){
37857 panel.setRegion(this);
37859 this.panels.add(panel);
37860 el.setStyle("position", "absolute");
37861 if(!panel.background){
37862 this.setActivePanel(panel);
37863 if(this.config.initialSize && this.panels.getCount()==1){
37864 this.resizeTo(this.config.initialSize);
37867 this.fireEvent("paneladded", this, panel);
37872 * Returns true if the panel is in this region.
37873 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37874 * @return {Boolean}
37876 hasPanel : function(panel){
37877 if(typeof panel == "object"){ // must be panel obj
37878 panel = panel.getId();
37880 return this.getPanel(panel) ? true : false;
37884 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37885 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37886 * @param {Boolean} preservePanel Overrides the config preservePanel option
37887 * @return {Roo.ContentPanel} The panel that was removed
37889 remove : function(panel, preservePanel){
37890 panel = this.getPanel(panel);
37895 this.fireEvent("beforeremove", this, panel, e);
37896 if(e.cancel === true){
37899 var panelId = panel.getId();
37900 this.panels.removeKey(panelId);
37905 * Returns the panel specified or null if it's not in this region.
37906 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37907 * @return {Roo.ContentPanel}
37909 getPanel : function(id){
37910 if(typeof id == "object"){ // must be panel obj
37913 return this.panels.get(id);
37917 * Returns this regions position (north/south/east/west/center).
37920 getPosition: function(){
37921 return this.position;
37925 * Ext JS Library 1.1.1
37926 * Copyright(c) 2006-2007, Ext JS, LLC.
37928 * Originally Released Under LGPL - original licence link has changed is not relivant.
37931 * <script type="text/javascript">
37935 * @class Roo.bootstrap.layout.Region
37936 * @extends Roo.bootstrap.layout.Basic
37937 * This class represents a region in a layout manager.
37939 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37940 * @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})
37941 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37942 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37943 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37944 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37945 * @cfg {String} title The title for the region (overrides panel titles)
37946 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37947 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37948 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37949 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37950 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37951 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37952 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37953 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37954 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37955 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37957 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37958 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37959 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37960 * @cfg {Number} width For East/West panels
37961 * @cfg {Number} height For North/South panels
37962 * @cfg {Boolean} split To show the splitter
37963 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37965 * @cfg {string} cls Extra CSS classes to add to region
37967 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37968 * @cfg {string} region the region that it inhabits..
37971 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37972 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37974 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37975 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37976 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37978 Roo.bootstrap.layout.Region = function(config)
37980 this.applyConfig(config);
37982 var mgr = config.mgr;
37983 var pos = config.region;
37984 config.skipConfig = true;
37985 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37988 this.onRender(mgr.el);
37991 this.visible = true;
37992 this.collapsed = false;
37993 this.unrendered_panels = [];
37996 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
37998 position: '', // set by wrapper (eg. north/south etc..)
37999 unrendered_panels : null, // unrendered panels.
38001 tabPosition : false,
38003 mgr: false, // points to 'Border'
38006 createBody : function(){
38007 /** This region's body element
38008 * @type Roo.Element */
38009 this.bodyEl = this.el.createChild({
38011 cls: "roo-layout-panel-body tab-content" // bootstrap added...
38015 onRender: function(ctr, pos)
38017 var dh = Roo.DomHelper;
38018 /** This region's container element
38019 * @type Roo.Element */
38020 this.el = dh.append(ctr.dom, {
38022 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
38024 /** This region's title element
38025 * @type Roo.Element */
38027 this.titleEl = dh.append(this.el.dom, {
38029 unselectable: "on",
38030 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
38032 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
38033 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
38037 this.titleEl.enableDisplayMode();
38038 /** This region's title text element
38039 * @type HTMLElement */
38040 this.titleTextEl = this.titleEl.dom.firstChild;
38041 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
38043 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
38044 this.closeBtn.enableDisplayMode();
38045 this.closeBtn.on("click", this.closeClicked, this);
38046 this.closeBtn.hide();
38048 this.createBody(this.config);
38049 if(this.config.hideWhenEmpty){
38051 this.on("paneladded", this.validateVisibility, this);
38052 this.on("panelremoved", this.validateVisibility, this);
38054 if(this.autoScroll){
38055 this.bodyEl.setStyle("overflow", "auto");
38057 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
38059 //if(c.titlebar !== false){
38060 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
38061 this.titleEl.hide();
38063 this.titleEl.show();
38064 if(this.config.title){
38065 this.titleTextEl.innerHTML = this.config.title;
38069 if(this.config.collapsed){
38070 this.collapse(true);
38072 if(this.config.hidden){
38076 if (this.unrendered_panels && this.unrendered_panels.length) {
38077 for (var i =0;i< this.unrendered_panels.length; i++) {
38078 this.add(this.unrendered_panels[i]);
38080 this.unrendered_panels = null;
38086 applyConfig : function(c)
38089 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
38090 var dh = Roo.DomHelper;
38091 if(c.titlebar !== false){
38092 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
38093 this.collapseBtn.on("click", this.collapse, this);
38094 this.collapseBtn.enableDisplayMode();
38096 if(c.showPin === true || this.showPin){
38097 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
38098 this.stickBtn.enableDisplayMode();
38099 this.stickBtn.on("click", this.expand, this);
38100 this.stickBtn.hide();
38105 /** This region's collapsed element
38106 * @type Roo.Element */
38109 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
38110 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
38113 if(c.floatable !== false){
38114 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
38115 this.collapsedEl.on("click", this.collapseClick, this);
38118 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
38119 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
38120 id: "message", unselectable: "on", style:{"float":"left"}});
38121 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
38123 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
38124 this.expandBtn.on("click", this.expand, this);
38128 if(this.collapseBtn){
38129 this.collapseBtn.setVisible(c.collapsible == true);
38132 this.cmargins = c.cmargins || this.cmargins ||
38133 (this.position == "west" || this.position == "east" ?
38134 {top: 0, left: 2, right:2, bottom: 0} :
38135 {top: 2, left: 0, right:0, bottom: 2});
38137 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
38140 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
38142 this.autoScroll = c.autoScroll || false;
38147 this.duration = c.duration || .30;
38148 this.slideDuration = c.slideDuration || .45;
38153 * Returns true if this region is currently visible.
38154 * @return {Boolean}
38156 isVisible : function(){
38157 return this.visible;
38161 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
38162 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
38164 //setCollapsedTitle : function(title){
38165 // title = title || " ";
38166 // if(this.collapsedTitleTextEl){
38167 // this.collapsedTitleTextEl.innerHTML = title;
38171 getBox : function(){
38173 // if(!this.collapsed){
38174 b = this.el.getBox(false, true);
38176 // b = this.collapsedEl.getBox(false, true);
38181 getMargins : function(){
38182 return this.margins;
38183 //return this.collapsed ? this.cmargins : this.margins;
38186 highlight : function(){
38187 this.el.addClass("x-layout-panel-dragover");
38190 unhighlight : function(){
38191 this.el.removeClass("x-layout-panel-dragover");
38194 updateBox : function(box)
38196 if (!this.bodyEl) {
38197 return; // not rendered yet..
38201 if(!this.collapsed){
38202 this.el.dom.style.left = box.x + "px";
38203 this.el.dom.style.top = box.y + "px";
38204 this.updateBody(box.width, box.height);
38206 this.collapsedEl.dom.style.left = box.x + "px";
38207 this.collapsedEl.dom.style.top = box.y + "px";
38208 this.collapsedEl.setSize(box.width, box.height);
38211 this.tabs.autoSizeTabs();
38215 updateBody : function(w, h)
38218 this.el.setWidth(w);
38219 w -= this.el.getBorderWidth("rl");
38220 if(this.config.adjustments){
38221 w += this.config.adjustments[0];
38224 if(h !== null && h > 0){
38225 this.el.setHeight(h);
38226 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
38227 h -= this.el.getBorderWidth("tb");
38228 if(this.config.adjustments){
38229 h += this.config.adjustments[1];
38231 this.bodyEl.setHeight(h);
38233 h = this.tabs.syncHeight(h);
38236 if(this.panelSize){
38237 w = w !== null ? w : this.panelSize.width;
38238 h = h !== null ? h : this.panelSize.height;
38240 if(this.activePanel){
38241 var el = this.activePanel.getEl();
38242 w = w !== null ? w : el.getWidth();
38243 h = h !== null ? h : el.getHeight();
38244 this.panelSize = {width: w, height: h};
38245 this.activePanel.setSize(w, h);
38247 if(Roo.isIE && this.tabs){
38248 this.tabs.el.repaint();
38253 * Returns the container element for this region.
38254 * @return {Roo.Element}
38256 getEl : function(){
38261 * Hides this region.
38264 //if(!this.collapsed){
38265 this.el.dom.style.left = "-2000px";
38268 // this.collapsedEl.dom.style.left = "-2000px";
38269 // this.collapsedEl.hide();
38271 this.visible = false;
38272 this.fireEvent("visibilitychange", this, false);
38276 * Shows this region if it was previously hidden.
38279 //if(!this.collapsed){
38282 // this.collapsedEl.show();
38284 this.visible = true;
38285 this.fireEvent("visibilitychange", this, true);
38288 closeClicked : function(){
38289 if(this.activePanel){
38290 this.remove(this.activePanel);
38294 collapseClick : function(e){
38296 e.stopPropagation();
38299 e.stopPropagation();
38305 * Collapses this region.
38306 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
38309 collapse : function(skipAnim, skipCheck = false){
38310 if(this.collapsed) {
38314 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
38316 this.collapsed = true;
38318 this.split.el.hide();
38320 if(this.config.animate && skipAnim !== true){
38321 this.fireEvent("invalidated", this);
38322 this.animateCollapse();
38324 this.el.setLocation(-20000,-20000);
38326 this.collapsedEl.show();
38327 this.fireEvent("collapsed", this);
38328 this.fireEvent("invalidated", this);
38334 animateCollapse : function(){
38339 * Expands this region if it was previously collapsed.
38340 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
38341 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
38344 expand : function(e, skipAnim){
38346 e.stopPropagation();
38348 if(!this.collapsed || this.el.hasActiveFx()) {
38352 this.afterSlideIn();
38355 this.collapsed = false;
38356 if(this.config.animate && skipAnim !== true){
38357 this.animateExpand();
38361 this.split.el.show();
38363 this.collapsedEl.setLocation(-2000,-2000);
38364 this.collapsedEl.hide();
38365 this.fireEvent("invalidated", this);
38366 this.fireEvent("expanded", this);
38370 animateExpand : function(){
38374 initTabs : function()
38376 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
38378 var ts = new Roo.bootstrap.panel.Tabs({
38379 el: this.bodyEl.dom,
38381 tabPosition: this.tabPosition ? this.tabPosition : 'top',
38382 disableTooltips: this.config.disableTabTips,
38383 toolbar : this.config.toolbar
38386 if(this.config.hideTabs){
38387 ts.stripWrap.setDisplayed(false);
38390 ts.resizeTabs = this.config.resizeTabs === true;
38391 ts.minTabWidth = this.config.minTabWidth || 40;
38392 ts.maxTabWidth = this.config.maxTabWidth || 250;
38393 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
38394 ts.monitorResize = false;
38395 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
38396 ts.bodyEl.addClass('roo-layout-tabs-body');
38397 this.panels.each(this.initPanelAsTab, this);
38400 initPanelAsTab : function(panel){
38401 var ti = this.tabs.addTab(
38405 this.config.closeOnTab && panel.isClosable(),
38408 if(panel.tabTip !== undefined){
38409 ti.setTooltip(panel.tabTip);
38411 ti.on("activate", function(){
38412 this.setActivePanel(panel);
38415 if(this.config.closeOnTab){
38416 ti.on("beforeclose", function(t, e){
38418 this.remove(panel);
38422 panel.tabItem = ti;
38427 updatePanelTitle : function(panel, title)
38429 if(this.activePanel == panel){
38430 this.updateTitle(title);
38433 var ti = this.tabs.getTab(panel.getEl().id);
38435 if(panel.tabTip !== undefined){
38436 ti.setTooltip(panel.tabTip);
38441 updateTitle : function(title){
38442 if(this.titleTextEl && !this.config.title){
38443 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
38447 setActivePanel : function(panel)
38449 panel = this.getPanel(panel);
38450 if(this.activePanel && this.activePanel != panel){
38451 if(this.activePanel.setActiveState(false) === false){
38455 this.activePanel = panel;
38456 panel.setActiveState(true);
38457 if(this.panelSize){
38458 panel.setSize(this.panelSize.width, this.panelSize.height);
38461 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
38463 this.updateTitle(panel.getTitle());
38465 this.fireEvent("invalidated", this);
38467 this.fireEvent("panelactivated", this, panel);
38471 * Shows the specified panel.
38472 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
38473 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
38475 showPanel : function(panel)
38477 panel = this.getPanel(panel);
38480 var tab = this.tabs.getTab(panel.getEl().id);
38481 if(tab.isHidden()){
38482 this.tabs.unhideTab(tab.id);
38486 this.setActivePanel(panel);
38493 * Get the active panel for this region.
38494 * @return {Roo.ContentPanel} The active panel or null
38496 getActivePanel : function(){
38497 return this.activePanel;
38500 validateVisibility : function(){
38501 if(this.panels.getCount() < 1){
38502 this.updateTitle(" ");
38503 this.closeBtn.hide();
38506 if(!this.isVisible()){
38513 * Adds the passed ContentPanel(s) to this region.
38514 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
38515 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
38517 add : function(panel)
38519 if(arguments.length > 1){
38520 for(var i = 0, len = arguments.length; i < len; i++) {
38521 this.add(arguments[i]);
38526 // if we have not been rendered yet, then we can not really do much of this..
38527 if (!this.bodyEl) {
38528 this.unrendered_panels.push(panel);
38535 if(this.hasPanel(panel)){
38536 this.showPanel(panel);
38539 panel.setRegion(this);
38540 this.panels.add(panel);
38541 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
38542 // sinle panel - no tab...?? would it not be better to render it with the tabs,
38543 // and hide them... ???
38544 this.bodyEl.dom.appendChild(panel.getEl().dom);
38545 if(panel.background !== true){
38546 this.setActivePanel(panel);
38548 this.fireEvent("paneladded", this, panel);
38555 this.initPanelAsTab(panel);
38559 if(panel.background !== true){
38560 this.tabs.activate(panel.getEl().id);
38562 this.fireEvent("paneladded", this, panel);
38567 * Hides the tab for the specified panel.
38568 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38570 hidePanel : function(panel){
38571 if(this.tabs && (panel = this.getPanel(panel))){
38572 this.tabs.hideTab(panel.getEl().id);
38577 * Unhides the tab for a previously hidden panel.
38578 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38580 unhidePanel : function(panel){
38581 if(this.tabs && (panel = this.getPanel(panel))){
38582 this.tabs.unhideTab(panel.getEl().id);
38586 clearPanels : function(){
38587 while(this.panels.getCount() > 0){
38588 this.remove(this.panels.first());
38593 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
38594 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38595 * @param {Boolean} preservePanel Overrides the config preservePanel option
38596 * @return {Roo.ContentPanel} The panel that was removed
38598 remove : function(panel, preservePanel)
38600 panel = this.getPanel(panel);
38605 this.fireEvent("beforeremove", this, panel, e);
38606 if(e.cancel === true){
38609 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
38610 var panelId = panel.getId();
38611 this.panels.removeKey(panelId);
38613 document.body.appendChild(panel.getEl().dom);
38616 this.tabs.removeTab(panel.getEl().id);
38617 }else if (!preservePanel){
38618 this.bodyEl.dom.removeChild(panel.getEl().dom);
38620 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
38621 var p = this.panels.first();
38622 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
38623 tempEl.appendChild(p.getEl().dom);
38624 this.bodyEl.update("");
38625 this.bodyEl.dom.appendChild(p.getEl().dom);
38627 this.updateTitle(p.getTitle());
38629 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
38630 this.setActivePanel(p);
38632 panel.setRegion(null);
38633 if(this.activePanel == panel){
38634 this.activePanel = null;
38636 if(this.config.autoDestroy !== false && preservePanel !== true){
38637 try{panel.destroy();}catch(e){}
38639 this.fireEvent("panelremoved", this, panel);
38644 * Returns the TabPanel component used by this region
38645 * @return {Roo.TabPanel}
38647 getTabs : function(){
38651 createTool : function(parentEl, className){
38652 var btn = Roo.DomHelper.append(parentEl, {
38654 cls: "x-layout-tools-button",
38657 cls: "roo-layout-tools-button-inner " + className,
38661 btn.addClassOnOver("roo-layout-tools-button-over");
38666 * Ext JS Library 1.1.1
38667 * Copyright(c) 2006-2007, Ext JS, LLC.
38669 * Originally Released Under LGPL - original licence link has changed is not relivant.
38672 * <script type="text/javascript">
38678 * @class Roo.SplitLayoutRegion
38679 * @extends Roo.LayoutRegion
38680 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
38682 Roo.bootstrap.layout.Split = function(config){
38683 this.cursor = config.cursor;
38684 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
38687 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
38689 splitTip : "Drag to resize.",
38690 collapsibleSplitTip : "Drag to resize. Double click to hide.",
38691 useSplitTips : false,
38693 applyConfig : function(config){
38694 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
38697 onRender : function(ctr,pos) {
38699 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
38700 if(!this.config.split){
38705 var splitEl = Roo.DomHelper.append(ctr.dom, {
38707 id: this.el.id + "-split",
38708 cls: "roo-layout-split roo-layout-split-"+this.position,
38711 /** The SplitBar for this region
38712 * @type Roo.SplitBar */
38713 // does not exist yet...
38714 Roo.log([this.position, this.orientation]);
38716 this.split = new Roo.bootstrap.SplitBar({
38717 dragElement : splitEl,
38718 resizingElement: this.el,
38719 orientation : this.orientation
38722 this.split.on("moved", this.onSplitMove, this);
38723 this.split.useShim = this.config.useShim === true;
38724 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
38725 if(this.useSplitTips){
38726 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
38728 //if(config.collapsible){
38729 // this.split.el.on("dblclick", this.collapse, this);
38732 if(typeof this.config.minSize != "undefined"){
38733 this.split.minSize = this.config.minSize;
38735 if(typeof this.config.maxSize != "undefined"){
38736 this.split.maxSize = this.config.maxSize;
38738 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
38739 this.hideSplitter();
38744 getHMaxSize : function(){
38745 var cmax = this.config.maxSize || 10000;
38746 var center = this.mgr.getRegion("center");
38747 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
38750 getVMaxSize : function(){
38751 var cmax = this.config.maxSize || 10000;
38752 var center = this.mgr.getRegion("center");
38753 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
38756 onSplitMove : function(split, newSize){
38757 this.fireEvent("resized", this, newSize);
38761 * Returns the {@link Roo.SplitBar} for this region.
38762 * @return {Roo.SplitBar}
38764 getSplitBar : function(){
38769 this.hideSplitter();
38770 Roo.bootstrap.layout.Split.superclass.hide.call(this);
38773 hideSplitter : function(){
38775 this.split.el.setLocation(-2000,-2000);
38776 this.split.el.hide();
38782 this.split.el.show();
38784 Roo.bootstrap.layout.Split.superclass.show.call(this);
38787 beforeSlide: function(){
38788 if(Roo.isGecko){// firefox overflow auto bug workaround
38789 this.bodyEl.clip();
38791 this.tabs.bodyEl.clip();
38793 if(this.activePanel){
38794 this.activePanel.getEl().clip();
38796 if(this.activePanel.beforeSlide){
38797 this.activePanel.beforeSlide();
38803 afterSlide : function(){
38804 if(Roo.isGecko){// firefox overflow auto bug workaround
38805 this.bodyEl.unclip();
38807 this.tabs.bodyEl.unclip();
38809 if(this.activePanel){
38810 this.activePanel.getEl().unclip();
38811 if(this.activePanel.afterSlide){
38812 this.activePanel.afterSlide();
38818 initAutoHide : function(){
38819 if(this.autoHide !== false){
38820 if(!this.autoHideHd){
38821 var st = new Roo.util.DelayedTask(this.slideIn, this);
38822 this.autoHideHd = {
38823 "mouseout": function(e){
38824 if(!e.within(this.el, true)){
38828 "mouseover" : function(e){
38834 this.el.on(this.autoHideHd);
38838 clearAutoHide : function(){
38839 if(this.autoHide !== false){
38840 this.el.un("mouseout", this.autoHideHd.mouseout);
38841 this.el.un("mouseover", this.autoHideHd.mouseover);
38845 clearMonitor : function(){
38846 Roo.get(document).un("click", this.slideInIf, this);
38849 // these names are backwards but not changed for compat
38850 slideOut : function(){
38851 if(this.isSlid || this.el.hasActiveFx()){
38854 this.isSlid = true;
38855 if(this.collapseBtn){
38856 this.collapseBtn.hide();
38858 this.closeBtnState = this.closeBtn.getStyle('display');
38859 this.closeBtn.hide();
38861 this.stickBtn.show();
38864 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
38865 this.beforeSlide();
38866 this.el.setStyle("z-index", 10001);
38867 this.el.slideIn(this.getSlideAnchor(), {
38868 callback: function(){
38870 this.initAutoHide();
38871 Roo.get(document).on("click", this.slideInIf, this);
38872 this.fireEvent("slideshow", this);
38879 afterSlideIn : function(){
38880 this.clearAutoHide();
38881 this.isSlid = false;
38882 this.clearMonitor();
38883 this.el.setStyle("z-index", "");
38884 if(this.collapseBtn){
38885 this.collapseBtn.show();
38887 this.closeBtn.setStyle('display', this.closeBtnState);
38889 this.stickBtn.hide();
38891 this.fireEvent("slidehide", this);
38894 slideIn : function(cb){
38895 if(!this.isSlid || this.el.hasActiveFx()){
38899 this.isSlid = false;
38900 this.beforeSlide();
38901 this.el.slideOut(this.getSlideAnchor(), {
38902 callback: function(){
38903 this.el.setLeftTop(-10000, -10000);
38905 this.afterSlideIn();
38913 slideInIf : function(e){
38914 if(!e.within(this.el)){
38919 animateCollapse : function(){
38920 this.beforeSlide();
38921 this.el.setStyle("z-index", 20000);
38922 var anchor = this.getSlideAnchor();
38923 this.el.slideOut(anchor, {
38924 callback : function(){
38925 this.el.setStyle("z-index", "");
38926 this.collapsedEl.slideIn(anchor, {duration:.3});
38928 this.el.setLocation(-10000,-10000);
38930 this.fireEvent("collapsed", this);
38937 animateExpand : function(){
38938 this.beforeSlide();
38939 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38940 this.el.setStyle("z-index", 20000);
38941 this.collapsedEl.hide({
38944 this.el.slideIn(this.getSlideAnchor(), {
38945 callback : function(){
38946 this.el.setStyle("z-index", "");
38949 this.split.el.show();
38951 this.fireEvent("invalidated", this);
38952 this.fireEvent("expanded", this);
38980 getAnchor : function(){
38981 return this.anchors[this.position];
38984 getCollapseAnchor : function(){
38985 return this.canchors[this.position];
38988 getSlideAnchor : function(){
38989 return this.sanchors[this.position];
38992 getAlignAdj : function(){
38993 var cm = this.cmargins;
38994 switch(this.position){
39010 getExpandAdj : function(){
39011 var c = this.collapsedEl, cm = this.cmargins;
39012 switch(this.position){
39014 return [-(cm.right+c.getWidth()+cm.left), 0];
39017 return [cm.right+c.getWidth()+cm.left, 0];
39020 return [0, -(cm.top+cm.bottom+c.getHeight())];
39023 return [0, cm.top+cm.bottom+c.getHeight()];
39029 * Ext JS Library 1.1.1
39030 * Copyright(c) 2006-2007, Ext JS, LLC.
39032 * Originally Released Under LGPL - original licence link has changed is not relivant.
39035 * <script type="text/javascript">
39038 * These classes are private internal classes
39040 Roo.bootstrap.layout.Center = function(config){
39041 config.region = "center";
39042 Roo.bootstrap.layout.Region.call(this, config);
39043 this.visible = true;
39044 this.minWidth = config.minWidth || 20;
39045 this.minHeight = config.minHeight || 20;
39048 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
39050 // center panel can't be hidden
39054 // center panel can't be hidden
39057 getMinWidth: function(){
39058 return this.minWidth;
39061 getMinHeight: function(){
39062 return this.minHeight;
39076 Roo.bootstrap.layout.North = function(config)
39078 config.region = 'north';
39079 config.cursor = 'n-resize';
39081 Roo.bootstrap.layout.Split.call(this, config);
39085 this.split.placement = Roo.bootstrap.SplitBar.TOP;
39086 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39087 this.split.el.addClass("roo-layout-split-v");
39089 var size = config.initialSize || config.height;
39090 if(typeof size != "undefined"){
39091 this.el.setHeight(size);
39094 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
39096 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39100 getBox : function(){
39101 if(this.collapsed){
39102 return this.collapsedEl.getBox();
39104 var box = this.el.getBox();
39106 box.height += this.split.el.getHeight();
39111 updateBox : function(box){
39112 if(this.split && !this.collapsed){
39113 box.height -= this.split.el.getHeight();
39114 this.split.el.setLeft(box.x);
39115 this.split.el.setTop(box.y+box.height);
39116 this.split.el.setWidth(box.width);
39118 if(this.collapsed){
39119 this.updateBody(box.width, null);
39121 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39129 Roo.bootstrap.layout.South = function(config){
39130 config.region = 'south';
39131 config.cursor = 's-resize';
39132 Roo.bootstrap.layout.Split.call(this, config);
39134 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
39135 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39136 this.split.el.addClass("roo-layout-split-v");
39138 var size = config.initialSize || config.height;
39139 if(typeof size != "undefined"){
39140 this.el.setHeight(size);
39144 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
39145 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39146 getBox : function(){
39147 if(this.collapsed){
39148 return this.collapsedEl.getBox();
39150 var box = this.el.getBox();
39152 var sh = this.split.el.getHeight();
39159 updateBox : function(box){
39160 if(this.split && !this.collapsed){
39161 var sh = this.split.el.getHeight();
39164 this.split.el.setLeft(box.x);
39165 this.split.el.setTop(box.y-sh);
39166 this.split.el.setWidth(box.width);
39168 if(this.collapsed){
39169 this.updateBody(box.width, null);
39171 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39175 Roo.bootstrap.layout.East = function(config){
39176 config.region = "east";
39177 config.cursor = "e-resize";
39178 Roo.bootstrap.layout.Split.call(this, config);
39180 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
39181 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39182 this.split.el.addClass("roo-layout-split-h");
39184 var size = config.initialSize || config.width;
39185 if(typeof size != "undefined"){
39186 this.el.setWidth(size);
39189 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
39190 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39191 getBox : function(){
39192 if(this.collapsed){
39193 return this.collapsedEl.getBox();
39195 var box = this.el.getBox();
39197 var sw = this.split.el.getWidth();
39204 updateBox : function(box){
39205 if(this.split && !this.collapsed){
39206 var sw = this.split.el.getWidth();
39208 this.split.el.setLeft(box.x);
39209 this.split.el.setTop(box.y);
39210 this.split.el.setHeight(box.height);
39213 if(this.collapsed){
39214 this.updateBody(null, box.height);
39216 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39220 Roo.bootstrap.layout.West = function(config){
39221 config.region = "west";
39222 config.cursor = "w-resize";
39224 Roo.bootstrap.layout.Split.call(this, config);
39226 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
39227 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39228 this.split.el.addClass("roo-layout-split-h");
39232 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
39233 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39235 onRender: function(ctr, pos)
39237 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
39238 var size = this.config.initialSize || this.config.width;
39239 if(typeof size != "undefined"){
39240 this.el.setWidth(size);
39244 getBox : function(){
39245 if(this.collapsed){
39246 return this.collapsedEl.getBox();
39248 var box = this.el.getBox();
39250 box.width += this.split.el.getWidth();
39255 updateBox : function(box){
39256 if(this.split && !this.collapsed){
39257 var sw = this.split.el.getWidth();
39259 this.split.el.setLeft(box.x+box.width);
39260 this.split.el.setTop(box.y);
39261 this.split.el.setHeight(box.height);
39263 if(this.collapsed){
39264 this.updateBody(null, box.height);
39266 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39268 });Roo.namespace("Roo.bootstrap.panel");/*
39270 * Ext JS Library 1.1.1
39271 * Copyright(c) 2006-2007, Ext JS, LLC.
39273 * Originally Released Under LGPL - original licence link has changed is not relivant.
39276 * <script type="text/javascript">
39279 * @class Roo.ContentPanel
39280 * @extends Roo.util.Observable
39281 * A basic ContentPanel element.
39282 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
39283 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
39284 * @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
39285 * @cfg {Boolean} closable True if the panel can be closed/removed
39286 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
39287 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
39288 * @cfg {Toolbar} toolbar A toolbar for this panel
39289 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
39290 * @cfg {String} title The title for this panel
39291 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
39292 * @cfg {String} url Calls {@link #setUrl} with this value
39293 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
39294 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
39295 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
39296 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
39297 * @cfg {Boolean} badges render the badges
39298 * @cfg {String} cls extra classes to use
39299 * @cfg {String} background (primary|secondary|success|info|warning|danger|light|dark)
39302 * Create a new ContentPanel.
39303 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
39304 * @param {String/Object} config A string to set only the title or a config object
39305 * @param {String} content (optional) Set the HTML content for this panel
39306 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
39308 Roo.bootstrap.panel.Content = function( config){
39310 this.tpl = config.tpl || false;
39312 var el = config.el;
39313 var content = config.content;
39315 if(config.autoCreate){ // xtype is available if this is called from factory
39318 this.el = Roo.get(el);
39319 if(!this.el && config && config.autoCreate){
39320 if(typeof config.autoCreate == "object"){
39321 if(!config.autoCreate.id){
39322 config.autoCreate.id = config.id||el;
39324 this.el = Roo.DomHelper.append(document.body,
39325 config.autoCreate, true);
39329 cls: (config.cls || '') +
39330 (config.background ? ' bg-' + config.background : '') +
39331 " roo-layout-inactive-content",
39335 elcfg.html = config.html;
39339 this.el = Roo.DomHelper.append(document.body, elcfg , true);
39342 this.closable = false;
39343 this.loaded = false;
39344 this.active = false;
39347 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
39349 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
39351 this.wrapEl = this.el; //this.el.wrap();
39353 if (config.toolbar.items) {
39354 ti = config.toolbar.items ;
39355 delete config.toolbar.items ;
39359 this.toolbar.render(this.wrapEl, 'before');
39360 for(var i =0;i < ti.length;i++) {
39361 // Roo.log(['add child', items[i]]);
39362 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39364 this.toolbar.items = nitems;
39365 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
39366 delete config.toolbar;
39370 // xtype created footer. - not sure if will work as we normally have to render first..
39371 if (this.footer && !this.footer.el && this.footer.xtype) {
39372 if (!this.wrapEl) {
39373 this.wrapEl = this.el.wrap();
39376 this.footer.container = this.wrapEl.createChild();
39378 this.footer = Roo.factory(this.footer, Roo);
39383 if(typeof config == "string"){
39384 this.title = config;
39386 Roo.apply(this, config);
39390 this.resizeEl = Roo.get(this.resizeEl, true);
39392 this.resizeEl = this.el;
39394 // handle view.xtype
39402 * Fires when this panel is activated.
39403 * @param {Roo.ContentPanel} this
39407 * @event deactivate
39408 * Fires when this panel is activated.
39409 * @param {Roo.ContentPanel} this
39411 "deactivate" : true,
39415 * Fires when this panel is resized if fitToFrame is true.
39416 * @param {Roo.ContentPanel} this
39417 * @param {Number} width The width after any component adjustments
39418 * @param {Number} height The height after any component adjustments
39424 * Fires when this tab is created
39425 * @param {Roo.ContentPanel} this
39436 if(this.autoScroll){
39437 this.resizeEl.setStyle("overflow", "auto");
39439 // fix randome scrolling
39440 //this.el.on('scroll', function() {
39441 // Roo.log('fix random scolling');
39442 // this.scrollTo('top',0);
39445 content = content || this.content;
39447 this.setContent(content);
39449 if(config && config.url){
39450 this.setUrl(this.url, this.params, this.loadOnce);
39455 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
39457 if (this.view && typeof(this.view.xtype) != 'undefined') {
39458 this.view.el = this.el.appendChild(document.createElement("div"));
39459 this.view = Roo.factory(this.view);
39460 this.view.render && this.view.render(false, '');
39464 this.fireEvent('render', this);
39467 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
39474 setRegion : function(region){
39475 this.region = region;
39476 this.setActiveClass(region && !this.background);
39480 setActiveClass: function(state)
39483 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
39484 this.el.setStyle('position','relative');
39486 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
39487 this.el.setStyle('position', 'absolute');
39492 * Returns the toolbar for this Panel if one was configured.
39493 * @return {Roo.Toolbar}
39495 getToolbar : function(){
39496 return this.toolbar;
39499 setActiveState : function(active)
39501 this.active = active;
39502 this.setActiveClass(active);
39504 if(this.fireEvent("deactivate", this) === false){
39509 this.fireEvent("activate", this);
39513 * Updates this panel's element
39514 * @param {String} content The new content
39515 * @param {Boolean} loadScripts (optional) true to look for and process scripts
39517 setContent : function(content, loadScripts){
39518 this.el.update(content, loadScripts);
39521 ignoreResize : function(w, h){
39522 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
39525 this.lastSize = {width: w, height: h};
39530 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
39531 * @return {Roo.UpdateManager} The UpdateManager
39533 getUpdateManager : function(){
39534 return this.el.getUpdateManager();
39537 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
39538 * @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:
39541 url: "your-url.php",
39542 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
39543 callback: yourFunction,
39544 scope: yourObject, //(optional scope)
39547 text: "Loading...",
39552 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
39553 * 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.
39554 * @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}
39555 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
39556 * @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.
39557 * @return {Roo.ContentPanel} this
39560 var um = this.el.getUpdateManager();
39561 um.update.apply(um, arguments);
39567 * 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.
39568 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
39569 * @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)
39570 * @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)
39571 * @return {Roo.UpdateManager} The UpdateManager
39573 setUrl : function(url, params, loadOnce){
39574 if(this.refreshDelegate){
39575 this.removeListener("activate", this.refreshDelegate);
39577 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39578 this.on("activate", this.refreshDelegate);
39579 return this.el.getUpdateManager();
39582 _handleRefresh : function(url, params, loadOnce){
39583 if(!loadOnce || !this.loaded){
39584 var updater = this.el.getUpdateManager();
39585 updater.update(url, params, this._setLoaded.createDelegate(this));
39589 _setLoaded : function(){
39590 this.loaded = true;
39594 * Returns this panel's id
39597 getId : function(){
39602 * Returns this panel's element - used by regiosn to add.
39603 * @return {Roo.Element}
39605 getEl : function(){
39606 return this.wrapEl || this.el;
39611 adjustForComponents : function(width, height)
39613 //Roo.log('adjustForComponents ');
39614 if(this.resizeEl != this.el){
39615 width -= this.el.getFrameWidth('lr');
39616 height -= this.el.getFrameWidth('tb');
39619 var te = this.toolbar.getEl();
39620 te.setWidth(width);
39621 height -= te.getHeight();
39624 var te = this.footer.getEl();
39625 te.setWidth(width);
39626 height -= te.getHeight();
39630 if(this.adjustments){
39631 width += this.adjustments[0];
39632 height += this.adjustments[1];
39634 return {"width": width, "height": height};
39637 setSize : function(width, height){
39638 if(this.fitToFrame && !this.ignoreResize(width, height)){
39639 if(this.fitContainer && this.resizeEl != this.el){
39640 this.el.setSize(width, height);
39642 var size = this.adjustForComponents(width, height);
39643 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
39644 this.fireEvent('resize', this, size.width, size.height);
39649 * Returns this panel's title
39652 getTitle : function(){
39654 if (typeof(this.title) != 'object') {
39659 for (var k in this.title) {
39660 if (!this.title.hasOwnProperty(k)) {
39664 if (k.indexOf('-') >= 0) {
39665 var s = k.split('-');
39666 for (var i = 0; i<s.length; i++) {
39667 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
39670 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
39677 * Set this panel's title
39678 * @param {String} title
39680 setTitle : function(title){
39681 this.title = title;
39683 this.region.updatePanelTitle(this, title);
39688 * Returns true is this panel was configured to be closable
39689 * @return {Boolean}
39691 isClosable : function(){
39692 return this.closable;
39695 beforeSlide : function(){
39697 this.resizeEl.clip();
39700 afterSlide : function(){
39702 this.resizeEl.unclip();
39706 * Force a content refresh from the URL specified in the {@link #setUrl} method.
39707 * Will fail silently if the {@link #setUrl} method has not been called.
39708 * This does not activate the panel, just updates its content.
39710 refresh : function(){
39711 if(this.refreshDelegate){
39712 this.loaded = false;
39713 this.refreshDelegate();
39718 * Destroys this panel
39720 destroy : function(){
39721 this.el.removeAllListeners();
39722 var tempEl = document.createElement("span");
39723 tempEl.appendChild(this.el.dom);
39724 tempEl.innerHTML = "";
39730 * form - if the content panel contains a form - this is a reference to it.
39731 * @type {Roo.form.Form}
39735 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
39736 * This contains a reference to it.
39742 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
39752 * @param {Object} cfg Xtype definition of item to add.
39756 getChildContainer: function () {
39757 return this.getEl();
39762 var ret = new Roo.factory(cfg);
39767 if (cfg.xtype.match(/^Form$/)) {
39770 //if (this.footer) {
39771 // el = this.footer.container.insertSibling(false, 'before');
39773 el = this.el.createChild();
39776 this.form = new Roo.form.Form(cfg);
39779 if ( this.form.allItems.length) {
39780 this.form.render(el.dom);
39784 // should only have one of theses..
39785 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
39786 // views.. should not be just added - used named prop 'view''
39788 cfg.el = this.el.appendChild(document.createElement("div"));
39791 var ret = new Roo.factory(cfg);
39793 ret.render && ret.render(false, ''); // render blank..
39803 * @class Roo.bootstrap.panel.Grid
39804 * @extends Roo.bootstrap.panel.Content
39806 * Create a new GridPanel.
39807 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
39808 * @param {Object} config A the config object
39814 Roo.bootstrap.panel.Grid = function(config)
39818 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
39819 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
39821 config.el = this.wrapper;
39822 //this.el = this.wrapper;
39824 if (config.container) {
39825 // ctor'ed from a Border/panel.grid
39828 this.wrapper.setStyle("overflow", "hidden");
39829 this.wrapper.addClass('roo-grid-container');
39834 if(config.toolbar){
39835 var tool_el = this.wrapper.createChild();
39836 this.toolbar = Roo.factory(config.toolbar);
39838 if (config.toolbar.items) {
39839 ti = config.toolbar.items ;
39840 delete config.toolbar.items ;
39844 this.toolbar.render(tool_el);
39845 for(var i =0;i < ti.length;i++) {
39846 // Roo.log(['add child', items[i]]);
39847 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39849 this.toolbar.items = nitems;
39851 delete config.toolbar;
39854 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
39855 config.grid.scrollBody = true;;
39856 config.grid.monitorWindowResize = false; // turn off autosizing
39857 config.grid.autoHeight = false;
39858 config.grid.autoWidth = false;
39860 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
39862 if (config.background) {
39863 // render grid on panel activation (if panel background)
39864 this.on('activate', function(gp) {
39865 if (!gp.grid.rendered) {
39866 gp.grid.render(this.wrapper);
39867 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39872 this.grid.render(this.wrapper);
39873 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39876 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
39877 // ??? needed ??? config.el = this.wrapper;
39882 // xtype created footer. - not sure if will work as we normally have to render first..
39883 if (this.footer && !this.footer.el && this.footer.xtype) {
39885 var ctr = this.grid.getView().getFooterPanel(true);
39886 this.footer.dataSource = this.grid.dataSource;
39887 this.footer = Roo.factory(this.footer, Roo);
39888 this.footer.render(ctr);
39898 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
39899 getId : function(){
39900 return this.grid.id;
39904 * Returns the grid for this panel
39905 * @return {Roo.bootstrap.Table}
39907 getGrid : function(){
39911 setSize : function(width, height){
39912 if(!this.ignoreResize(width, height)){
39913 var grid = this.grid;
39914 var size = this.adjustForComponents(width, height);
39915 // tfoot is not a footer?
39918 var gridel = grid.getGridEl();
39919 gridel.setSize(size.width, size.height);
39921 var tbd = grid.getGridEl().select('tbody', true).first();
39922 var thd = grid.getGridEl().select('thead',true).first();
39923 var tbf= grid.getGridEl().select('tfoot', true).first();
39926 size.height -= thd.getHeight();
39929 size.height -= thd.getHeight();
39932 tbd.setSize(size.width, size.height );
39933 // this is for the account management tab -seems to work there.
39934 var thd = grid.getGridEl().select('thead',true).first();
39936 // tbd.setSize(size.width, size.height - thd.getHeight());
39945 beforeSlide : function(){
39946 this.grid.getView().scroller.clip();
39949 afterSlide : function(){
39950 this.grid.getView().scroller.unclip();
39953 destroy : function(){
39954 this.grid.destroy();
39956 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39961 * @class Roo.bootstrap.panel.Nest
39962 * @extends Roo.bootstrap.panel.Content
39964 * Create a new Panel, that can contain a layout.Border.
39967 * @param {Roo.BorderLayout} layout The layout for this panel
39968 * @param {String/Object} config A string to set only the title or a config object
39970 Roo.bootstrap.panel.Nest = function(config)
39972 // construct with only one argument..
39973 /* FIXME - implement nicer consturctors
39974 if (layout.layout) {
39976 layout = config.layout;
39977 delete config.layout;
39979 if (layout.xtype && !layout.getEl) {
39980 // then layout needs constructing..
39981 layout = Roo.factory(layout, Roo);
39985 config.el = config.layout.getEl();
39987 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39989 config.layout.monitorWindowResize = false; // turn off autosizing
39990 this.layout = config.layout;
39991 this.layout.getEl().addClass("roo-layout-nested-layout");
39992 this.layout.parent = this;
39999 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
40001 setSize : function(width, height){
40002 if(!this.ignoreResize(width, height)){
40003 var size = this.adjustForComponents(width, height);
40004 var el = this.layout.getEl();
40005 if (size.height < 1) {
40006 el.setWidth(size.width);
40008 el.setSize(size.width, size.height);
40010 var touch = el.dom.offsetWidth;
40011 this.layout.layout();
40012 // ie requires a double layout on the first pass
40013 if(Roo.isIE && !this.initialized){
40014 this.initialized = true;
40015 this.layout.layout();
40020 // activate all subpanels if not currently active..
40022 setActiveState : function(active){
40023 this.active = active;
40024 this.setActiveClass(active);
40027 this.fireEvent("deactivate", this);
40031 this.fireEvent("activate", this);
40032 // not sure if this should happen before or after..
40033 if (!this.layout) {
40034 return; // should not happen..
40037 for (var r in this.layout.regions) {
40038 reg = this.layout.getRegion(r);
40039 if (reg.getActivePanel()) {
40040 //reg.showPanel(reg.getActivePanel()); // force it to activate..
40041 reg.setActivePanel(reg.getActivePanel());
40044 if (!reg.panels.length) {
40047 reg.showPanel(reg.getPanel(0));
40056 * Returns the nested BorderLayout for this panel
40057 * @return {Roo.BorderLayout}
40059 getLayout : function(){
40060 return this.layout;
40064 * Adds a xtype elements to the layout of the nested panel
40068 xtype : 'ContentPanel',
40075 xtype : 'NestedLayoutPanel',
40081 items : [ ... list of content panels or nested layout panels.. ]
40085 * @param {Object} cfg Xtype definition of item to add.
40087 addxtype : function(cfg) {
40088 return this.layout.addxtype(cfg);
40093 * Ext JS Library 1.1.1
40094 * Copyright(c) 2006-2007, Ext JS, LLC.
40096 * Originally Released Under LGPL - original licence link has changed is not relivant.
40099 * <script type="text/javascript">
40102 * @class Roo.TabPanel
40103 * @extends Roo.util.Observable
40104 * A lightweight tab container.
40108 // basic tabs 1, built from existing content
40109 var tabs = new Roo.TabPanel("tabs1");
40110 tabs.addTab("script", "View Script");
40111 tabs.addTab("markup", "View Markup");
40112 tabs.activate("script");
40114 // more advanced tabs, built from javascript
40115 var jtabs = new Roo.TabPanel("jtabs");
40116 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
40118 // set up the UpdateManager
40119 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
40120 var updater = tab2.getUpdateManager();
40121 updater.setDefaultUrl("ajax1.htm");
40122 tab2.on('activate', updater.refresh, updater, true);
40124 // Use setUrl for Ajax loading
40125 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
40126 tab3.setUrl("ajax2.htm", null, true);
40129 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
40132 jtabs.activate("jtabs-1");
40135 * Create a new TabPanel.
40136 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
40137 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
40139 Roo.bootstrap.panel.Tabs = function(config){
40141 * The container element for this TabPanel.
40142 * @type Roo.Element
40144 this.el = Roo.get(config.el);
40147 if(typeof config == "boolean"){
40148 this.tabPosition = config ? "bottom" : "top";
40150 Roo.apply(this, config);
40154 if(this.tabPosition == "bottom"){
40155 // if tabs are at the bottom = create the body first.
40156 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40157 this.el.addClass("roo-tabs-bottom");
40159 // next create the tabs holders
40161 if (this.tabPosition == "west"){
40163 var reg = this.region; // fake it..
40165 if (!reg.mgr.parent) {
40168 reg = reg.mgr.parent.region;
40170 Roo.log("got nest?");
40172 if (reg.mgr.getRegion('west')) {
40173 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
40174 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
40175 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40176 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40177 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40185 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
40186 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40187 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40188 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40193 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
40196 // finally - if tabs are at the top, then create the body last..
40197 if(this.tabPosition != "bottom"){
40198 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
40199 * @type Roo.Element
40201 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40202 this.el.addClass("roo-tabs-top");
40206 this.bodyEl.setStyle("position", "relative");
40208 this.active = null;
40209 this.activateDelegate = this.activate.createDelegate(this);
40214 * Fires when the active tab changes
40215 * @param {Roo.TabPanel} this
40216 * @param {Roo.TabPanelItem} activePanel The new active tab
40220 * @event beforetabchange
40221 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
40222 * @param {Roo.TabPanel} this
40223 * @param {Object} e Set cancel to true on this object to cancel the tab change
40224 * @param {Roo.TabPanelItem} tab The tab being changed to
40226 "beforetabchange" : true
40229 Roo.EventManager.onWindowResize(this.onResize, this);
40230 this.cpad = this.el.getPadding("lr");
40231 this.hiddenCount = 0;
40234 // toolbar on the tabbar support...
40235 if (this.toolbar) {
40236 alert("no toolbar support yet");
40237 this.toolbar = false;
40239 var tcfg = this.toolbar;
40240 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
40241 this.toolbar = new Roo.Toolbar(tcfg);
40242 if (Roo.isSafari) {
40243 var tbl = tcfg.container.child('table', true);
40244 tbl.setAttribute('width', '100%');
40252 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
40255 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
40257 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
40259 tabPosition : "top",
40261 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
40263 currentTabWidth : 0,
40265 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
40269 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
40273 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
40275 preferredTabWidth : 175,
40277 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
40279 resizeTabs : false,
40281 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
40283 monitorResize : true,
40285 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
40287 toolbar : false, // set by caller..
40289 region : false, /// set by caller
40291 disableTooltips : true, // not used yet...
40294 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
40295 * @param {String} id The id of the div to use <b>or create</b>
40296 * @param {String} text The text for the tab
40297 * @param {String} content (optional) Content to put in the TabPanelItem body
40298 * @param {Boolean} closable (optional) True to create a close icon on the tab
40299 * @return {Roo.TabPanelItem} The created TabPanelItem
40301 addTab : function(id, text, content, closable, tpl)
40303 var item = new Roo.bootstrap.panel.TabItem({
40307 closable : closable,
40310 this.addTabItem(item);
40312 item.setContent(content);
40318 * Returns the {@link Roo.TabPanelItem} with the specified id/index
40319 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
40320 * @return {Roo.TabPanelItem}
40322 getTab : function(id){
40323 return this.items[id];
40327 * Hides the {@link Roo.TabPanelItem} with the specified id/index
40328 * @param {String/Number} id The id or index of the TabPanelItem to hide.
40330 hideTab : function(id){
40331 var t = this.items[id];
40334 this.hiddenCount++;
40335 this.autoSizeTabs();
40340 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
40341 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
40343 unhideTab : function(id){
40344 var t = this.items[id];
40346 t.setHidden(false);
40347 this.hiddenCount--;
40348 this.autoSizeTabs();
40353 * Adds an existing {@link Roo.TabPanelItem}.
40354 * @param {Roo.TabPanelItem} item The TabPanelItem to add
40356 addTabItem : function(item)
40358 this.items[item.id] = item;
40359 this.items.push(item);
40360 this.autoSizeTabs();
40361 // if(this.resizeTabs){
40362 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
40363 // this.autoSizeTabs();
40365 // item.autoSize();
40370 * Removes a {@link Roo.TabPanelItem}.
40371 * @param {String/Number} id The id or index of the TabPanelItem to remove.
40373 removeTab : function(id){
40374 var items = this.items;
40375 var tab = items[id];
40376 if(!tab) { return; }
40377 var index = items.indexOf(tab);
40378 if(this.active == tab && items.length > 1){
40379 var newTab = this.getNextAvailable(index);
40384 this.stripEl.dom.removeChild(tab.pnode.dom);
40385 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
40386 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
40388 items.splice(index, 1);
40389 delete this.items[tab.id];
40390 tab.fireEvent("close", tab);
40391 tab.purgeListeners();
40392 this.autoSizeTabs();
40395 getNextAvailable : function(start){
40396 var items = this.items;
40398 // look for a next tab that will slide over to
40399 // replace the one being removed
40400 while(index < items.length){
40401 var item = items[++index];
40402 if(item && !item.isHidden()){
40406 // if one isn't found select the previous tab (on the left)
40409 var item = items[--index];
40410 if(item && !item.isHidden()){
40418 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
40419 * @param {String/Number} id The id or index of the TabPanelItem to disable.
40421 disableTab : function(id){
40422 var tab = this.items[id];
40423 if(tab && this.active != tab){
40429 * Enables a {@link Roo.TabPanelItem} that is disabled.
40430 * @param {String/Number} id The id or index of the TabPanelItem to enable.
40432 enableTab : function(id){
40433 var tab = this.items[id];
40438 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
40439 * @param {String/Number} id The id or index of the TabPanelItem to activate.
40440 * @return {Roo.TabPanelItem} The TabPanelItem.
40442 activate : function(id)
40444 //Roo.log('activite:' + id);
40446 var tab = this.items[id];
40450 if(tab == this.active || tab.disabled){
40454 this.fireEvent("beforetabchange", this, e, tab);
40455 if(e.cancel !== true && !tab.disabled){
40457 this.active.hide();
40459 this.active = this.items[id];
40460 this.active.show();
40461 this.fireEvent("tabchange", this, this.active);
40467 * Gets the active {@link Roo.TabPanelItem}.
40468 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
40470 getActiveTab : function(){
40471 return this.active;
40475 * Updates the tab body element to fit the height of the container element
40476 * for overflow scrolling
40477 * @param {Number} targetHeight (optional) Override the starting height from the elements height
40479 syncHeight : function(targetHeight){
40480 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
40481 var bm = this.bodyEl.getMargins();
40482 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
40483 this.bodyEl.setHeight(newHeight);
40487 onResize : function(){
40488 if(this.monitorResize){
40489 this.autoSizeTabs();
40494 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
40496 beginUpdate : function(){
40497 this.updating = true;
40501 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
40503 endUpdate : function(){
40504 this.updating = false;
40505 this.autoSizeTabs();
40509 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
40511 autoSizeTabs : function()
40513 var count = this.items.length;
40514 var vcount = count - this.hiddenCount;
40517 this.stripEl.hide();
40519 this.stripEl.show();
40522 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
40527 var w = Math.max(this.el.getWidth() - this.cpad, 10);
40528 var availWidth = Math.floor(w / vcount);
40529 var b = this.stripBody;
40530 if(b.getWidth() > w){
40531 var tabs = this.items;
40532 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
40533 if(availWidth < this.minTabWidth){
40534 /*if(!this.sleft){ // incomplete scrolling code
40535 this.createScrollButtons();
40538 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
40541 if(this.currentTabWidth < this.preferredTabWidth){
40542 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
40548 * Returns the number of tabs in this TabPanel.
40551 getCount : function(){
40552 return this.items.length;
40556 * Resizes all the tabs to the passed width
40557 * @param {Number} The new width
40559 setTabWidth : function(width){
40560 this.currentTabWidth = width;
40561 for(var i = 0, len = this.items.length; i < len; i++) {
40562 if(!this.items[i].isHidden()) {
40563 this.items[i].setWidth(width);
40569 * Destroys this TabPanel
40570 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
40572 destroy : function(removeEl){
40573 Roo.EventManager.removeResizeListener(this.onResize, this);
40574 for(var i = 0, len = this.items.length; i < len; i++){
40575 this.items[i].purgeListeners();
40577 if(removeEl === true){
40578 this.el.update("");
40583 createStrip : function(container)
40585 var strip = document.createElement("nav");
40586 strip.className = Roo.bootstrap.version == 4 ?
40587 "navbar-light bg-light" :
40588 "navbar navbar-default"; //"x-tabs-wrap";
40589 container.appendChild(strip);
40593 createStripList : function(strip)
40595 // div wrapper for retard IE
40596 // returns the "tr" element.
40597 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
40598 //'<div class="x-tabs-strip-wrap">'+
40599 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
40600 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
40601 return strip.firstChild; //.firstChild.firstChild.firstChild;
40603 createBody : function(container)
40605 var body = document.createElement("div");
40606 Roo.id(body, "tab-body");
40607 //Roo.fly(body).addClass("x-tabs-body");
40608 Roo.fly(body).addClass("tab-content");
40609 container.appendChild(body);
40612 createItemBody :function(bodyEl, id){
40613 var body = Roo.getDom(id);
40615 body = document.createElement("div");
40618 //Roo.fly(body).addClass("x-tabs-item-body");
40619 Roo.fly(body).addClass("tab-pane");
40620 bodyEl.insertBefore(body, bodyEl.firstChild);
40624 createStripElements : function(stripEl, text, closable, tpl)
40626 var td = document.createElement("li"); // was td..
40627 td.className = 'nav-item';
40629 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
40632 stripEl.appendChild(td);
40634 td.className = "x-tabs-closable";
40635 if(!this.closeTpl){
40636 this.closeTpl = new Roo.Template(
40637 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40638 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
40639 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
40642 var el = this.closeTpl.overwrite(td, {"text": text});
40643 var close = el.getElementsByTagName("div")[0];
40644 var inner = el.getElementsByTagName("em")[0];
40645 return {"el": el, "close": close, "inner": inner};
40648 // not sure what this is..
40649 // if(!this.tabTpl){
40650 //this.tabTpl = new Roo.Template(
40651 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40652 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
40654 // this.tabTpl = new Roo.Template(
40655 // '<a href="#">' +
40656 // '<span unselectable="on"' +
40657 // (this.disableTooltips ? '' : ' title="{text}"') +
40658 // ' >{text}</span></a>'
40664 var template = tpl || this.tabTpl || false;
40667 template = new Roo.Template(
40668 Roo.bootstrap.version == 4 ?
40670 '<a class="nav-link" href="#" unselectable="on"' +
40671 (this.disableTooltips ? '' : ' title="{text}"') +
40674 '<a class="nav-link" href="#">' +
40675 '<span unselectable="on"' +
40676 (this.disableTooltips ? '' : ' title="{text}"') +
40677 ' >{text}</span></a>'
40682 switch (typeof(template)) {
40686 template = new Roo.Template(template);
40692 var el = template.overwrite(td, {"text": text});
40694 var inner = el.getElementsByTagName("span")[0];
40696 return {"el": el, "inner": inner};
40704 * @class Roo.TabPanelItem
40705 * @extends Roo.util.Observable
40706 * Represents an individual item (tab plus body) in a TabPanel.
40707 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
40708 * @param {String} id The id of this TabPanelItem
40709 * @param {String} text The text for the tab of this TabPanelItem
40710 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
40712 Roo.bootstrap.panel.TabItem = function(config){
40714 * The {@link Roo.TabPanel} this TabPanelItem belongs to
40715 * @type Roo.TabPanel
40717 this.tabPanel = config.panel;
40719 * The id for this TabPanelItem
40722 this.id = config.id;
40724 this.disabled = false;
40726 this.text = config.text;
40728 this.loaded = false;
40729 this.closable = config.closable;
40732 * The body element for this TabPanelItem.
40733 * @type Roo.Element
40735 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
40736 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
40737 this.bodyEl.setStyle("display", "block");
40738 this.bodyEl.setStyle("zoom", "1");
40739 //this.hideAction();
40741 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
40743 this.el = Roo.get(els.el);
40744 this.inner = Roo.get(els.inner, true);
40745 this.textEl = Roo.bootstrap.version == 4 ?
40746 this.el : Roo.get(this.el.dom.firstChild, true);
40748 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
40749 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
40752 // this.el.on("mousedown", this.onTabMouseDown, this);
40753 this.el.on("click", this.onTabClick, this);
40755 if(config.closable){
40756 var c = Roo.get(els.close, true);
40757 c.dom.title = this.closeText;
40758 c.addClassOnOver("close-over");
40759 c.on("click", this.closeClick, this);
40765 * Fires when this tab becomes the active tab.
40766 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40767 * @param {Roo.TabPanelItem} this
40771 * @event beforeclose
40772 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
40773 * @param {Roo.TabPanelItem} this
40774 * @param {Object} e Set cancel to true on this object to cancel the close.
40776 "beforeclose": true,
40779 * Fires when this tab is closed.
40780 * @param {Roo.TabPanelItem} this
40784 * @event deactivate
40785 * Fires when this tab is no longer the active tab.
40786 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40787 * @param {Roo.TabPanelItem} this
40789 "deactivate" : true
40791 this.hidden = false;
40793 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
40796 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
40798 purgeListeners : function(){
40799 Roo.util.Observable.prototype.purgeListeners.call(this);
40800 this.el.removeAllListeners();
40803 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
40806 this.status_node.addClass("active");
40809 this.tabPanel.stripWrap.repaint();
40811 this.fireEvent("activate", this.tabPanel, this);
40815 * Returns true if this tab is the active tab.
40816 * @return {Boolean}
40818 isActive : function(){
40819 return this.tabPanel.getActiveTab() == this;
40823 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
40826 this.status_node.removeClass("active");
40828 this.fireEvent("deactivate", this.tabPanel, this);
40831 hideAction : function(){
40832 this.bodyEl.hide();
40833 this.bodyEl.setStyle("position", "absolute");
40834 this.bodyEl.setLeft("-20000px");
40835 this.bodyEl.setTop("-20000px");
40838 showAction : function(){
40839 this.bodyEl.setStyle("position", "relative");
40840 this.bodyEl.setTop("");
40841 this.bodyEl.setLeft("");
40842 this.bodyEl.show();
40846 * Set the tooltip for the tab.
40847 * @param {String} tooltip The tab's tooltip
40849 setTooltip : function(text){
40850 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
40851 this.textEl.dom.qtip = text;
40852 this.textEl.dom.removeAttribute('title');
40854 this.textEl.dom.title = text;
40858 onTabClick : function(e){
40859 e.preventDefault();
40860 this.tabPanel.activate(this.id);
40863 onTabMouseDown : function(e){
40864 e.preventDefault();
40865 this.tabPanel.activate(this.id);
40868 getWidth : function(){
40869 return this.inner.getWidth();
40872 setWidth : function(width){
40873 var iwidth = width - this.linode.getPadding("lr");
40874 this.inner.setWidth(iwidth);
40875 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
40876 this.linode.setWidth(width);
40880 * Show or hide the tab
40881 * @param {Boolean} hidden True to hide or false to show.
40883 setHidden : function(hidden){
40884 this.hidden = hidden;
40885 this.linode.setStyle("display", hidden ? "none" : "");
40889 * Returns true if this tab is "hidden"
40890 * @return {Boolean}
40892 isHidden : function(){
40893 return this.hidden;
40897 * Returns the text for this tab
40900 getText : function(){
40904 autoSize : function(){
40905 //this.el.beginMeasure();
40906 this.textEl.setWidth(1);
40908 * #2804 [new] Tabs in Roojs
40909 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
40911 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
40912 //this.el.endMeasure();
40916 * Sets the text for the tab (Note: this also sets the tooltip text)
40917 * @param {String} text The tab's text and tooltip
40919 setText : function(text){
40921 this.textEl.update(text);
40922 this.setTooltip(text);
40923 //if(!this.tabPanel.resizeTabs){
40924 // this.autoSize();
40928 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
40930 activate : function(){
40931 this.tabPanel.activate(this.id);
40935 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
40937 disable : function(){
40938 if(this.tabPanel.active != this){
40939 this.disabled = true;
40940 this.status_node.addClass("disabled");
40945 * Enables this TabPanelItem if it was previously disabled.
40947 enable : function(){
40948 this.disabled = false;
40949 this.status_node.removeClass("disabled");
40953 * Sets the content for this TabPanelItem.
40954 * @param {String} content The content
40955 * @param {Boolean} loadScripts true to look for and load scripts
40957 setContent : function(content, loadScripts){
40958 this.bodyEl.update(content, loadScripts);
40962 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40963 * @return {Roo.UpdateManager} The UpdateManager
40965 getUpdateManager : function(){
40966 return this.bodyEl.getUpdateManager();
40970 * Set a URL to be used to load the content for this TabPanelItem.
40971 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40972 * @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)
40973 * @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)
40974 * @return {Roo.UpdateManager} The UpdateManager
40976 setUrl : function(url, params, loadOnce){
40977 if(this.refreshDelegate){
40978 this.un('activate', this.refreshDelegate);
40980 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40981 this.on("activate", this.refreshDelegate);
40982 return this.bodyEl.getUpdateManager();
40986 _handleRefresh : function(url, params, loadOnce){
40987 if(!loadOnce || !this.loaded){
40988 var updater = this.bodyEl.getUpdateManager();
40989 updater.update(url, params, this._setLoaded.createDelegate(this));
40994 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40995 * Will fail silently if the setUrl method has not been called.
40996 * This does not activate the panel, just updates its content.
40998 refresh : function(){
40999 if(this.refreshDelegate){
41000 this.loaded = false;
41001 this.refreshDelegate();
41006 _setLoaded : function(){
41007 this.loaded = true;
41011 closeClick : function(e){
41014 this.fireEvent("beforeclose", this, o);
41015 if(o.cancel !== true){
41016 this.tabPanel.removeTab(this.id);
41020 * The text displayed in the tooltip for the close icon.
41023 closeText : "Close this tab"
41026 * This script refer to:
41027 * Title: International Telephone Input
41028 * Author: Jack O'Connor
41029 * Code version: v12.1.12
41030 * Availability: https://github.com/jackocnr/intl-tel-input.git
41033 Roo.bootstrap.PhoneInputData = function() {
41036 "Afghanistan (افغانستان)",
41041 "Albania (Shqipëri)",
41046 "Algeria (الجزائر)",
41071 "Antigua and Barbuda",
41081 "Armenia (Հայաստան)",
41097 "Austria (Österreich)",
41102 "Azerbaijan (Azərbaycan)",
41112 "Bahrain (البحرين)",
41117 "Bangladesh (বাংলাদেশ)",
41127 "Belarus (Беларусь)",
41132 "Belgium (België)",
41162 "Bosnia and Herzegovina (Босна и Херцеговина)",
41177 "British Indian Ocean Territory",
41182 "British Virgin Islands",
41192 "Bulgaria (България)",
41202 "Burundi (Uburundi)",
41207 "Cambodia (កម្ពុជា)",
41212 "Cameroon (Cameroun)",
41221 ["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"]
41224 "Cape Verde (Kabu Verdi)",
41229 "Caribbean Netherlands",
41240 "Central African Republic (République centrafricaine)",
41260 "Christmas Island",
41266 "Cocos (Keeling) Islands",
41277 "Comoros (جزر القمر)",
41282 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
41287 "Congo (Republic) (Congo-Brazzaville)",
41307 "Croatia (Hrvatska)",
41328 "Czech Republic (Česká republika)",
41333 "Denmark (Danmark)",
41348 "Dominican Republic (República Dominicana)",
41352 ["809", "829", "849"]
41370 "Equatorial Guinea (Guinea Ecuatorial)",
41390 "Falkland Islands (Islas Malvinas)",
41395 "Faroe Islands (Føroyar)",
41416 "French Guiana (Guyane française)",
41421 "French Polynesia (Polynésie française)",
41436 "Georgia (საქართველო)",
41441 "Germany (Deutschland)",
41461 "Greenland (Kalaallit Nunaat)",
41498 "Guinea-Bissau (Guiné Bissau)",
41523 "Hungary (Magyarország)",
41528 "Iceland (Ísland)",
41548 "Iraq (العراق)",
41564 "Israel (ישראל)",
41591 "Jordan (الأردن)",
41596 "Kazakhstan (Казахстан)",
41617 "Kuwait (الكويت)",
41622 "Kyrgyzstan (Кыргызстан)",
41632 "Latvia (Latvija)",
41637 "Lebanon (لبنان)",
41652 "Libya (ليبيا)",
41662 "Lithuania (Lietuva)",
41677 "Macedonia (FYROM) (Македонија)",
41682 "Madagascar (Madagasikara)",
41712 "Marshall Islands",
41722 "Mauritania (موريتانيا)",
41727 "Mauritius (Moris)",
41748 "Moldova (Republica Moldova)",
41758 "Mongolia (Монгол)",
41763 "Montenegro (Crna Gora)",
41773 "Morocco (المغرب)",
41779 "Mozambique (Moçambique)",
41784 "Myanmar (Burma) (မြန်မာ)",
41789 "Namibia (Namibië)",
41804 "Netherlands (Nederland)",
41809 "New Caledonia (Nouvelle-Calédonie)",
41844 "North Korea (조선 민주주의 인민 공화국)",
41849 "Northern Mariana Islands",
41865 "Pakistan (پاکستان)",
41875 "Palestine (فلسطين)",
41885 "Papua New Guinea",
41927 "Réunion (La Réunion)",
41933 "Romania (România)",
41949 "Saint Barthélemy",
41960 "Saint Kitts and Nevis",
41970 "Saint Martin (Saint-Martin (partie française))",
41976 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41981 "Saint Vincent and the Grenadines",
41996 "São Tomé and Príncipe (São Tomé e Príncipe)",
42001 "Saudi Arabia (المملكة العربية السعودية)",
42006 "Senegal (Sénégal)",
42036 "Slovakia (Slovensko)",
42041 "Slovenia (Slovenija)",
42051 "Somalia (Soomaaliya)",
42061 "South Korea (대한민국)",
42066 "South Sudan (جنوب السودان)",
42076 "Sri Lanka (ශ්රී ලංකාව)",
42081 "Sudan (السودان)",
42091 "Svalbard and Jan Mayen",
42102 "Sweden (Sverige)",
42107 "Switzerland (Schweiz)",
42112 "Syria (سوريا)",
42157 "Trinidad and Tobago",
42162 "Tunisia (تونس)",
42167 "Turkey (Türkiye)",
42177 "Turks and Caicos Islands",
42187 "U.S. Virgin Islands",
42197 "Ukraine (Україна)",
42202 "United Arab Emirates (الإمارات العربية المتحدة)",
42224 "Uzbekistan (Oʻzbekiston)",
42234 "Vatican City (Città del Vaticano)",
42245 "Vietnam (Việt Nam)",
42250 "Wallis and Futuna (Wallis-et-Futuna)",
42255 "Western Sahara (الصحراء الغربية)",
42261 "Yemen (اليمن)",
42285 * This script refer to:
42286 * Title: International Telephone Input
42287 * Author: Jack O'Connor
42288 * Code version: v12.1.12
42289 * Availability: https://github.com/jackocnr/intl-tel-input.git
42293 * @class Roo.bootstrap.PhoneInput
42294 * @extends Roo.bootstrap.TriggerField
42295 * An input with International dial-code selection
42297 * @cfg {String} defaultDialCode default '+852'
42298 * @cfg {Array} preferedCountries default []
42301 * Create a new PhoneInput.
42302 * @param {Object} config Configuration options
42305 Roo.bootstrap.PhoneInput = function(config) {
42306 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
42309 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
42311 listWidth: undefined,
42313 selectedClass: 'active',
42315 invalidClass : "has-warning",
42317 validClass: 'has-success',
42319 allowed: '0123456789',
42324 * @cfg {String} defaultDialCode The default dial code when initializing the input
42326 defaultDialCode: '+852',
42329 * @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
42331 preferedCountries: false,
42333 getAutoCreate : function()
42335 var data = Roo.bootstrap.PhoneInputData();
42336 var align = this.labelAlign || this.parentLabelAlign();
42339 this.allCountries = [];
42340 this.dialCodeMapping = [];
42342 for (var i = 0; i < data.length; i++) {
42344 this.allCountries[i] = {
42348 priority: c[3] || 0,
42349 areaCodes: c[4] || null
42351 this.dialCodeMapping[c[2]] = {
42354 priority: c[3] || 0,
42355 areaCodes: c[4] || null
42367 // type: 'number', -- do not use number - we get the flaky up/down arrows.
42368 maxlength: this.max_length,
42369 cls : 'form-control tel-input',
42370 autocomplete: 'new-password'
42373 var hiddenInput = {
42376 cls: 'hidden-tel-input'
42380 hiddenInput.name = this.name;
42383 if (this.disabled) {
42384 input.disabled = true;
42387 var flag_container = {
42404 cls: this.hasFeedback ? 'has-feedback' : '',
42410 cls: 'dial-code-holder',
42417 cls: 'roo-select2-container input-group',
42424 if (this.fieldLabel.length) {
42427 tooltip: 'This field is required'
42433 cls: 'control-label',
42439 html: this.fieldLabel
42442 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42448 if(this.indicatorpos == 'right') {
42449 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42456 if(align == 'left') {
42464 if(this.labelWidth > 12){
42465 label.style = "width: " + this.labelWidth + 'px';
42467 if(this.labelWidth < 13 && this.labelmd == 0){
42468 this.labelmd = this.labelWidth;
42470 if(this.labellg > 0){
42471 label.cls += ' col-lg-' + this.labellg;
42472 input.cls += ' col-lg-' + (12 - this.labellg);
42474 if(this.labelmd > 0){
42475 label.cls += ' col-md-' + this.labelmd;
42476 container.cls += ' col-md-' + (12 - this.labelmd);
42478 if(this.labelsm > 0){
42479 label.cls += ' col-sm-' + this.labelsm;
42480 container.cls += ' col-sm-' + (12 - this.labelsm);
42482 if(this.labelxs > 0){
42483 label.cls += ' col-xs-' + this.labelxs;
42484 container.cls += ' col-xs-' + (12 - this.labelxs);
42494 var settings = this;
42496 ['xs','sm','md','lg'].map(function(size){
42497 if (settings[size]) {
42498 cfg.cls += ' col-' + size + '-' + settings[size];
42502 this.store = new Roo.data.Store({
42503 proxy : new Roo.data.MemoryProxy({}),
42504 reader : new Roo.data.JsonReader({
42515 'name' : 'dialCode',
42519 'name' : 'priority',
42523 'name' : 'areaCodes',
42530 if(!this.preferedCountries) {
42531 this.preferedCountries = [
42538 var p = this.preferedCountries.reverse();
42541 for (var i = 0; i < p.length; i++) {
42542 for (var j = 0; j < this.allCountries.length; j++) {
42543 if(this.allCountries[j].iso2 == p[i]) {
42544 var t = this.allCountries[j];
42545 this.allCountries.splice(j,1);
42546 this.allCountries.unshift(t);
42552 this.store.proxy.data = {
42554 data: this.allCountries
42560 initEvents : function()
42563 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
42565 this.indicator = this.indicatorEl();
42566 this.flag = this.flagEl();
42567 this.dialCodeHolder = this.dialCodeHolderEl();
42569 this.trigger = this.el.select('div.flag-box',true).first();
42570 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
42575 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42576 _this.list.setWidth(lw);
42579 this.list.on('mouseover', this.onViewOver, this);
42580 this.list.on('mousemove', this.onViewMove, this);
42581 this.inputEl().on("keyup", this.onKeyUp, this);
42582 this.inputEl().on("keypress", this.onKeyPress, this);
42584 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
42586 this.view = new Roo.View(this.list, this.tpl, {
42587 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42590 this.view.on('click', this.onViewClick, this);
42591 this.setValue(this.defaultDialCode);
42594 onTriggerClick : function(e)
42596 Roo.log('trigger click');
42601 if(this.isExpanded()){
42603 this.hasFocus = false;
42605 this.store.load({});
42606 this.hasFocus = true;
42611 isExpanded : function()
42613 return this.list.isVisible();
42616 collapse : function()
42618 if(!this.isExpanded()){
42622 Roo.get(document).un('mousedown', this.collapseIf, this);
42623 Roo.get(document).un('mousewheel', this.collapseIf, this);
42624 this.fireEvent('collapse', this);
42628 expand : function()
42632 if(this.isExpanded() || !this.hasFocus){
42636 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
42637 this.list.setWidth(lw);
42640 this.restrictHeight();
42642 Roo.get(document).on('mousedown', this.collapseIf, this);
42643 Roo.get(document).on('mousewheel', this.collapseIf, this);
42645 this.fireEvent('expand', this);
42648 restrictHeight : function()
42650 this.list.alignTo(this.inputEl(), this.listAlign);
42651 this.list.alignTo(this.inputEl(), this.listAlign);
42654 onViewOver : function(e, t)
42656 if(this.inKeyMode){
42659 var item = this.view.findItemFromChild(t);
42662 var index = this.view.indexOf(item);
42663 this.select(index, false);
42668 onViewClick : function(view, doFocus, el, e)
42670 var index = this.view.getSelectedIndexes()[0];
42672 var r = this.store.getAt(index);
42675 this.onSelect(r, index);
42677 if(doFocus !== false && !this.blockFocus){
42678 this.inputEl().focus();
42682 onViewMove : function(e, t)
42684 this.inKeyMode = false;
42687 select : function(index, scrollIntoView)
42689 this.selectedIndex = index;
42690 this.view.select(index);
42691 if(scrollIntoView !== false){
42692 var el = this.view.getNode(index);
42694 this.list.scrollChildIntoView(el, false);
42699 createList : function()
42701 this.list = Roo.get(document.body).createChild({
42703 cls: 'typeahead typeahead-long dropdown-menu tel-list',
42704 style: 'display:none'
42707 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
42710 collapseIf : function(e)
42712 var in_combo = e.within(this.el);
42713 var in_list = e.within(this.list);
42714 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
42716 if (in_combo || in_list || is_list) {
42722 onSelect : function(record, index)
42724 if(this.fireEvent('beforeselect', this, record, index) !== false){
42726 this.setFlagClass(record.data.iso2);
42727 this.setDialCode(record.data.dialCode);
42728 this.hasFocus = false;
42730 this.fireEvent('select', this, record, index);
42734 flagEl : function()
42736 var flag = this.el.select('div.flag',true).first();
42743 dialCodeHolderEl : function()
42745 var d = this.el.select('input.dial-code-holder',true).first();
42752 setDialCode : function(v)
42754 this.dialCodeHolder.dom.value = '+'+v;
42757 setFlagClass : function(n)
42759 this.flag.dom.className = 'flag '+n;
42762 getValue : function()
42764 var v = this.inputEl().getValue();
42765 if(this.dialCodeHolder) {
42766 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
42771 setValue : function(v)
42773 var d = this.getDialCode(v);
42775 //invalid dial code
42776 if(v.length == 0 || !d || d.length == 0) {
42778 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
42779 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42785 this.setFlagClass(this.dialCodeMapping[d].iso2);
42786 this.setDialCode(d);
42787 this.inputEl().dom.value = v.replace('+'+d,'');
42788 this.hiddenEl().dom.value = this.getValue();
42793 getDialCode : function(v)
42797 if (v.length == 0) {
42798 return this.dialCodeHolder.dom.value;
42802 if (v.charAt(0) != "+") {
42805 var numericChars = "";
42806 for (var i = 1; i < v.length; i++) {
42807 var c = v.charAt(i);
42810 if (this.dialCodeMapping[numericChars]) {
42811 dialCode = v.substr(1, i);
42813 if (numericChars.length == 4) {
42823 this.setValue(this.defaultDialCode);
42827 hiddenEl : function()
42829 return this.el.select('input.hidden-tel-input',true).first();
42832 // after setting val
42833 onKeyUp : function(e){
42834 this.setValue(this.getValue());
42837 onKeyPress : function(e){
42838 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
42845 * @class Roo.bootstrap.MoneyField
42846 * @extends Roo.bootstrap.ComboBox
42847 * Bootstrap MoneyField class
42850 * Create a new MoneyField.
42851 * @param {Object} config Configuration options
42854 Roo.bootstrap.MoneyField = function(config) {
42856 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
42860 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
42863 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
42865 allowDecimals : true,
42867 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
42869 decimalSeparator : ".",
42871 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
42873 decimalPrecision : 0,
42875 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
42877 allowNegative : true,
42879 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
42883 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
42885 minValue : Number.NEGATIVE_INFINITY,
42887 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
42889 maxValue : Number.MAX_VALUE,
42891 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
42893 minText : "The minimum value for this field is {0}",
42895 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
42897 maxText : "The maximum value for this field is {0}",
42899 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
42900 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
42902 nanText : "{0} is not a valid number",
42904 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
42908 * @cfg {String} defaults currency of the MoneyField
42909 * value should be in lkey
42911 defaultCurrency : false,
42913 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
42915 thousandsDelimiter : false,
42917 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
42928 getAutoCreate : function()
42930 var align = this.labelAlign || this.parentLabelAlign();
42942 cls : 'form-control roo-money-amount-input',
42943 autocomplete: 'new-password'
42946 var hiddenInput = {
42950 cls: 'hidden-number-input'
42953 if(this.max_length) {
42954 input.maxlength = this.max_length;
42958 hiddenInput.name = this.name;
42961 if (this.disabled) {
42962 input.disabled = true;
42965 var clg = 12 - this.inputlg;
42966 var cmd = 12 - this.inputmd;
42967 var csm = 12 - this.inputsm;
42968 var cxs = 12 - this.inputxs;
42972 cls : 'row roo-money-field',
42976 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42980 cls: 'roo-select2-container input-group',
42984 cls : 'form-control roo-money-currency-input',
42985 autocomplete: 'new-password',
42987 name : this.currencyName
42991 cls : 'input-group-addon',
43005 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
43009 cls: this.hasFeedback ? 'has-feedback' : '',
43020 if (this.fieldLabel.length) {
43023 tooltip: 'This field is required'
43029 cls: 'control-label',
43035 html: this.fieldLabel
43038 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
43044 if(this.indicatorpos == 'right') {
43045 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
43052 if(align == 'left') {
43060 if(this.labelWidth > 12){
43061 label.style = "width: " + this.labelWidth + 'px';
43063 if(this.labelWidth < 13 && this.labelmd == 0){
43064 this.labelmd = this.labelWidth;
43066 if(this.labellg > 0){
43067 label.cls += ' col-lg-' + this.labellg;
43068 input.cls += ' col-lg-' + (12 - this.labellg);
43070 if(this.labelmd > 0){
43071 label.cls += ' col-md-' + this.labelmd;
43072 container.cls += ' col-md-' + (12 - this.labelmd);
43074 if(this.labelsm > 0){
43075 label.cls += ' col-sm-' + this.labelsm;
43076 container.cls += ' col-sm-' + (12 - this.labelsm);
43078 if(this.labelxs > 0){
43079 label.cls += ' col-xs-' + this.labelxs;
43080 container.cls += ' col-xs-' + (12 - this.labelxs);
43091 var settings = this;
43093 ['xs','sm','md','lg'].map(function(size){
43094 if (settings[size]) {
43095 cfg.cls += ' col-' + size + '-' + settings[size];
43102 initEvents : function()
43104 this.indicator = this.indicatorEl();
43106 this.initCurrencyEvent();
43108 this.initNumberEvent();
43111 initCurrencyEvent : function()
43114 throw "can not find store for combo";
43117 this.store = Roo.factory(this.store, Roo.data);
43118 this.store.parent = this;
43122 this.triggerEl = this.el.select('.input-group-addon', true).first();
43124 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
43129 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
43130 _this.list.setWidth(lw);
43133 this.list.on('mouseover', this.onViewOver, this);
43134 this.list.on('mousemove', this.onViewMove, this);
43135 this.list.on('scroll', this.onViewScroll, this);
43138 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
43141 this.view = new Roo.View(this.list, this.tpl, {
43142 singleSelect:true, store: this.store, selectedClass: this.selectedClass
43145 this.view.on('click', this.onViewClick, this);
43147 this.store.on('beforeload', this.onBeforeLoad, this);
43148 this.store.on('load', this.onLoad, this);
43149 this.store.on('loadexception', this.onLoadException, this);
43151 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
43152 "up" : function(e){
43153 this.inKeyMode = true;
43157 "down" : function(e){
43158 if(!this.isExpanded()){
43159 this.onTriggerClick();
43161 this.inKeyMode = true;
43166 "enter" : function(e){
43169 if(this.fireEvent("specialkey", this, e)){
43170 this.onViewClick(false);
43176 "esc" : function(e){
43180 "tab" : function(e){
43183 if(this.fireEvent("specialkey", this, e)){
43184 this.onViewClick(false);
43192 doRelay : function(foo, bar, hname){
43193 if(hname == 'down' || this.scope.isExpanded()){
43194 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43202 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
43206 initNumberEvent : function(e)
43208 this.inputEl().on("keydown" , this.fireKey, this);
43209 this.inputEl().on("focus", this.onFocus, this);
43210 this.inputEl().on("blur", this.onBlur, this);
43212 this.inputEl().relayEvent('keyup', this);
43214 if(this.indicator){
43215 this.indicator.addClass('invisible');
43218 this.originalValue = this.getValue();
43220 if(this.validationEvent == 'keyup'){
43221 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
43222 this.inputEl().on('keyup', this.filterValidation, this);
43224 else if(this.validationEvent !== false){
43225 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
43228 if(this.selectOnFocus){
43229 this.on("focus", this.preFocus, this);
43232 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
43233 this.inputEl().on("keypress", this.filterKeys, this);
43235 this.inputEl().relayEvent('keypress', this);
43238 var allowed = "0123456789";
43240 if(this.allowDecimals){
43241 allowed += this.decimalSeparator;
43244 if(this.allowNegative){
43248 if(this.thousandsDelimiter) {
43252 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
43254 var keyPress = function(e){
43256 var k = e.getKey();
43258 var c = e.getCharCode();
43261 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
43262 allowed.indexOf(String.fromCharCode(c)) === -1
43268 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
43272 if(allowed.indexOf(String.fromCharCode(c)) === -1){
43277 this.inputEl().on("keypress", keyPress, this);
43281 onTriggerClick : function(e)
43288 this.loadNext = false;
43290 if(this.isExpanded()){
43295 this.hasFocus = true;
43297 if(this.triggerAction == 'all') {
43298 this.doQuery(this.allQuery, true);
43302 this.doQuery(this.getRawValue());
43305 getCurrency : function()
43307 var v = this.currencyEl().getValue();
43312 restrictHeight : function()
43314 this.list.alignTo(this.currencyEl(), this.listAlign);
43315 this.list.alignTo(this.currencyEl(), this.listAlign);
43318 onViewClick : function(view, doFocus, el, e)
43320 var index = this.view.getSelectedIndexes()[0];
43322 var r = this.store.getAt(index);
43325 this.onSelect(r, index);
43329 onSelect : function(record, index){
43331 if(this.fireEvent('beforeselect', this, record, index) !== false){
43333 this.setFromCurrencyData(index > -1 ? record.data : false);
43337 this.fireEvent('select', this, record, index);
43341 setFromCurrencyData : function(o)
43345 this.lastCurrency = o;
43347 if (this.currencyField) {
43348 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
43350 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
43353 this.lastSelectionText = currency;
43355 //setting default currency
43356 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
43357 this.setCurrency(this.defaultCurrency);
43361 this.setCurrency(currency);
43364 setFromData : function(o)
43368 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
43370 this.setFromCurrencyData(c);
43375 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
43377 Roo.log('no value set for '+ (this.name ? this.name : this.id));
43380 this.setValue(value);
43384 setCurrency : function(v)
43386 this.currencyValue = v;
43389 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
43394 setValue : function(v)
43396 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
43402 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
43404 this.inputEl().dom.value = (v == '') ? '' :
43405 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
43407 if(!this.allowZero && v === '0') {
43408 this.hiddenEl().dom.value = '';
43409 this.inputEl().dom.value = '';
43416 getRawValue : function()
43418 var v = this.inputEl().getValue();
43423 getValue : function()
43425 return this.fixPrecision(this.parseValue(this.getRawValue()));
43428 parseValue : function(value)
43430 if(this.thousandsDelimiter) {
43432 r = new RegExp(",", "g");
43433 value = value.replace(r, "");
43436 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
43437 return isNaN(value) ? '' : value;
43441 fixPrecision : function(value)
43443 if(this.thousandsDelimiter) {
43445 r = new RegExp(",", "g");
43446 value = value.replace(r, "");
43449 var nan = isNaN(value);
43451 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
43452 return nan ? '' : value;
43454 return parseFloat(value).toFixed(this.decimalPrecision);
43457 decimalPrecisionFcn : function(v)
43459 return Math.floor(v);
43462 validateValue : function(value)
43464 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
43468 var num = this.parseValue(value);
43471 this.markInvalid(String.format(this.nanText, value));
43475 if(num < this.minValue){
43476 this.markInvalid(String.format(this.minText, this.minValue));
43480 if(num > this.maxValue){
43481 this.markInvalid(String.format(this.maxText, this.maxValue));
43488 validate : function()
43490 if(this.disabled || this.allowBlank){
43495 var currency = this.getCurrency();
43497 if(this.validateValue(this.getRawValue()) && currency.length){
43502 this.markInvalid();
43506 getName: function()
43511 beforeBlur : function()
43517 var v = this.parseValue(this.getRawValue());
43524 onBlur : function()
43528 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43529 //this.el.removeClass(this.focusClass);
43532 this.hasFocus = false;
43534 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
43538 var v = this.getValue();
43540 if(String(v) !== String(this.startValue)){
43541 this.fireEvent('change', this, v, this.startValue);
43544 this.fireEvent("blur", this);
43547 inputEl : function()
43549 return this.el.select('.roo-money-amount-input', true).first();
43552 currencyEl : function()
43554 return this.el.select('.roo-money-currency-input', true).first();
43557 hiddenEl : function()
43559 return this.el.select('input.hidden-number-input',true).first();
43563 * @class Roo.bootstrap.BezierSignature
43564 * @extends Roo.bootstrap.Component
43565 * Bootstrap BezierSignature class
43566 * This script refer to:
43567 * Title: Signature Pad
43569 * Availability: https://github.com/szimek/signature_pad
43572 * Create a new BezierSignature
43573 * @param {Object} config The config object
43576 Roo.bootstrap.BezierSignature = function(config){
43577 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
43583 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
43590 mouse_btn_down: true,
43593 * @cfg {int} canvas height
43595 canvas_height: '200px',
43598 * @cfg {float|function} Radius of a single dot.
43603 * @cfg {float} Minimum width of a line. Defaults to 0.5.
43608 * @cfg {float} Maximum width of a line. Defaults to 2.5.
43613 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
43618 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
43623 * @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.
43625 bg_color: 'rgba(0, 0, 0, 0)',
43628 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
43630 dot_color: 'black',
43633 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
43635 velocity_filter_weight: 0.7,
43638 * @cfg {function} Callback when stroke begin.
43643 * @cfg {function} Callback when stroke end.
43647 getAutoCreate : function()
43649 var cls = 'roo-signature column';
43652 cls += ' ' + this.cls;
43662 for(var i = 0; i < col_sizes.length; i++) {
43663 if(this[col_sizes[i]]) {
43664 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
43674 cls: 'roo-signature-body',
43678 cls: 'roo-signature-body-canvas',
43679 height: this.canvas_height,
43680 width: this.canvas_width
43687 style: 'display: none'
43695 initEvents: function()
43697 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
43699 var canvas = this.canvasEl();
43701 // mouse && touch event swapping...
43702 canvas.dom.style.touchAction = 'none';
43703 canvas.dom.style.msTouchAction = 'none';
43705 this.mouse_btn_down = false;
43706 canvas.on('mousedown', this._handleMouseDown, this);
43707 canvas.on('mousemove', this._handleMouseMove, this);
43708 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
43710 if (window.PointerEvent) {
43711 canvas.on('pointerdown', this._handleMouseDown, this);
43712 canvas.on('pointermove', this._handleMouseMove, this);
43713 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
43716 if ('ontouchstart' in window) {
43717 canvas.on('touchstart', this._handleTouchStart, this);
43718 canvas.on('touchmove', this._handleTouchMove, this);
43719 canvas.on('touchend', this._handleTouchEnd, this);
43722 Roo.EventManager.onWindowResize(this.resize, this, true);
43724 // file input event
43725 this.fileEl().on('change', this.uploadImage, this);
43732 resize: function(){
43734 var canvas = this.canvasEl().dom;
43735 var ctx = this.canvasElCtx();
43736 var img_data = false;
43738 if(canvas.width > 0) {
43739 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
43741 // setting canvas width will clean img data
43744 var style = window.getComputedStyle ?
43745 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
43747 var padding_left = parseInt(style.paddingLeft) || 0;
43748 var padding_right = parseInt(style.paddingRight) || 0;
43750 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
43753 ctx.putImageData(img_data, 0, 0);
43757 _handleMouseDown: function(e)
43759 if (e.browserEvent.which === 1) {
43760 this.mouse_btn_down = true;
43761 this.strokeBegin(e);
43765 _handleMouseMove: function (e)
43767 if (this.mouse_btn_down) {
43768 this.strokeMoveUpdate(e);
43772 _handleMouseUp: function (e)
43774 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
43775 this.mouse_btn_down = false;
43780 _handleTouchStart: function (e) {
43782 e.preventDefault();
43783 if (e.browserEvent.targetTouches.length === 1) {
43784 // var touch = e.browserEvent.changedTouches[0];
43785 // this.strokeBegin(touch);
43787 this.strokeBegin(e); // assume e catching the correct xy...
43791 _handleTouchMove: function (e) {
43792 e.preventDefault();
43793 // var touch = event.targetTouches[0];
43794 // _this._strokeMoveUpdate(touch);
43795 this.strokeMoveUpdate(e);
43798 _handleTouchEnd: function (e) {
43799 var wasCanvasTouched = e.target === this.canvasEl().dom;
43800 if (wasCanvasTouched) {
43801 e.preventDefault();
43802 // var touch = event.changedTouches[0];
43803 // _this._strokeEnd(touch);
43808 reset: function () {
43809 this._lastPoints = [];
43810 this._lastVelocity = 0;
43811 this._lastWidth = (this.min_width + this.max_width) / 2;
43812 this.canvasElCtx().fillStyle = this.dot_color;
43815 strokeMoveUpdate: function(e)
43817 this.strokeUpdate(e);
43819 if (this.throttle) {
43820 this.throttleStroke(this.strokeUpdate, this.throttle);
43823 this.strokeUpdate(e);
43827 strokeBegin: function(e)
43829 var newPointGroup = {
43830 color: this.dot_color,
43834 if (typeof this.onBegin === 'function') {
43838 this.curve_data.push(newPointGroup);
43840 this.strokeUpdate(e);
43843 strokeUpdate: function(e)
43845 var rect = this.canvasEl().dom.getBoundingClientRect();
43846 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
43847 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
43848 var lastPoints = lastPointGroup.points;
43849 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
43850 var isLastPointTooClose = lastPoint
43851 ? point.distanceTo(lastPoint) <= this.min_distance
43853 var color = lastPointGroup.color;
43854 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
43855 var curve = this.addPoint(point);
43857 this.drawDot({color: color, point: point});
43860 this.drawCurve({color: color, curve: curve});
43870 strokeEnd: function(e)
43872 this.strokeUpdate(e);
43873 if (typeof this.onEnd === 'function') {
43878 addPoint: function (point) {
43879 var _lastPoints = this._lastPoints;
43880 _lastPoints.push(point);
43881 if (_lastPoints.length > 2) {
43882 if (_lastPoints.length === 3) {
43883 _lastPoints.unshift(_lastPoints[0]);
43885 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
43886 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
43887 _lastPoints.shift();
43893 calculateCurveWidths: function (startPoint, endPoint) {
43894 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
43895 (1 - this.velocity_filter_weight) * this._lastVelocity;
43897 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
43900 start: this._lastWidth
43903 this._lastVelocity = velocity;
43904 this._lastWidth = newWidth;
43908 drawDot: function (_a) {
43909 var color = _a.color, point = _a.point;
43910 var ctx = this.canvasElCtx();
43911 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
43913 this.drawCurveSegment(point.x, point.y, width);
43915 ctx.fillStyle = color;
43919 drawCurve: function (_a) {
43920 var color = _a.color, curve = _a.curve;
43921 var ctx = this.canvasElCtx();
43922 var widthDelta = curve.endWidth - curve.startWidth;
43923 var drawSteps = Math.floor(curve.length()) * 2;
43925 ctx.fillStyle = color;
43926 for (var i = 0; i < drawSteps; i += 1) {
43927 var t = i / drawSteps;
43933 var x = uuu * curve.startPoint.x;
43934 x += 3 * uu * t * curve.control1.x;
43935 x += 3 * u * tt * curve.control2.x;
43936 x += ttt * curve.endPoint.x;
43937 var y = uuu * curve.startPoint.y;
43938 y += 3 * uu * t * curve.control1.y;
43939 y += 3 * u * tt * curve.control2.y;
43940 y += ttt * curve.endPoint.y;
43941 var width = curve.startWidth + ttt * widthDelta;
43942 this.drawCurveSegment(x, y, width);
43948 drawCurveSegment: function (x, y, width) {
43949 var ctx = this.canvasElCtx();
43951 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43952 this.is_empty = false;
43957 var ctx = this.canvasElCtx();
43958 var canvas = this.canvasEl().dom;
43959 ctx.fillStyle = this.bg_color;
43960 ctx.clearRect(0, 0, canvas.width, canvas.height);
43961 ctx.fillRect(0, 0, canvas.width, canvas.height);
43962 this.curve_data = [];
43964 this.is_empty = true;
43969 return this.el.select('input',true).first();
43972 canvasEl: function()
43974 return this.el.select('canvas',true).first();
43977 canvasElCtx: function()
43979 return this.el.select('canvas',true).first().dom.getContext('2d');
43982 getImage: function(type)
43984 if(this.is_empty) {
43989 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43992 drawFromImage: function(img_src)
43994 var img = new Image();
43996 img.onload = function(){
43997 this.canvasElCtx().drawImage(img, 0, 0);
44002 this.is_empty = false;
44005 selectImage: function()
44007 this.fileEl().dom.click();
44010 uploadImage: function(e)
44012 var reader = new FileReader();
44014 reader.onload = function(e){
44015 var img = new Image();
44016 img.onload = function(){
44018 this.canvasElCtx().drawImage(img, 0, 0);
44020 img.src = e.target.result;
44023 reader.readAsDataURL(e.target.files[0]);
44026 // Bezier Point Constructor
44027 Point: (function () {
44028 function Point(x, y, time) {
44031 this.time = time || Date.now();
44033 Point.prototype.distanceTo = function (start) {
44034 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
44036 Point.prototype.equals = function (other) {
44037 return this.x === other.x && this.y === other.y && this.time === other.time;
44039 Point.prototype.velocityFrom = function (start) {
44040 return this.time !== start.time
44041 ? this.distanceTo(start) / (this.time - start.time)
44048 // Bezier Constructor
44049 Bezier: (function () {
44050 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
44051 this.startPoint = startPoint;
44052 this.control2 = control2;
44053 this.control1 = control1;
44054 this.endPoint = endPoint;
44055 this.startWidth = startWidth;
44056 this.endWidth = endWidth;
44058 Bezier.fromPoints = function (points, widths, scope) {
44059 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
44060 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
44061 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
44063 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
44064 var dx1 = s1.x - s2.x;
44065 var dy1 = s1.y - s2.y;
44066 var dx2 = s2.x - s3.x;
44067 var dy2 = s2.y - s3.y;
44068 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
44069 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
44070 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
44071 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
44072 var dxm = m1.x - m2.x;
44073 var dym = m1.y - m2.y;
44074 var k = l2 / (l1 + l2);
44075 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
44076 var tx = s2.x - cm.x;
44077 var ty = s2.y - cm.y;
44079 c1: new scope.Point(m1.x + tx, m1.y + ty),
44080 c2: new scope.Point(m2.x + tx, m2.y + ty)
44083 Bezier.prototype.length = function () {
44088 for (var i = 0; i <= steps; i += 1) {
44090 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
44091 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
44093 var xdiff = cx - px;
44094 var ydiff = cy - py;
44095 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
44102 Bezier.prototype.point = function (t, start, c1, c2, end) {
44103 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
44104 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
44105 + (3.0 * c2 * (1.0 - t) * t * t)
44106 + (end * t * t * t);
44111 throttleStroke: function(fn, wait) {
44112 if (wait === void 0) { wait = 250; }
44114 var timeout = null;
44118 var later = function () {
44119 previous = Date.now();
44121 result = fn.apply(storedContext, storedArgs);
44123 storedContext = null;
44127 return function wrapper() {
44129 for (var _i = 0; _i < arguments.length; _i++) {
44130 args[_i] = arguments[_i];
44132 var now = Date.now();
44133 var remaining = wait - (now - previous);
44134 storedContext = this;
44136 if (remaining <= 0 || remaining > wait) {
44138 clearTimeout(timeout);
44142 result = fn.apply(storedContext, storedArgs);
44144 storedContext = null;
44148 else if (!timeout) {
44149 timeout = window.setTimeout(later, remaining);