4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
14 * @class Roo.ComponentMgr
15 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
18 Roo.ComponentMgr = function(){
19 var all = new Roo.util.MixedCollection();
23 * Registers a component.
24 * @param {Roo.Component} c The component
26 register : function(c){
31 * Unregisters a component.
32 * @param {Roo.Component} c The component
34 unregister : function(c){
39 * Returns a component by id
40 * @param {String} id The component id
47 * Registers a function that will be called when a specified component is added to ComponentMgr
48 * @param {String} id The component id
49 * @param {Funtction} fn The callback function
50 * @param {Object} scope The scope of the callback
52 onAvailable : function(id, fn, scope){
53 all.on("add", function(index, o){
55 fn.call(scope || o, o);
56 all.un("add", fn, scope);
63 * Ext JS Library 1.1.1
64 * Copyright(c) 2006-2007, Ext JS, LLC.
66 * Originally Released Under LGPL - original licence link has changed is not relivant.
69 * <script type="text/javascript">
73 * @class Roo.Component
74 * @extends Roo.util.Observable
75 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
76 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
77 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
78 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
79 * All visual components (widgets) that require rendering into a layout should subclass Component.
81 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
82 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
83 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
85 Roo.Component = function(config){
86 config = config || {};
87 if(config.tagName || config.dom || typeof config == "string"){ // element object
88 config = {el: config, id: config.id || config};
90 this.initialConfig = config;
92 Roo.apply(this, config);
96 * Fires after the component is disabled.
97 * @param {Roo.Component} this
102 * Fires after the component is enabled.
103 * @param {Roo.Component} this
108 * Fires before the component is shown. Return false to stop the show.
109 * @param {Roo.Component} this
114 * Fires after the component is shown.
115 * @param {Roo.Component} this
120 * Fires before the component is hidden. Return false to stop the hide.
121 * @param {Roo.Component} this
126 * Fires after the component is hidden.
127 * @param {Roo.Component} this
131 * @event beforerender
132 * Fires before the component is rendered. Return false to stop the render.
133 * @param {Roo.Component} this
138 * Fires after the component is rendered.
139 * @param {Roo.Component} this
143 * @event beforedestroy
144 * Fires before the component is destroyed. Return false to stop the destroy.
145 * @param {Roo.Component} this
147 beforedestroy : true,
150 * Fires after the component is destroyed.
151 * @param {Roo.Component} this
156 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
158 Roo.ComponentMgr.register(this);
159 Roo.Component.superclass.constructor.call(this);
160 this.initComponent();
161 if(this.renderTo){ // not supported by all components yet. use at your own risk!
162 this.render(this.renderTo);
163 delete this.renderTo;
168 Roo.Component.AUTO_ID = 1000;
170 Roo.extend(Roo.Component, Roo.util.Observable, {
172 * @property {Boolean} hidden
173 * true if this component is hidden. Read-only.
177 * true if this component is disabled. Read-only.
181 * true if this component has been rendered. Read-only.
185 /** @cfg {String} disableClass
186 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
188 disabledClass : "x-item-disabled",
189 /** @cfg {Boolean} allowDomMove
190 * Whether the component can move the Dom node when rendering (defaults to true).
193 /** @cfg {String} hideMode
194 * How this component should hidden. Supported values are
195 * "visibility" (css visibility), "offsets" (negative offset position) and
196 * "display" (css display) - defaults to "display".
201 ctype : "Roo.Component",
203 /** @cfg {String} actionMode
204 * which property holds the element that used for hide() / show() / disable() / enable()
210 getActionEl : function(){
211 return this[this.actionMode];
214 initComponent : Roo.emptyFn,
216 * If this is a lazy rendering component, render it to its container element.
217 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
219 render : function(container, position){
220 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
221 if(!container && this.el){
222 this.el = Roo.get(this.el);
223 container = this.el.dom.parentNode;
224 this.allowDomMove = false;
226 this.container = Roo.get(container);
227 this.rendered = true;
228 if(position !== undefined){
229 if(typeof position == 'number'){
230 position = this.container.dom.childNodes[position];
232 position = Roo.getDom(position);
235 this.onRender(this.container, position || null);
237 this.el.addClass(this.cls);
241 this.el.applyStyles(this.style);
244 this.fireEvent("render", this);
245 this.afterRender(this.container);
257 // default function is not really useful
258 onRender : function(ct, position){
260 this.el = Roo.get(this.el);
261 if(this.allowDomMove !== false){
262 ct.dom.insertBefore(this.el.dom, position);
268 getAutoCreate : function(){
269 var cfg = typeof this.autoCreate == "object" ?
270 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
271 if(this.id && !cfg.id){
278 afterRender : Roo.emptyFn,
281 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
282 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
284 destroy : function(){
285 if(this.fireEvent("beforedestroy", this) !== false){
286 this.purgeListeners();
287 this.beforeDestroy();
289 this.el.removeAllListeners();
291 if(this.actionMode == "container"){
292 this.container.remove();
296 Roo.ComponentMgr.unregister(this);
297 this.fireEvent("destroy", this);
302 beforeDestroy : function(){
307 onDestroy : function(){
312 * Returns the underlying {@link Roo.Element}.
313 * @return {Roo.Element} The element
320 * Returns the id of this component.
328 * Try to focus this component.
329 * @param {Boolean} selectText True to also select the text in this component (if applicable)
330 * @return {Roo.Component} this
332 focus : function(selectText){
335 if(selectText === true){
336 this.el.dom.select();
351 * Disable this component.
352 * @return {Roo.Component} this
354 disable : function(){
358 this.disabled = true;
359 this.fireEvent("disable", this);
364 onDisable : function(){
365 this.getActionEl().addClass(this.disabledClass);
366 this.el.dom.disabled = true;
370 * Enable this component.
371 * @return {Roo.Component} this
377 this.disabled = false;
378 this.fireEvent("enable", this);
383 onEnable : function(){
384 this.getActionEl().removeClass(this.disabledClass);
385 this.el.dom.disabled = false;
389 * Convenience function for setting disabled/enabled by boolean.
390 * @param {Boolean} disabled
392 setDisabled : function(disabled){
393 this[disabled ? "disable" : "enable"]();
397 * Show this component.
398 * @return {Roo.Component} this
401 if(this.fireEvent("beforeshow", this) !== false){
406 this.fireEvent("show", this);
413 var ae = this.getActionEl();
414 if(this.hideMode == 'visibility'){
415 ae.dom.style.visibility = "visible";
416 }else if(this.hideMode == 'offsets'){
417 ae.removeClass('x-hidden');
419 ae.dom.style.display = "";
424 * Hide this component.
425 * @return {Roo.Component} this
428 if(this.fireEvent("beforehide", this) !== false){
433 this.fireEvent("hide", this);
440 var ae = this.getActionEl();
441 if(this.hideMode == 'visibility'){
442 ae.dom.style.visibility = "hidden";
443 }else if(this.hideMode == 'offsets'){
444 ae.addClass('x-hidden');
446 ae.dom.style.display = "none";
451 * Convenience function to hide or show this component by boolean.
452 * @param {Boolean} visible True to show, false to hide
453 * @return {Roo.Component} this
455 setVisible: function(visible){
465 * Returns true if this component is visible.
467 isVisible : function(){
468 return this.getActionEl().isVisible();
471 cloneConfig : function(overrides){
472 overrides = overrides || {};
473 var id = overrides.id || Roo.id();
474 var cfg = Roo.applyIf(overrides, this.initialConfig);
475 cfg.id = id; // prevent dup id
476 return new this.constructor(cfg);
480 * Ext JS Library 1.1.1
481 * Copyright(c) 2006-2007, Ext JS, LLC.
483 * Originally Released Under LGPL - original licence link has changed is not relivant.
486 * <script type="text/javascript">
491 * @extends Roo.Element
492 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
493 * automatic maintaining of shadow/shim positions.
494 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
495 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
496 * you can pass a string with a CSS class name. False turns off the shadow.
497 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
498 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
499 * @cfg {String} cls CSS class to add to the element
500 * @cfg {Number} zindex Starting z-index (defaults to 11000)
501 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
503 * @param {Object} config An object with config options.
504 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
507 Roo.Layer = function(config, existingEl){
508 config = config || {};
509 var dh = Roo.DomHelper;
510 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
512 this.dom = Roo.getDom(existingEl);
515 var o = config.dh || {tag: "div", cls: "x-layer"};
516 this.dom = dh.append(pel, o);
519 this.addClass(config.cls);
521 this.constrain = config.constrain !== false;
522 this.visibilityMode = Roo.Element.VISIBILITY;
524 this.id = this.dom.id = config.id;
526 this.id = Roo.id(this.dom);
528 this.zindex = config.zindex || this.getZIndex();
529 this.position("absolute", this.zindex);
531 this.shadowOffset = config.shadowOffset || 4;
532 this.shadow = new Roo.Shadow({
533 offset : this.shadowOffset,
537 this.shadowOffset = 0;
539 this.useShim = config.shim !== false && Roo.useShims;
540 this.useDisplay = config.useDisplay;
544 var supr = Roo.Element.prototype;
546 // shims are shared among layer to keep from having 100 iframes
549 Roo.extend(Roo.Layer, Roo.Element, {
551 getZIndex : function(){
552 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
555 getShim : function(){
562 var shim = shims.shift();
564 shim = this.createShim();
565 shim.enableDisplayMode('block');
566 shim.dom.style.display = 'none';
567 shim.dom.style.visibility = 'visible';
569 var pn = this.dom.parentNode;
570 if(shim.dom.parentNode != pn){
571 pn.insertBefore(shim.dom, this.dom);
573 shim.setStyle('z-index', this.getZIndex()-2);
578 hideShim : function(){
580 this.shim.setDisplayed(false);
581 shims.push(this.shim);
586 disableShadow : function(){
588 this.shadowDisabled = true;
590 this.lastShadowOffset = this.shadowOffset;
591 this.shadowOffset = 0;
595 enableShadow : function(show){
597 this.shadowDisabled = false;
598 this.shadowOffset = this.lastShadowOffset;
599 delete this.lastShadowOffset;
607 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
608 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
609 sync : function(doShow){
610 var sw = this.shadow;
611 if(!this.updating && this.isVisible() && (sw || this.useShim)){
612 var sh = this.getShim();
614 var w = this.getWidth(),
615 h = this.getHeight();
617 var l = this.getLeft(true),
618 t = this.getTop(true);
620 if(sw && !this.shadowDisabled){
621 if(doShow && !sw.isVisible()){
624 sw.realign(l, t, w, h);
630 // fit the shim behind the shadow, so it is shimmed too
631 var a = sw.adjusts, s = sh.dom.style;
632 s.left = (Math.min(l, l+a.l))+"px";
633 s.top = (Math.min(t, t+a.t))+"px";
634 s.width = (w+a.w)+"px";
635 s.height = (h+a.h)+"px";
649 destroy : function(){
654 this.removeAllListeners();
655 var pn = this.dom.parentNode;
657 pn.removeChild(this.dom);
659 Roo.Element.uncache(this.id);
667 beginUpdate : function(){
668 this.updating = true;
672 endUpdate : function(){
673 this.updating = false;
678 hideUnders : function(negOffset){
686 constrainXY : function(){
688 var vw = Roo.lib.Dom.getViewWidth(),
689 vh = Roo.lib.Dom.getViewHeight();
690 var s = Roo.get(document).getScroll();
692 var xy = this.getXY();
693 var x = xy[0], y = xy[1];
694 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
695 // only move it if it needs it
697 // first validate right/bottom
698 if((x + w) > vw+s.left){
699 x = vw - w - this.shadowOffset;
702 if((y + h) > vh+s.top){
703 y = vh - h - this.shadowOffset;
706 // then make sure top/left isn't negative
717 var ay = this.avoidY;
718 if(y <= ay && (y+h) >= ay){
724 supr.setXY.call(this, xy);
730 isVisible : function(){
735 showAction : function(){
736 this.visible = true; // track visibility to prevent getStyle calls
737 if(this.useDisplay === true){
738 this.setDisplayed("");
739 }else if(this.lastXY){
740 supr.setXY.call(this, this.lastXY);
741 }else if(this.lastLT){
742 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
747 hideAction : function(){
748 this.visible = false;
749 if(this.useDisplay === true){
750 this.setDisplayed(false);
752 this.setLeftTop(-10000,-10000);
756 // overridden Element method
757 setVisible : function(v, a, d, c, e){
767 }.createDelegate(this);
768 supr.setVisible.call(this, true, true, d, cb, e);
771 this.hideUnders(true);
780 }.createDelegate(this);
782 supr.setVisible.call(this, v, a, d, cb, e);
791 storeXY : function(xy){
796 storeLeftTop : function(left, top){
798 this.lastLT = [left, top];
802 beforeFx : function(){
804 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
808 afterFx : function(){
809 Roo.Layer.superclass.afterFx.apply(this, arguments);
810 this.sync(this.isVisible());
814 beforeAction : function(){
815 if(!this.updating && this.shadow){
820 // overridden Element method
821 setLeft : function(left){
822 this.storeLeftTop(left, this.getTop(true));
823 supr.setLeft.apply(this, arguments);
827 setTop : function(top){
828 this.storeLeftTop(this.getLeft(true), top);
829 supr.setTop.apply(this, arguments);
833 setLeftTop : function(left, top){
834 this.storeLeftTop(left, top);
835 supr.setLeftTop.apply(this, arguments);
839 setXY : function(xy, a, d, c, e){
843 var cb = this.createCB(c);
844 supr.setXY.call(this, xy, a, d, cb, e);
851 createCB : function(c){
862 // overridden Element method
863 setX : function(x, a, d, c, e){
864 this.setXY([x, this.getY()], a, d, c, e);
867 // overridden Element method
868 setY : function(y, a, d, c, e){
869 this.setXY([this.getX(), y], a, d, c, e);
872 // overridden Element method
873 setSize : function(w, h, a, d, c, e){
875 var cb = this.createCB(c);
876 supr.setSize.call(this, w, h, a, d, cb, e);
882 // overridden Element method
883 setWidth : function(w, a, d, c, e){
885 var cb = this.createCB(c);
886 supr.setWidth.call(this, w, a, d, cb, e);
892 // overridden Element method
893 setHeight : function(h, a, d, c, e){
895 var cb = this.createCB(c);
896 supr.setHeight.call(this, h, a, d, cb, e);
902 // overridden Element method
903 setBounds : function(x, y, w, h, a, d, c, e){
905 var cb = this.createCB(c);
907 this.storeXY([x, y]);
908 supr.setXY.call(this, [x, y]);
909 supr.setSize.call(this, w, h, a, d, cb, e);
912 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
918 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
919 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
920 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
921 * @param {Number} zindex The new z-index to set
922 * @return {this} The Layer
924 setZIndex : function(zindex){
925 this.zindex = zindex;
926 this.setStyle("z-index", zindex + 2);
928 this.shadow.setZIndex(zindex + 1);
931 this.shim.setStyle("z-index", zindex);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
950 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
951 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
953 * Create a new Shadow
954 * @param {Object} config The config object
956 Roo.Shadow = function(config){
957 Roo.apply(this, config);
958 if(typeof this.mode != "string"){
959 this.mode = this.defaultMode;
961 var o = this.offset, a = {h: 0};
962 var rad = Math.floor(this.offset/2);
963 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
969 a.l -= this.offset + rad;
970 a.t -= this.offset + rad;
981 a.l -= (this.offset - rad);
982 a.t -= this.offset + rad;
984 a.w -= (this.offset - rad)*2;
995 a.l -= (this.offset - rad);
996 a.t -= (this.offset - rad);
998 a.w -= (this.offset + rad + 1);
999 a.h -= (this.offset + rad);
1008 Roo.Shadow.prototype = {
1010 * @cfg {String} mode
1011 * The shadow display mode. Supports the following options:<br />
1012 * sides: Shadow displays on both sides and bottom only<br />
1013 * frame: Shadow displays equally on all four sides<br />
1014 * drop: Traditional bottom-right drop shadow (default)
1017 * @cfg {String} offset
1018 * The number of pixels to offset the shadow from the element (defaults to 4)
1023 defaultMode: "drop",
1026 * Displays the shadow under the target element
1027 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
1029 show : function(target){
1030 target = Roo.get(target);
1032 this.el = Roo.Shadow.Pool.pull();
1033 if(this.el.dom.nextSibling != target.dom){
1034 this.el.insertBefore(target);
1037 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
1039 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
1042 target.getLeft(true),
1043 target.getTop(true),
1047 this.el.dom.style.display = "block";
1051 * Returns true if the shadow is visible, else false
1053 isVisible : function(){
1054 return this.el ? true : false;
1058 * Direct alignment when values are already available. Show must be called at least once before
1059 * calling this method to ensure it is initialized.
1060 * @param {Number} left The target element left position
1061 * @param {Number} top The target element top position
1062 * @param {Number} width The target element width
1063 * @param {Number} height The target element height
1065 realign : function(l, t, w, h){
1069 var a = this.adjusts, d = this.el.dom, s = d.style;
1071 s.left = (l+a.l)+"px";
1072 s.top = (t+a.t)+"px";
1073 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
1074 if(s.width != sws || s.height != shs){
1078 var cn = d.childNodes;
1079 var sww = Math.max(0, (sw-12))+"px";
1080 cn[0].childNodes[1].style.width = sww;
1081 cn[1].childNodes[1].style.width = sww;
1082 cn[2].childNodes[1].style.width = sww;
1083 cn[1].style.height = Math.max(0, (sh-12))+"px";
1093 this.el.dom.style.display = "none";
1094 Roo.Shadow.Pool.push(this.el);
1100 * Adjust the z-index of this shadow
1101 * @param {Number} zindex The new z-index
1103 setZIndex : function(z){
1106 this.el.setStyle("z-index", z);
1111 // Private utility class that manages the internal Shadow cache
1112 Roo.Shadow.Pool = function(){
1114 var markup = Roo.isIE ?
1115 '<div class="x-ie-shadow"></div>' :
1116 '<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>';
1121 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
1122 sh.autoBoxAdjust = false;
1127 push : function(sh){
1133 * Ext JS Library 1.1.1
1134 * Copyright(c) 2006-2007, Ext JS, LLC.
1136 * Originally Released Under LGPL - original licence link has changed is not relivant.
1139 * <script type="text/javascript">
1143 * @class Roo.BoxComponent
1144 * @extends Roo.Component
1145 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
1146 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
1147 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
1148 * layout containers.
1150 * @param {Roo.Element/String/Object} config The configuration options.
1152 Roo.BoxComponent = function(config){
1153 Roo.Component.call(this, config);
1157 * Fires after the component is resized.
1158 * @param {Roo.Component} this
1159 * @param {Number} adjWidth The box-adjusted width that was set
1160 * @param {Number} adjHeight The box-adjusted height that was set
1161 * @param {Number} rawWidth The width that was originally specified
1162 * @param {Number} rawHeight The height that was originally specified
1167 * Fires after the component is moved.
1168 * @param {Roo.Component} this
1169 * @param {Number} x The new x position
1170 * @param {Number} y The new y position
1176 Roo.extend(Roo.BoxComponent, Roo.Component, {
1177 // private, set in afterRender to signify that the component has been rendered
1179 // private, used to defer height settings to subclasses
1181 /** @cfg {Number} width
1182 * width (optional) size of component
1184 /** @cfg {Number} height
1185 * height (optional) size of component
1189 * Sets the width and height of the component. This method fires the resize event. This method can accept
1190 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
1191 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
1192 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
1193 * @return {Roo.BoxComponent} this
1195 setSize : function(w, h){
1196 // support for standard size objects
1197 if(typeof w == 'object'){
1208 // prevent recalcs when not needed
1209 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
1212 this.lastSize = {width: w, height: h};
1214 var adj = this.adjustSize(w, h);
1215 var aw = adj.width, ah = adj.height;
1216 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
1217 var rz = this.getResizeEl();
1218 if(!this.deferHeight && aw !== undefined && ah !== undefined){
1220 }else if(!this.deferHeight && ah !== undefined){
1222 }else if(aw !== undefined){
1225 this.onResize(aw, ah, w, h);
1226 this.fireEvent('resize', this, aw, ah, w, h);
1232 * Gets the current size of the component's underlying element.
1233 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
1235 getSize : function(){
1236 return this.el.getSize();
1240 * Gets the current XY position of the component's underlying element.
1241 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
1242 * @return {Array} The XY position of the element (e.g., [100, 200])
1244 getPosition : function(local){
1246 return [this.el.getLeft(true), this.el.getTop(true)];
1248 return this.xy || this.el.getXY();
1252 * Gets the current box measurements of the component's underlying element.
1253 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
1254 * @returns {Object} box An object in the format {x, y, width, height}
1256 getBox : function(local){
1257 var s = this.el.getSize();
1259 s.x = this.el.getLeft(true);
1260 s.y = this.el.getTop(true);
1262 var xy = this.xy || this.el.getXY();
1270 * Sets the current box measurements of the component's underlying element.
1271 * @param {Object} box An object in the format {x, y, width, height}
1272 * @returns {Roo.BoxComponent} this
1274 updateBox : function(box){
1275 this.setSize(box.width, box.height);
1276 this.setPagePosition(box.x, box.y);
1281 getResizeEl : function(){
1282 return this.resizeEl || this.el;
1286 getPositionEl : function(){
1287 return this.positionEl || this.el;
1291 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
1292 * This method fires the move event.
1293 * @param {Number} left The new left
1294 * @param {Number} top The new top
1295 * @returns {Roo.BoxComponent} this
1297 setPosition : function(x, y){
1303 var adj = this.adjustPosition(x, y);
1304 var ax = adj.x, ay = adj.y;
1306 var el = this.getPositionEl();
1307 if(ax !== undefined || ay !== undefined){
1308 if(ax !== undefined && ay !== undefined){
1309 el.setLeftTop(ax, ay);
1310 }else if(ax !== undefined){
1312 }else if(ay !== undefined){
1315 this.onPosition(ax, ay);
1316 this.fireEvent('move', this, ax, ay);
1322 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
1323 * This method fires the move event.
1324 * @param {Number} x The new x position
1325 * @param {Number} y The new y position
1326 * @returns {Roo.BoxComponent} this
1328 setPagePosition : function(x, y){
1334 if(x === undefined || y === undefined){ // cannot translate undefined points
1337 var p = this.el.translatePoints(x, y);
1338 this.setPosition(p.left, p.top);
1343 onRender : function(ct, position){
1344 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
1346 this.resizeEl = Roo.get(this.resizeEl);
1348 if(this.positionEl){
1349 this.positionEl = Roo.get(this.positionEl);
1354 afterRender : function(){
1355 Roo.BoxComponent.superclass.afterRender.call(this);
1356 this.boxReady = true;
1357 this.setSize(this.width, this.height);
1358 if(this.x || this.y){
1359 this.setPosition(this.x, this.y);
1361 if(this.pageX || this.pageY){
1362 this.setPagePosition(this.pageX, this.pageY);
1367 * Force the component's size to recalculate based on the underlying element's current height and width.
1368 * @returns {Roo.BoxComponent} this
1370 syncSize : function(){
1371 delete this.lastSize;
1372 this.setSize(this.el.getWidth(), this.el.getHeight());
1377 * Called after the component is resized, this method is empty by default but can be implemented by any
1378 * subclass that needs to perform custom logic after a resize occurs.
1379 * @param {Number} adjWidth The box-adjusted width that was set
1380 * @param {Number} adjHeight The box-adjusted height that was set
1381 * @param {Number} rawWidth The width that was originally specified
1382 * @param {Number} rawHeight The height that was originally specified
1384 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
1389 * Called after the component is moved, this method is empty by default but can be implemented by any
1390 * subclass that needs to perform custom logic after a move occurs.
1391 * @param {Number} x The new x position
1392 * @param {Number} y The new y position
1394 onPosition : function(x, y){
1399 adjustSize : function(w, h){
1403 if(this.autoHeight){
1406 return {width : w, height: h};
1410 adjustPosition : function(x, y){
1411 return {x : x, y: y};
1415 * Ext JS Library 1.1.1
1416 * Copyright(c) 2006-2007, Ext JS, LLC.
1418 * Originally Released Under LGPL - original licence link has changed is not relivant.
1421 * <script type="text/javascript">
1426 * @class Roo.SplitBar
1427 * @extends Roo.util.Observable
1428 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
1432 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
1433 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
1434 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
1435 split.minSize = 100;
1436 split.maxSize = 600;
1437 split.animate = true;
1438 split.on('moved', splitterMoved);
1441 * Create a new SplitBar
1442 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
1443 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
1444 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
1445 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
1446 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
1447 position of the SplitBar).
1449 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
1452 this.el = Roo.get(dragElement, true);
1453 this.el.dom.unselectable = "on";
1455 this.resizingEl = Roo.get(resizingElement, true);
1459 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
1460 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
1463 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
1466 * The minimum size of the resizing element. (Defaults to 0)
1472 * The maximum size of the resizing element. (Defaults to 2000)
1475 this.maxSize = 2000;
1478 * Whether to animate the transition to the new size
1481 this.animate = false;
1484 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
1487 this.useShim = false;
1494 this.proxy = Roo.SplitBar.createProxy(this.orientation);
1496 this.proxy = Roo.get(existingProxy).dom;
1499 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
1502 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
1505 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
1508 this.dragSpecs = {};
1511 * @private The adapter to use to positon and resize elements
1513 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
1514 this.adapter.init(this);
1516 if(this.orientation == Roo.SplitBar.HORIZONTAL){
1518 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
1519 this.el.addClass("x-splitbar-h");
1522 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
1523 this.el.addClass("x-splitbar-v");
1529 * Fires when the splitter is moved (alias for {@link #event-moved})
1530 * @param {Roo.SplitBar} this
1531 * @param {Number} newSize the new width or height
1536 * Fires when the splitter is moved
1537 * @param {Roo.SplitBar} this
1538 * @param {Number} newSize the new width or height
1542 * @event beforeresize
1543 * Fires before the splitter is dragged
1544 * @param {Roo.SplitBar} this
1546 "beforeresize" : true,
1548 "beforeapply" : true
1551 Roo.util.Observable.call(this);
1554 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
1555 onStartProxyDrag : function(x, y){
1556 this.fireEvent("beforeresize", this);
1558 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
1560 o.enableDisplayMode("block");
1561 // all splitbars share the same overlay
1562 Roo.SplitBar.prototype.overlay = o;
1564 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1565 this.overlay.show();
1566 Roo.get(this.proxy).setDisplayed("block");
1567 var size = this.adapter.getElementSize(this);
1568 this.activeMinSize = this.getMinimumSize();;
1569 this.activeMaxSize = this.getMaximumSize();;
1570 var c1 = size - this.activeMinSize;
1571 var c2 = Math.max(this.activeMaxSize - size, 0);
1572 if(this.orientation == Roo.SplitBar.HORIZONTAL){
1573 this.dd.resetConstraints();
1574 this.dd.setXConstraint(
1575 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
1576 this.placement == Roo.SplitBar.LEFT ? c2 : c1
1578 this.dd.setYConstraint(0, 0);
1580 this.dd.resetConstraints();
1581 this.dd.setXConstraint(0, 0);
1582 this.dd.setYConstraint(
1583 this.placement == Roo.SplitBar.TOP ? c1 : c2,
1584 this.placement == Roo.SplitBar.TOP ? c2 : c1
1587 this.dragSpecs.startSize = size;
1588 this.dragSpecs.startPoint = [x, y];
1589 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
1593 * @private Called after the drag operation by the DDProxy
1595 onEndProxyDrag : function(e){
1596 Roo.get(this.proxy).setDisplayed(false);
1597 var endPoint = Roo.lib.Event.getXY(e);
1599 this.overlay.hide();
1602 if(this.orientation == Roo.SplitBar.HORIZONTAL){
1603 newSize = this.dragSpecs.startSize +
1604 (this.placement == Roo.SplitBar.LEFT ?
1605 endPoint[0] - this.dragSpecs.startPoint[0] :
1606 this.dragSpecs.startPoint[0] - endPoint[0]
1609 newSize = this.dragSpecs.startSize +
1610 (this.placement == Roo.SplitBar.TOP ?
1611 endPoint[1] - this.dragSpecs.startPoint[1] :
1612 this.dragSpecs.startPoint[1] - endPoint[1]
1615 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
1616 if(newSize != this.dragSpecs.startSize){
1617 if(this.fireEvent('beforeapply', this, newSize) !== false){
1618 this.adapter.setElementSize(this, newSize);
1619 this.fireEvent("moved", this, newSize);
1620 this.fireEvent("resize", this, newSize);
1626 * Get the adapter this SplitBar uses
1627 * @return The adapter object
1629 getAdapter : function(){
1630 return this.adapter;
1634 * Set the adapter this SplitBar uses
1635 * @param {Object} adapter A SplitBar adapter object
1637 setAdapter : function(adapter){
1638 this.adapter = adapter;
1639 this.adapter.init(this);
1643 * Gets the minimum size for the resizing element
1644 * @return {Number} The minimum size
1646 getMinimumSize : function(){
1647 return this.minSize;
1651 * Sets the minimum size for the resizing element
1652 * @param {Number} minSize The minimum size
1654 setMinimumSize : function(minSize){
1655 this.minSize = minSize;
1659 * Gets the maximum size for the resizing element
1660 * @return {Number} The maximum size
1662 getMaximumSize : function(){
1663 return this.maxSize;
1667 * Sets the maximum size for the resizing element
1668 * @param {Number} maxSize The maximum size
1670 setMaximumSize : function(maxSize){
1671 this.maxSize = maxSize;
1675 * Sets the initialize size for the resizing element
1676 * @param {Number} size The initial size
1678 setCurrentSize : function(size){
1679 var oldAnimate = this.animate;
1680 this.animate = false;
1681 this.adapter.setElementSize(this, size);
1682 this.animate = oldAnimate;
1686 * Destroy this splitbar.
1687 * @param {Boolean} removeEl True to remove the element
1689 destroy : function(removeEl){
1694 this.proxy.parentNode.removeChild(this.proxy);
1702 * @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.
1704 Roo.SplitBar.createProxy = function(dir){
1705 var proxy = new Roo.Element(document.createElement("div"));
1706 proxy.unselectable();
1707 var cls = 'x-splitbar-proxy';
1708 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
1709 document.body.appendChild(proxy.dom);
1714 * @class Roo.SplitBar.BasicLayoutAdapter
1715 * Default Adapter. It assumes the splitter and resizing element are not positioned
1716 * elements and only gets/sets the width of the element. Generally used for table based layouts.
1718 Roo.SplitBar.BasicLayoutAdapter = function(){
1721 Roo.SplitBar.BasicLayoutAdapter.prototype = {
1722 // do nothing for now
1727 * Called before drag operations to get the current size of the resizing element.
1728 * @param {Roo.SplitBar} s The SplitBar using this adapter
1730 getElementSize : function(s){
1731 if(s.orientation == Roo.SplitBar.HORIZONTAL){
1732 return s.resizingEl.getWidth();
1734 return s.resizingEl.getHeight();
1739 * Called after drag operations to set the size of the resizing element.
1740 * @param {Roo.SplitBar} s The SplitBar using this adapter
1741 * @param {Number} newSize The new size to set
1742 * @param {Function} onComplete A function to be invoked when resizing is complete
1744 setElementSize : function(s, newSize, onComplete){
1745 if(s.orientation == Roo.SplitBar.HORIZONTAL){
1747 s.resizingEl.setWidth(newSize);
1749 onComplete(s, newSize);
1752 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
1757 s.resizingEl.setHeight(newSize);
1759 onComplete(s, newSize);
1762 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
1769 *@class Roo.SplitBar.AbsoluteLayoutAdapter
1770 * @extends Roo.SplitBar.BasicLayoutAdapter
1771 * Adapter that moves the splitter element to align with the resized sizing element.
1772 * Used with an absolute positioned SplitBar.
1773 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
1774 * document.body, make sure you assign an id to the body element.
1776 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
1777 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
1778 this.container = Roo.get(container);
1781 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
1786 getElementSize : function(s){
1787 return this.basic.getElementSize(s);
1790 setElementSize : function(s, newSize, onComplete){
1791 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
1794 moveSplitter : function(s){
1795 var yes = Roo.SplitBar;
1796 switch(s.placement){
1798 s.el.setX(s.resizingEl.getRight());
1801 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
1804 s.el.setY(s.resizingEl.getBottom());
1807 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
1814 * Orientation constant - Create a vertical SplitBar
1818 Roo.SplitBar.VERTICAL = 1;
1821 * Orientation constant - Create a horizontal SplitBar
1825 Roo.SplitBar.HORIZONTAL = 2;
1828 * Placement constant - The resizing element is to the left of the splitter element
1832 Roo.SplitBar.LEFT = 1;
1835 * Placement constant - The resizing element is to the right of the splitter element
1839 Roo.SplitBar.RIGHT = 2;
1842 * Placement constant - The resizing element is positioned above the splitter element
1846 Roo.SplitBar.TOP = 3;
1849 * Placement constant - The resizing element is positioned under splitter element
1853 Roo.SplitBar.BOTTOM = 4;
1856 * Ext JS Library 1.1.1
1857 * Copyright(c) 2006-2007, Ext JS, LLC.
1859 * Originally Released Under LGPL - original licence link has changed is not relivant.
1862 * <script type="text/javascript">
1867 * @extends Roo.util.Observable
1868 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
1869 * This class also supports single and multi selection modes. <br>
1870 * Create a data model bound view:
1872 var store = new Roo.data.Store(...);
1874 var view = new Roo.View("my-element",
1875 '<div id="{0}">{2} - {1}</div>', // auto create template
1878 selectedClass: "ydataview-selected",
1882 // listen for node click?
1883 view.on("click", function(vw, index, node, e){
1884 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
1888 dataModel.load("foobar.xml");
1890 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
1892 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
1893 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
1896 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
1897 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
1898 * @param {Object} config The config object
1900 Roo.View = function(container, tpl, config){
1901 this.el = Roo.get(container);
1902 if(typeof tpl == "string"){
1903 tpl = new Roo.Template(tpl);
1907 * The template used by this View
1908 * @type {Roo.DomHelper.Template}
1912 Roo.apply(this, config);
1917 * @event beforeclick
1918 * Fires before a click is processed. Returns false to cancel the default action.
1919 * @param {Roo.View} this
1920 * @param {Number} index The index of the target node
1921 * @param {HTMLElement} node The target node
1922 * @param {Roo.EventObject} e The raw event object
1924 "beforeclick" : true,
1927 * Fires when a template node is clicked.
1928 * @param {Roo.View} this
1929 * @param {Number} index The index of the target node
1930 * @param {HTMLElement} node The target node
1931 * @param {Roo.EventObject} e The raw event object
1936 * Fires when a template node is double clicked.
1937 * @param {Roo.View} this
1938 * @param {Number} index The index of the target node
1939 * @param {HTMLElement} node The target node
1940 * @param {Roo.EventObject} e The raw event object
1944 * @event contextmenu
1945 * Fires when a template node is right clicked.
1946 * @param {Roo.View} this
1947 * @param {Number} index The index of the target node
1948 * @param {HTMLElement} node The target node
1949 * @param {Roo.EventObject} e The raw event object
1951 "contextmenu" : true,
1953 * @event selectionchange
1954 * Fires when the selected nodes change.
1955 * @param {Roo.View} this
1956 * @param {Array} selections Array of the selected nodes
1958 "selectionchange" : true,
1961 * @event beforeselect
1962 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
1963 * @param {Roo.View} this
1964 * @param {HTMLElement} node The node to be selected
1965 * @param {Array} selections Array of currently selected nodes
1967 "beforeselect" : true
1971 "click": this.onClick,
1972 "dblclick": this.onDblClick,
1973 "contextmenu": this.onContextMenu,
1977 this.selections = [];
1979 this.cmp = new Roo.CompositeElementLite([]);
1981 this.store = Roo.factory(this.store, Roo.data);
1982 this.setStore(this.store, true);
1984 Roo.View.superclass.constructor.call(this);
1987 Roo.extend(Roo.View, Roo.util.Observable, {
1989 * The css class to add to selected nodes
1990 * @type {Roo.DomHelper.Template}
1992 selectedClass : "x-view-selected",
1996 * Returns the element this view is bound to.
1997 * @return {Roo.Element}
2004 * Refreshes the view.
2006 refresh : function(){
2008 this.clearSelections();
2011 var records = this.store.getRange();
2012 if(records.length < 1){
2013 this.el.update(this.emptyText);
2016 for(var i = 0, len = records.length; i < len; i++){
2017 var data = this.prepareData(records[i].data, i, records[i]);
2018 html[html.length] = t.apply(data);
2020 this.el.update(html.join(""));
2021 this.nodes = this.el.dom.childNodes;
2022 this.updateIndexes(0);
2026 * Function to override to reformat the data that is sent to
2027 * the template for each node.
2028 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
2029 * a JSON object for an UpdateManager bound view).
2031 prepareData : function(data){
2035 onUpdate : function(ds, record){
2036 this.clearSelections();
2037 var index = this.store.indexOf(record);
2038 var n = this.nodes[index];
2039 this.tpl.insertBefore(n, this.prepareData(record.data));
2040 n.parentNode.removeChild(n);
2041 this.updateIndexes(index, index);
2044 onAdd : function(ds, records, index){
2045 this.clearSelections();
2046 if(this.nodes.length == 0){
2050 var n = this.nodes[index];
2051 for(var i = 0, len = records.length; i < len; i++){
2052 var d = this.prepareData(records[i].data);
2054 this.tpl.insertBefore(n, d);
2056 this.tpl.append(this.el, d);
2059 this.updateIndexes(index);
2062 onRemove : function(ds, record, index){
2063 this.clearSelections();
2064 this.el.dom.removeChild(this.nodes[index]);
2065 this.updateIndexes(index);
2069 * Refresh an individual node.
2070 * @param {Number} index
2072 refreshNode : function(index){
2073 this.onUpdate(this.store, this.store.getAt(index));
2076 updateIndexes : function(startIndex, endIndex){
2077 var ns = this.nodes;
2078 startIndex = startIndex || 0;
2079 endIndex = endIndex || ns.length - 1;
2080 for(var i = startIndex; i <= endIndex; i++){
2081 ns[i].nodeIndex = i;
2086 * Changes the data store this view uses and refresh the view.
2087 * @param {Store} store
2089 setStore : function(store, initial){
2090 if(!initial && this.store){
2091 this.store.un("datachanged", this.refresh);
2092 this.store.un("add", this.onAdd);
2093 this.store.un("remove", this.onRemove);
2094 this.store.un("update", this.onUpdate);
2095 this.store.un("clear", this.refresh);
2099 store.on("datachanged", this.refresh, this);
2100 store.on("add", this.onAdd, this);
2101 store.on("remove", this.onRemove, this);
2102 store.on("update", this.onUpdate, this);
2103 store.on("clear", this.refresh, this);
2112 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
2113 * @param {HTMLElement} node
2114 * @return {HTMLElement} The template node
2116 findItemFromChild : function(node){
2117 var el = this.el.dom;
2118 if(!node || node.parentNode == el){
2121 var p = node.parentNode;
2122 while(p && p != el){
2123 if(p.parentNode == el){
2132 onClick : function(e){
2133 var item = this.findItemFromChild(e.getTarget());
2135 var index = this.indexOf(item);
2136 if(this.onItemClick(item, index, e) !== false){
2137 this.fireEvent("click", this, index, item, e);
2140 this.clearSelections();
2145 onContextMenu : function(e){
2146 var item = this.findItemFromChild(e.getTarget());
2148 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
2153 onDblClick : function(e){
2154 var item = this.findItemFromChild(e.getTarget());
2156 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
2160 onItemClick : function(item, index, e){
2161 if(this.fireEvent("beforeclick", this, index, item, e) === false){
2164 if(this.multiSelect || this.singleSelect){
2165 if(this.multiSelect && e.shiftKey && this.lastSelection){
2166 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
2168 this.select(item, this.multiSelect && e.ctrlKey);
2169 this.lastSelection = item;
2177 * Get the number of selected nodes.
2180 getSelectionCount : function(){
2181 return this.selections.length;
2185 * Get the currently selected nodes.
2186 * @return {Array} An array of HTMLElements
2188 getSelectedNodes : function(){
2189 return this.selections;
2193 * Get the indexes of the selected nodes.
2196 getSelectedIndexes : function(){
2197 var indexes = [], s = this.selections;
2198 for(var i = 0, len = s.length; i < len; i++){
2199 indexes.push(s[i].nodeIndex);
2205 * Clear all selections
2206 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
2208 clearSelections : function(suppressEvent){
2209 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
2210 this.cmp.elements = this.selections;
2211 this.cmp.removeClass(this.selectedClass);
2212 this.selections = [];
2214 this.fireEvent("selectionchange", this, this.selections);
2220 * Returns true if the passed node is selected
2221 * @param {HTMLElement/Number} node The node or node index
2224 isSelected : function(node){
2225 var s = this.selections;
2229 node = this.getNode(node);
2230 return s.indexOf(node) !== -1;
2235 * @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
2236 * @param {Boolean} keepExisting (optional) true to keep existing selections
2237 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
2239 select : function(nodeInfo, keepExisting, suppressEvent){
2240 if(nodeInfo instanceof Array){
2242 this.clearSelections(true);
2244 for(var i = 0, len = nodeInfo.length; i < len; i++){
2245 this.select(nodeInfo[i], true, true);
2248 var node = this.getNode(nodeInfo);
2249 if(node && !this.isSelected(node)){
2251 this.clearSelections(true);
2253 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
2254 Roo.fly(node).addClass(this.selectedClass);
2255 this.selections.push(node);
2257 this.fireEvent("selectionchange", this, this.selections);
2265 * Gets a template node.
2266 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
2267 * @return {HTMLElement} The node or null if it wasn't found
2269 getNode : function(nodeInfo){
2270 if(typeof nodeInfo == "string"){
2271 return document.getElementById(nodeInfo);
2272 }else if(typeof nodeInfo == "number"){
2273 return this.nodes[nodeInfo];
2279 * Gets a range template nodes.
2280 * @param {Number} startIndex
2281 * @param {Number} endIndex
2282 * @return {Array} An array of nodes
2284 getNodes : function(start, end){
2285 var ns = this.nodes;
2287 end = typeof end == "undefined" ? ns.length - 1 : end;
2290 for(var i = start; i <= end; i++){
2294 for(var i = start; i >= end; i--){
2302 * Finds the index of the passed node
2303 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
2304 * @return {Number} The index of the node or -1
2306 indexOf : function(node){
2307 node = this.getNode(node);
2308 if(typeof node.nodeIndex == "number"){
2309 return node.nodeIndex;
2311 var ns = this.nodes;
2312 for(var i = 0, len = ns.length; i < len; i++){
2322 * Ext JS Library 1.1.1
2323 * Copyright(c) 2006-2007, Ext JS, LLC.
2325 * Originally Released Under LGPL - original licence link has changed is not relivant.
2328 * <script type="text/javascript">
2332 * @class Roo.JsonView
2334 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
2336 var view = new Roo.JsonView("my-element",
2337 '<div id="{id}">{foo} - {bar}</div>', // auto create template
2338 { multiSelect: true, jsonRoot: "data" }
2341 // listen for node click?
2342 view.on("click", function(vw, index, node, e){
2343 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
2346 // direct load of JSON data
2347 view.load("foobar.php");
2349 // Example from my blog list
2350 var tpl = new Roo.Template(
2351 '<div class="entry">' +
2352 '<a class="entry-title" href="{link}">{title}</a>' +
2353 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
2354 "</div><hr />"
2357 var moreView = new Roo.JsonView("entry-list", tpl, {
2360 moreView.on("beforerender", this.sortEntries, this);
2362 url: "/blog/get-posts.php",
2363 params: "allposts=true",
2364 text: "Loading Blog Entries..."
2368 * Create a new JsonView
2369 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
2370 * @param {Template} tpl The rendering template
2371 * @param {Object} config The config object
2373 Roo.JsonView = function(container, tpl, config){
2374 Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
2376 var um = this.el.getUpdateManager();
2377 um.setRenderer(this);
2378 um.on("update", this.onLoad, this);
2379 um.on("failure", this.onLoadException, this);
2382 * @event beforerender
2383 * Fires before rendering of the downloaded JSON data.
2384 * @param {Roo.JsonView} this
2385 * @param {Object} data The JSON data loaded
2389 * Fires when data is loaded.
2390 * @param {Roo.JsonView} this
2391 * @param {Object} data The JSON data loaded
2392 * @param {Object} response The raw Connect response object
2395 * @event loadexception
2396 * Fires when loading fails.
2397 * @param {Roo.JsonView} this
2398 * @param {Object} response The raw Connect response object
2401 'beforerender' : true,
2403 'loadexception' : true
2406 Roo.extend(Roo.JsonView, Roo.View, {
2408 * The root property in the loaded JSON object that contains the data
2414 * Refreshes the view.
2416 refresh : function(){
2417 this.clearSelections();
2420 var o = this.jsonData;
2421 if(o && o.length > 0){
2422 for(var i = 0, len = o.length; i < len; i++){
2423 var data = this.prepareData(o[i], i, o);
2424 html[html.length] = this.tpl.apply(data);
2427 html.push(this.emptyText);
2429 this.el.update(html.join(""));
2430 this.nodes = this.el.dom.childNodes;
2431 this.updateIndexes(0);
2435 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
2436 * @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:
2439 url: "your-url.php",
2440 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
2441 callback: yourFunction,
2442 scope: yourObject, //(optional scope)
2450 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
2451 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
2452 * @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}
2453 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
2454 * @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.
2457 var um = this.el.getUpdateManager();
2458 um.update.apply(um, arguments);
2461 render : function(el, response){
2462 this.clearSelections();
2466 o = Roo.util.JSON.decode(response.responseText);
2469 o = /** eval:var:o */ eval("o." + this.jsonRoot);
2474 * The current JSON data or null
2477 this.beforeRender();
2482 * Get the number of records in the current JSON dataset
2485 getCount : function(){
2486 return this.jsonData ? this.jsonData.length : 0;
2490 * Returns the JSON object for the specified node(s)
2491 * @param {HTMLElement/Array} node The node or an array of nodes
2492 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
2493 * you get the JSON object for the node
2495 getNodeData : function(node){
2496 if(node instanceof Array){
2498 for(var i = 0, len = node.length; i < len; i++){
2499 data.push(this.getNodeData(node[i]));
2503 return this.jsonData[this.indexOf(node)] || null;
2506 beforeRender : function(){
2507 this.snapshot = this.jsonData;
2509 this.sort.apply(this, this.sortInfo);
2511 this.fireEvent("beforerender", this, this.jsonData);
2514 onLoad : function(el, o){
2515 this.fireEvent("load", this, this.jsonData, o);
2518 onLoadException : function(el, o){
2519 this.fireEvent("loadexception", this, o);
2523 * Filter the data by a specific property.
2524 * @param {String} property A property on your JSON objects
2525 * @param {String/RegExp} value Either string that the property values
2526 * should start with, or a RegExp to test against the property
2528 filter : function(property, value){
2531 var ss = this.snapshot;
2532 if(typeof value == "string"){
2533 var vlen = value.length;
2538 value = value.toLowerCase();
2539 for(var i = 0, len = ss.length; i < len; i++){
2541 if(o[property].substr(0, vlen).toLowerCase() == value){
2545 } else if(value.exec){ // regex?
2546 for(var i = 0, len = ss.length; i < len; i++){
2548 if(value.test(o[property])){
2555 this.jsonData = data;
2561 * Filter by a function. The passed function will be called with each
2562 * object in the current dataset. If the function returns true the value is kept,
2563 * otherwise it is filtered.
2564 * @param {Function} fn
2565 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
2567 filterBy : function(fn, scope){
2570 var ss = this.snapshot;
2571 for(var i = 0, len = ss.length; i < len; i++){
2573 if(fn.call(scope || this, o)){
2577 this.jsonData = data;
2583 * Clears the current filter.
2585 clearFilter : function(){
2586 if(this.snapshot && this.jsonData != this.snapshot){
2587 this.jsonData = this.snapshot;
2594 * Sorts the data for this view and refreshes it.
2595 * @param {String} property A property on your JSON objects to sort on
2596 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
2597 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
2599 sort : function(property, dir, sortType){
2600 this.sortInfo = Array.prototype.slice.call(arguments, 0);
2603 var dsc = dir && dir.toLowerCase() == "desc";
2604 var f = function(o1, o2){
2605 var v1 = sortType ? sortType(o1[p]) : o1[p];
2606 var v2 = sortType ? sortType(o2[p]) : o2[p];
2609 return dsc ? +1 : -1;
2611 return dsc ? -1 : +1;
2616 this.jsonData.sort(f);
2618 if(this.jsonData != this.snapshot){
2619 this.snapshot.sort(f);
2625 * Ext JS Library 1.1.1
2626 * Copyright(c) 2006-2007, Ext JS, LLC.
2628 * Originally Released Under LGPL - original licence link has changed is not relivant.
2631 * <script type="text/javascript">
2636 * @class Roo.ColorPalette
2637 * @extends Roo.Component
2638 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
2639 * Here's an example of typical usage:
2641 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
2642 cp.render('my-div');
2644 cp.on('select', function(palette, selColor){
2645 // do something with selColor
2649 * Create a new ColorPalette
2650 * @param {Object} config The config object
2652 Roo.ColorPalette = function(config){
2653 Roo.ColorPalette.superclass.constructor.call(this, config);
2657 * Fires when a color is selected
2658 * @param {ColorPalette} this
2659 * @param {String} color The 6-digit color hex code (without the # symbol)
2665 this.on("select", this.handler, this.scope, true);
2668 Roo.extend(Roo.ColorPalette, Roo.Component, {
2670 * @cfg {String} itemCls
2671 * The CSS class to apply to the containing element (defaults to "x-color-palette")
2673 itemCls : "x-color-palette",
2675 * @cfg {String} value
2676 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
2677 * the hex codes are case-sensitive.
2682 ctype: "Roo.ColorPalette",
2685 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
2687 allowReselect : false,
2690 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
2691 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
2692 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
2693 * of colors with the width setting until the box is symmetrical.</p>
2694 * <p>You can override individual colors if needed:</p>
2696 var cp = new Roo.ColorPalette();
2697 cp.colors[0] = "FF0000"; // change the first box to red
2700 Or you can provide a custom array of your own for complete control:
2702 var cp = new Roo.ColorPalette();
2703 cp.colors = ["000000", "993300", "333300"];
2708 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
2709 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
2710 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
2711 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
2712 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
2716 onRender : function(container, position){
2717 var t = new Roo.MasterTemplate(
2718 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
2720 var c = this.colors;
2721 for(var i = 0, len = c.length; i < len; i++){
2724 var el = document.createElement("div");
2725 el.className = this.itemCls;
2727 container.dom.insertBefore(el, position);
2728 this.el = Roo.get(el);
2729 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
2730 if(this.clickEvent != 'click'){
2731 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
2736 afterRender : function(){
2737 Roo.ColorPalette.superclass.afterRender.call(this);
2746 handleClick : function(e, t){
2749 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
2750 this.select(c.toUpperCase());
2755 * Selects the specified color in the palette (fires the select event)
2756 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
2758 select : function(color){
2759 color = color.replace("#", "");
2760 if(color != this.value || this.allowReselect){
2763 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
2765 el.child("a.color-"+color).addClass("x-color-palette-sel");
2767 this.fireEvent("select", this, color);
2772 * Ext JS Library 1.1.1
2773 * Copyright(c) 2006-2007, Ext JS, LLC.
2775 * Originally Released Under LGPL - original licence link has changed is not relivant.
2778 * <script type="text/javascript">
2782 * @class Roo.DatePicker
2783 * @extends Roo.Component
2784 * Simple date picker class.
2786 * Create a new DatePicker
2787 * @param {Object} config The config object
2789 Roo.DatePicker = function(config){
2790 Roo.DatePicker.superclass.constructor.call(this, config);
2792 this.value = config && config.value ?
2793 config.value.clearTime() : new Date().clearTime();
2798 * Fires when a date is selected
2799 * @param {DatePicker} this
2800 * @param {Date} date The selected date
2806 this.on("select", this.handler, this.scope || this);
2808 // build the disabledDatesRE
2809 if(!this.disabledDatesRE && this.disabledDates){
2810 var dd = this.disabledDates;
2812 for(var i = 0; i < dd.length; i++){
2814 if(i != dd.length-1) re += "|";
2816 this.disabledDatesRE = new RegExp(re + ")");
2820 Roo.extend(Roo.DatePicker, Roo.Component, {
2822 * @cfg {String} todayText
2823 * The text to display on the button that selects the current date (defaults to "Today")
2825 todayText : "Today",
2827 * @cfg {String} okText
2828 * The text to display on the ok button
2830 okText : " OK ", //   to give the user extra clicking room
2832 * @cfg {String} cancelText
2833 * The text to display on the cancel button
2835 cancelText : "Cancel",
2837 * @cfg {String} todayTip
2838 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
2840 todayTip : "{0} (Spacebar)",
2842 * @cfg {Date} minDate
2843 * Minimum allowable date (JavaScript date object, defaults to null)
2847 * @cfg {Date} maxDate
2848 * Maximum allowable date (JavaScript date object, defaults to null)
2852 * @cfg {String} minText
2853 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
2855 minText : "This date is before the minimum date",
2857 * @cfg {String} maxText
2858 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
2860 maxText : "This date is after the maximum date",
2862 * @cfg {String} format
2863 * The default date format string which can be overriden for localization support. The format must be
2864 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
2868 * @cfg {Array} disabledDays
2869 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
2871 disabledDays : null,
2873 * @cfg {String} disabledDaysText
2874 * The tooltip to display when the date falls on a disabled day (defaults to "")
2876 disabledDaysText : "",
2878 * @cfg {RegExp} disabledDatesRE
2879 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
2881 disabledDatesRE : null,
2883 * @cfg {String} disabledDatesText
2884 * The tooltip text to display when the date falls on a disabled date (defaults to "")
2886 disabledDatesText : "",
2888 * @cfg {Boolean} constrainToViewport
2889 * True to constrain the date picker to the viewport (defaults to true)
2891 constrainToViewport : true,
2893 * @cfg {Array} monthNames
2894 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
2896 monthNames : Date.monthNames,
2898 * @cfg {Array} dayNames
2899 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
2901 dayNames : Date.dayNames,
2903 * @cfg {String} nextText
2904 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
2906 nextText: 'Next Month (Control+Right)',
2908 * @cfg {String} prevText
2909 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
2911 prevText: 'Previous Month (Control+Left)',
2913 * @cfg {String} monthYearText
2914 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
2916 monthYearText: 'Choose a month (Control+Up/Down to move years)',
2918 * @cfg {Number} startDay
2919 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
2923 * @cfg {Bool} showClear
2924 * Show a clear button (usefull for date form elements that can be blank.)
2930 * Sets the value of the date field
2931 * @param {Date} value The date to set
2933 setValue : function(value){
2934 var old = this.value;
2935 this.value = value.clearTime(true);
2937 this.update(this.value);
2942 * Gets the current selected value of the date field
2943 * @return {Date} The selected date
2945 getValue : function(){
2952 this.update(this.activeDate);
2957 onRender : function(container, position){
2959 '<table cellspacing="0">',
2960 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
2961 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
2962 var dn = this.dayNames;
2963 for(var i = 0; i < 7; i++){
2964 var d = this.startDay+i;
2968 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
2970 m[m.length] = "</tr></thead><tbody><tr>";
2971 for(var i = 0; i < 42; i++) {
2972 if(i % 7 == 0 && i != 0){
2973 m[m.length] = "</tr><tr>";
2975 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
2977 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
2978 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
2980 var el = document.createElement("div");
2981 el.className = "x-date-picker";
2982 el.innerHTML = m.join("");
2984 container.dom.insertBefore(el, position);
2986 this.el = Roo.get(el);
2987 this.eventEl = Roo.get(el.firstChild);
2989 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
2990 handler: this.showPrevMonth,
2992 preventDefault:true,
2996 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
2997 handler: this.showNextMonth,
2999 preventDefault:true,
3003 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
3005 this.monthPicker = this.el.down('div.x-date-mp');
3006 this.monthPicker.enableDisplayMode('block');
3008 var kn = new Roo.KeyNav(this.eventEl, {
3009 "left" : function(e){
3011 this.showPrevMonth() :
3012 this.update(this.activeDate.add("d", -1));
3015 "right" : function(e){
3017 this.showNextMonth() :
3018 this.update(this.activeDate.add("d", 1));
3023 this.showNextYear() :
3024 this.update(this.activeDate.add("d", -7));
3027 "down" : function(e){
3029 this.showPrevYear() :
3030 this.update(this.activeDate.add("d", 7));
3033 "pageUp" : function(e){
3034 this.showNextMonth();
3037 "pageDown" : function(e){
3038 this.showPrevMonth();
3041 "enter" : function(e){
3042 e.stopPropagation();
3049 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
3051 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
3053 this.el.unselectable();
3055 this.cells = this.el.select("table.x-date-inner tbody td");
3056 this.textNodes = this.el.query("table.x-date-inner tbody span");
3058 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
3060 tooltip: this.monthYearText
3063 this.mbtn.on('click', this.showMonthPicker, this);
3064 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
3067 var today = (new Date()).dateFormat(this.format);
3069 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
3071 text: String.format(this.todayText, today),
3072 tooltip: String.format(this.todayTip, today),
3073 handler: this.selectToday,
3077 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
3080 if (this.showClear) {
3082 baseTb.add( new Roo.Toolbar.Fill());
3085 cls: 'x-btn-icon x-btn-clear',
3086 handler: function() {
3088 this.fireEvent("select", this, '');
3098 this.update(this.value);
3101 createMonthPicker : function(){
3102 if(!this.monthPicker.dom.firstChild){
3103 var buf = ['<table border="0" cellspacing="0">'];
3104 for(var i = 0; i < 6; i++){
3106 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
3107 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
3109 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
3110 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
3114 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
3116 '</button><button type="button" class="x-date-mp-cancel">',
3118 '</button></td></tr>',
3121 this.monthPicker.update(buf.join(''));
3122 this.monthPicker.on('click', this.onMonthClick, this);
3123 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
3125 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
3126 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
3128 this.mpMonths.each(function(m, a, i){
3131 m.dom.xmonth = 5 + Math.round(i * .5);
3133 m.dom.xmonth = Math.round((i-1) * .5);
3139 showMonthPicker : function(){
3140 this.createMonthPicker();
3141 var size = this.el.getSize();
3142 this.monthPicker.setSize(size);
3143 this.monthPicker.child('table').setSize(size);
3145 this.mpSelMonth = (this.activeDate || this.value).getMonth();
3146 this.updateMPMonth(this.mpSelMonth);
3147 this.mpSelYear = (this.activeDate || this.value).getFullYear();
3148 this.updateMPYear(this.mpSelYear);
3150 this.monthPicker.slideIn('t', {duration:.2});
3153 updateMPYear : function(y){
3155 var ys = this.mpYears.elements;
3156 for(var i = 1; i <= 10; i++){
3157 var td = ys[i-1], y2;
3159 y2 = y + Math.round(i * .5);
3160 td.firstChild.innerHTML = y2;
3163 y2 = y - (5-Math.round(i * .5));
3164 td.firstChild.innerHTML = y2;
3167 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
3171 updateMPMonth : function(sm){
3172 this.mpMonths.each(function(m, a, i){
3173 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
3177 selectMPMonth: function(m){
3181 onMonthClick : function(e, t){
3183 var el = new Roo.Element(t), pn;
3184 if(el.is('button.x-date-mp-cancel')){
3185 this.hideMonthPicker();
3187 else if(el.is('button.x-date-mp-ok')){
3188 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
3189 this.hideMonthPicker();
3191 else if(pn = el.up('td.x-date-mp-month', 2)){
3192 this.mpMonths.removeClass('x-date-mp-sel');
3193 pn.addClass('x-date-mp-sel');
3194 this.mpSelMonth = pn.dom.xmonth;
3196 else if(pn = el.up('td.x-date-mp-year', 2)){
3197 this.mpYears.removeClass('x-date-mp-sel');
3198 pn.addClass('x-date-mp-sel');
3199 this.mpSelYear = pn.dom.xyear;
3201 else if(el.is('a.x-date-mp-prev')){
3202 this.updateMPYear(this.mpyear-10);
3204 else if(el.is('a.x-date-mp-next')){
3205 this.updateMPYear(this.mpyear+10);
3209 onMonthDblClick : function(e, t){
3211 var el = new Roo.Element(t), pn;
3212 if(pn = el.up('td.x-date-mp-month', 2)){
3213 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
3214 this.hideMonthPicker();
3216 else if(pn = el.up('td.x-date-mp-year', 2)){
3217 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
3218 this.hideMonthPicker();
3222 hideMonthPicker : function(disableAnim){
3223 if(this.monthPicker){
3224 if(disableAnim === true){
3225 this.monthPicker.hide();
3227 this.monthPicker.slideOut('t', {duration:.2});
3233 showPrevMonth : function(e){
3234 this.update(this.activeDate.add("mo", -1));
3238 showNextMonth : function(e){
3239 this.update(this.activeDate.add("mo", 1));
3243 showPrevYear : function(){
3244 this.update(this.activeDate.add("y", -1));
3248 showNextYear : function(){
3249 this.update(this.activeDate.add("y", 1));
3253 handleMouseWheel : function(e){
3254 var delta = e.getWheelDelta();
3256 this.showPrevMonth();
3258 } else if(delta < 0){
3259 this.showNextMonth();
3265 handleDateClick : function(e, t){
3267 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
3268 this.setValue(new Date(t.dateValue));
3269 this.fireEvent("select", this, this.value);
3274 selectToday : function(){
3275 this.setValue(new Date().clearTime());
3276 this.fireEvent("select", this, this.value);
3280 update : function(date){
3281 var vd = this.activeDate;
3282 this.activeDate = date;
3284 var t = date.getTime();
3285 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
3286 this.cells.removeClass("x-date-selected");
3287 this.cells.each(function(c){
3288 if(c.dom.firstChild.dateValue == t){
3289 c.addClass("x-date-selected");
3290 setTimeout(function(){
3291 try{c.dom.firstChild.focus();}catch(e){}
3299 var days = date.getDaysInMonth();
3300 var firstOfMonth = date.getFirstDateOfMonth();
3301 var startingPos = firstOfMonth.getDay()-this.startDay;
3303 if(startingPos <= this.startDay){
3307 var pm = date.add("mo", -1);
3308 var prevStart = pm.getDaysInMonth()-startingPos;
3310 var cells = this.cells.elements;
3311 var textEls = this.textNodes;
3312 days += startingPos;
3314 // convert everything to numbers so it's fast
3316 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
3317 var today = new Date().clearTime().getTime();
3318 var sel = date.clearTime().getTime();
3319 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
3320 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
3321 var ddMatch = this.disabledDatesRE;
3322 var ddText = this.disabledDatesText;
3323 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
3324 var ddaysText = this.disabledDaysText;
3325 var format = this.format;
3327 var setCellClass = function(cal, cell){
3329 var t = d.getTime();
3330 cell.firstChild.dateValue = t;
3332 cell.className += " x-date-today";
3333 cell.title = cal.todayText;
3336 cell.className += " x-date-selected";
3337 setTimeout(function(){
3338 try{cell.firstChild.focus();}catch(e){}
3343 cell.className = " x-date-disabled";
3344 cell.title = cal.minText;
3348 cell.className = " x-date-disabled";
3349 cell.title = cal.maxText;
3353 if(ddays.indexOf(d.getDay()) != -1){
3354 cell.title = ddaysText;
3355 cell.className = " x-date-disabled";
3358 if(ddMatch && format){
3359 var fvalue = d.dateFormat(format);
3360 if(ddMatch.test(fvalue)){
3361 cell.title = ddText.replace("%0", fvalue);
3362 cell.className = " x-date-disabled";
3368 for(; i < startingPos; i++) {
3369 textEls[i].innerHTML = (++prevStart);
3370 d.setDate(d.getDate()+1);
3371 cells[i].className = "x-date-prevday";
3372 setCellClass(this, cells[i]);
3374 for(; i < days; i++){
3375 intDay = i - startingPos + 1;
3376 textEls[i].innerHTML = (intDay);
3377 d.setDate(d.getDate()+1);
3378 cells[i].className = "x-date-active";
3379 setCellClass(this, cells[i]);
3382 for(; i < 42; i++) {
3383 textEls[i].innerHTML = (++extraDays);
3384 d.setDate(d.getDate()+1);
3385 cells[i].className = "x-date-nextday";
3386 setCellClass(this, cells[i]);
3389 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
3391 if(!this.internalRender){
3392 var main = this.el.dom.firstChild;
3393 var w = main.offsetWidth;
3394 this.el.setWidth(w + this.el.getBorderWidth("lr"));
3395 Roo.fly(main).setWidth(w);
3396 this.internalRender = true;
3397 // opera does not respect the auto grow header center column
3398 // then, after it gets a width opera refuses to recalculate
3399 // without a second pass
3400 if(Roo.isOpera && !this.secondPass){
3401 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
3402 this.secondPass = true;
3403 this.update.defer(10, this, [date]);
3409 * Ext JS Library 1.1.1
3410 * Copyright(c) 2006-2007, Ext JS, LLC.
3412 * Originally Released Under LGPL - original licence link has changed is not relivant.
3415 * <script type="text/javascript">
3418 * @class Roo.TabPanel
3419 * @extends Roo.util.Observable
3420 * A lightweight tab container.
3424 // basic tabs 1, built from existing content
3425 var tabs = new Roo.TabPanel("tabs1");
3426 tabs.addTab("script", "View Script");
3427 tabs.addTab("markup", "View Markup");
3428 tabs.activate("script");
3430 // more advanced tabs, built from javascript
3431 var jtabs = new Roo.TabPanel("jtabs");
3432 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
3434 // set up the UpdateManager
3435 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
3436 var updater = tab2.getUpdateManager();
3437 updater.setDefaultUrl("ajax1.htm");
3438 tab2.on('activate', updater.refresh, updater, true);
3440 // Use setUrl for Ajax loading
3441 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
3442 tab3.setUrl("ajax2.htm", null, true);
3445 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
3448 jtabs.activate("jtabs-1");
3451 * Create a new TabPanel.
3452 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
3453 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
3455 Roo.TabPanel = function(container, config){
3457 * The container element for this TabPanel.
3460 this.el = Roo.get(container, true);
3462 if(typeof config == "boolean"){
3463 this.tabPosition = config ? "bottom" : "top";
3465 Roo.apply(this, config);
3468 if(this.tabPosition == "bottom"){
3469 this.bodyEl = Roo.get(this.createBody(this.el.dom));
3470 this.el.addClass("x-tabs-bottom");
3472 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
3473 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
3474 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
3476 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
3478 if(this.tabPosition != "bottom"){
3479 /** The body element that contains {@link Roo.TabPanelItem} bodies.
3482 this.bodyEl = Roo.get(this.createBody(this.el.dom));
3483 this.el.addClass("x-tabs-top");
3487 this.bodyEl.setStyle("position", "relative");
3490 this.activateDelegate = this.activate.createDelegate(this);
3495 * Fires when the active tab changes
3496 * @param {Roo.TabPanel} this
3497 * @param {Roo.TabPanelItem} activePanel The new active tab
3501 * @event beforetabchange
3502 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
3503 * @param {Roo.TabPanel} this
3504 * @param {Object} e Set cancel to true on this object to cancel the tab change
3505 * @param {Roo.TabPanelItem} tab The tab being changed to
3507 "beforetabchange" : true
3510 Roo.EventManager.onWindowResize(this.onResize, this);
3511 this.cpad = this.el.getPadding("lr");
3512 this.hiddenCount = 0;
3514 Roo.TabPanel.superclass.constructor.call(this);
3517 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
3519 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
3521 tabPosition : "top",
3523 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
3525 currentTabWidth : 0,
3527 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
3531 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
3535 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
3537 preferredTabWidth : 175,
3539 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
3543 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
3545 monitorResize : true,
3548 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
3549 * @param {String} id The id of the div to use <b>or create</b>
3550 * @param {String} text The text for the tab
3551 * @param {String} content (optional) Content to put in the TabPanelItem body
3552 * @param {Boolean} closable (optional) True to create a close icon on the tab
3553 * @return {Roo.TabPanelItem} The created TabPanelItem
3555 addTab : function(id, text, content, closable){
3556 var item = new Roo.TabPanelItem(this, id, text, closable);
3557 this.addTabItem(item);
3559 item.setContent(content);
3565 * Returns the {@link Roo.TabPanelItem} with the specified id/index
3566 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
3567 * @return {Roo.TabPanelItem}
3569 getTab : function(id){
3570 return this.items[id];
3574 * Hides the {@link Roo.TabPanelItem} with the specified id/index
3575 * @param {String/Number} id The id or index of the TabPanelItem to hide.
3577 hideTab : function(id){
3578 var t = this.items[id];
3582 this.autoSizeTabs();
3587 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
3588 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
3590 unhideTab : function(id){
3591 var t = this.items[id];
3595 this.autoSizeTabs();
3600 * Adds an existing {@link Roo.TabPanelItem}.
3601 * @param {Roo.TabPanelItem} item The TabPanelItem to add
3603 addTabItem : function(item){
3604 this.items[item.id] = item;
3605 this.items.push(item);
3606 if(this.resizeTabs){
3607 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
3608 this.autoSizeTabs();
3615 * Removes a {@link Roo.TabPanelItem}.
3616 * @param {String/Number} id The id or index of the TabPanelItem to remove.
3618 removeTab : function(id){
3619 var items = this.items;
3620 var tab = items[id];
3622 var index = items.indexOf(tab);
3623 if(this.active == tab && items.length > 1){
3624 var newTab = this.getNextAvailable(index);
3625 if(newTab)newTab.activate();
3627 this.stripEl.dom.removeChild(tab.pnode.dom);
3628 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
3629 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
3631 items.splice(index, 1);
3632 delete this.items[tab.id];
3633 tab.fireEvent("close", tab);
3634 tab.purgeListeners();
3635 this.autoSizeTabs();
3638 getNextAvailable : function(start){
3639 var items = this.items;
3641 // look for a next tab that will slide over to
3642 // replace the one being removed
3643 while(index < items.length){
3644 var item = items[++index];
3645 if(item && !item.isHidden()){
3649 // if one isn't found select the previous tab (on the left)
3652 var item = items[--index];
3653 if(item && !item.isHidden()){
3661 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
3662 * @param {String/Number} id The id or index of the TabPanelItem to disable.
3664 disableTab : function(id){
3665 var tab = this.items[id];
3666 if(tab && this.active != tab){
3672 * Enables a {@link Roo.TabPanelItem} that is disabled.
3673 * @param {String/Number} id The id or index of the TabPanelItem to enable.
3675 enableTab : function(id){
3676 var tab = this.items[id];
3681 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
3682 * @param {String/Number} id The id or index of the TabPanelItem to activate.
3683 * @return {Roo.TabPanelItem} The TabPanelItem.
3685 activate : function(id){
3686 var tab = this.items[id];
3690 if(tab == this.active || tab.disabled){
3694 this.fireEvent("beforetabchange", this, e, tab);
3695 if(e.cancel !== true && !tab.disabled){
3699 this.active = this.items[id];
3701 this.fireEvent("tabchange", this, this.active);
3707 * Gets the active {@link Roo.TabPanelItem}.
3708 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
3710 getActiveTab : function(){
3715 * Updates the tab body element to fit the height of the container element
3716 * for overflow scrolling
3717 * @param {Number} targetHeight (optional) Override the starting height from the elements height
3719 syncHeight : function(targetHeight){
3720 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
3721 var bm = this.bodyEl.getMargins();
3722 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
3723 this.bodyEl.setHeight(newHeight);
3727 onResize : function(){
3728 if(this.monitorResize){
3729 this.autoSizeTabs();
3734 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
3736 beginUpdate : function(){
3737 this.updating = true;
3741 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
3743 endUpdate : function(){
3744 this.updating = false;
3745 this.autoSizeTabs();
3749 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
3751 autoSizeTabs : function(){
3752 var count = this.items.length;
3753 var vcount = count - this.hiddenCount;
3754 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
3755 var w = Math.max(this.el.getWidth() - this.cpad, 10);
3756 var availWidth = Math.floor(w / vcount);
3757 var b = this.stripBody;
3758 if(b.getWidth() > w){
3759 var tabs = this.items;
3760 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
3761 if(availWidth < this.minTabWidth){
3762 /*if(!this.sleft){ // incomplete scrolling code
3763 this.createScrollButtons();
3766 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
3769 if(this.currentTabWidth < this.preferredTabWidth){
3770 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
3776 * Returns the number of tabs in this TabPanel.
3779 getCount : function(){
3780 return this.items.length;
3784 * Resizes all the tabs to the passed width
3785 * @param {Number} The new width
3787 setTabWidth : function(width){
3788 this.currentTabWidth = width;
3789 for(var i = 0, len = this.items.length; i < len; i++) {
3790 if(!this.items[i].isHidden())this.items[i].setWidth(width);
3795 * Destroys this TabPanel
3796 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
3798 destroy : function(removeEl){
3799 Roo.EventManager.removeResizeListener(this.onResize, this);
3800 for(var i = 0, len = this.items.length; i < len; i++){
3801 this.items[i].purgeListeners();
3803 if(removeEl === true){
3811 * @class Roo.TabPanelItem
3812 * @extends Roo.util.Observable
3813 * Represents an individual item (tab plus body) in a TabPanel.
3814 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
3815 * @param {String} id The id of this TabPanelItem
3816 * @param {String} text The text for the tab of this TabPanelItem
3817 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
3819 Roo.TabPanelItem = function(tabPanel, id, text, closable){
3821 * The {@link Roo.TabPanel} this TabPanelItem belongs to
3822 * @type Roo.TabPanel
3824 this.tabPanel = tabPanel;
3826 * The id for this TabPanelItem
3831 this.disabled = false;
3835 this.loaded = false;
3836 this.closable = closable;
3839 * The body element for this TabPanelItem.
3842 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
3843 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
3844 this.bodyEl.setStyle("display", "block");
3845 this.bodyEl.setStyle("zoom", "1");
3848 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
3850 this.el = Roo.get(els.el, true);
3851 this.inner = Roo.get(els.inner, true);
3852 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
3853 this.pnode = Roo.get(els.el.parentNode, true);
3854 this.el.on("mousedown", this.onTabMouseDown, this);
3855 this.el.on("click", this.onTabClick, this);
3858 var c = Roo.get(els.close, true);
3859 c.dom.title = this.closeText;
3860 c.addClassOnOver("close-over");
3861 c.on("click", this.closeClick, this);
3867 * Fires when this tab becomes the active tab.
3868 * @param {Roo.TabPanel} tabPanel The parent TabPanel
3869 * @param {Roo.TabPanelItem} this
3873 * @event beforeclose
3874 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
3875 * @param {Roo.TabPanelItem} this
3876 * @param {Object} e Set cancel to true on this object to cancel the close.
3878 "beforeclose": true,
3881 * Fires when this tab is closed.
3882 * @param {Roo.TabPanelItem} this
3887 * Fires when this tab is no longer the active tab.
3888 * @param {Roo.TabPanel} tabPanel The parent TabPanel
3889 * @param {Roo.TabPanelItem} this
3893 this.hidden = false;
3895 Roo.TabPanelItem.superclass.constructor.call(this);
3898 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
3899 purgeListeners : function(){
3900 Roo.util.Observable.prototype.purgeListeners.call(this);
3901 this.el.removeAllListeners();
3904 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
3907 this.pnode.addClass("on");
3910 this.tabPanel.stripWrap.repaint();
3912 this.fireEvent("activate", this.tabPanel, this);
3916 * Returns true if this tab is the active tab.
3919 isActive : function(){
3920 return this.tabPanel.getActiveTab() == this;
3924 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
3927 this.pnode.removeClass("on");
3929 this.fireEvent("deactivate", this.tabPanel, this);
3932 hideAction : function(){
3934 this.bodyEl.setStyle("position", "absolute");
3935 this.bodyEl.setLeft("-20000px");
3936 this.bodyEl.setTop("-20000px");
3939 showAction : function(){
3940 this.bodyEl.setStyle("position", "relative");
3941 this.bodyEl.setTop("");
3942 this.bodyEl.setLeft("");
3947 * Set the tooltip for the tab.
3948 * @param {String} tooltip The tab's tooltip
3950 setTooltip : function(text){
3951 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
3952 this.textEl.dom.qtip = text;
3953 this.textEl.dom.removeAttribute('title');
3955 this.textEl.dom.title = text;
3959 onTabClick : function(e){
3961 this.tabPanel.activate(this.id);
3964 onTabMouseDown : function(e){
3966 this.tabPanel.activate(this.id);
3969 getWidth : function(){
3970 return this.inner.getWidth();
3973 setWidth : function(width){
3974 var iwidth = width - this.pnode.getPadding("lr");
3975 this.inner.setWidth(iwidth);
3976 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
3977 this.pnode.setWidth(width);
3981 * Show or hide the tab
3982 * @param {Boolean} hidden True to hide or false to show.
3984 setHidden : function(hidden){
3985 this.hidden = hidden;
3986 this.pnode.setStyle("display", hidden ? "none" : "");
3990 * Returns true if this tab is "hidden"
3993 isHidden : function(){
3998 * Returns the text for this tab
4001 getText : function(){
4005 autoSize : function(){
4006 //this.el.beginMeasure();
4007 this.textEl.setWidth(1);
4008 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
4009 //this.el.endMeasure();
4013 * Sets the text for the tab (Note: this also sets the tooltip text)
4014 * @param {String} text The tab's text and tooltip
4016 setText : function(text){
4018 this.textEl.update(text);
4019 this.setTooltip(text);
4020 if(!this.tabPanel.resizeTabs){
4025 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
4027 activate : function(){
4028 this.tabPanel.activate(this.id);
4032 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
4034 disable : function(){
4035 if(this.tabPanel.active != this){
4036 this.disabled = true;
4037 this.pnode.addClass("disabled");
4042 * Enables this TabPanelItem if it was previously disabled.
4044 enable : function(){
4045 this.disabled = false;
4046 this.pnode.removeClass("disabled");
4050 * Sets the content for this TabPanelItem.
4051 * @param {String} content The content
4052 * @param {Boolean} loadScripts true to look for and load scripts
4054 setContent : function(content, loadScripts){
4055 this.bodyEl.update(content, loadScripts);
4059 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
4060 * @return {Roo.UpdateManager} The UpdateManager
4062 getUpdateManager : function(){
4063 return this.bodyEl.getUpdateManager();
4067 * Set a URL to be used to load the content for this TabPanelItem.
4068 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
4069 * @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)
4070 * @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)
4071 * @return {Roo.UpdateManager} The UpdateManager
4073 setUrl : function(url, params, loadOnce){
4074 if(this.refreshDelegate){
4075 this.un('activate', this.refreshDelegate);
4077 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
4078 this.on("activate", this.refreshDelegate);
4079 return this.bodyEl.getUpdateManager();
4083 _handleRefresh : function(url, params, loadOnce){
4084 if(!loadOnce || !this.loaded){
4085 var updater = this.bodyEl.getUpdateManager();
4086 updater.update(url, params, this._setLoaded.createDelegate(this));
4091 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
4092 * Will fail silently if the setUrl method has not been called.
4093 * This does not activate the panel, just updates its content.
4095 refresh : function(){
4096 if(this.refreshDelegate){
4097 this.loaded = false;
4098 this.refreshDelegate();
4103 _setLoaded : function(){
4108 closeClick : function(e){
4111 this.fireEvent("beforeclose", this, o);
4112 if(o.cancel !== true){
4113 this.tabPanel.removeTab(this.id);
4117 * The text displayed in the tooltip for the close icon.
4120 closeText : "Close this tab"
4124 Roo.TabPanel.prototype.createStrip = function(container){
4125 var strip = document.createElement("div");
4126 strip.className = "x-tabs-wrap";
4127 container.appendChild(strip);
4131 Roo.TabPanel.prototype.createStripList = function(strip){
4132 // div wrapper for retard IE
4133 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
4134 return strip.firstChild.firstChild.firstChild.firstChild;
4137 Roo.TabPanel.prototype.createBody = function(container){
4138 var body = document.createElement("div");
4139 Roo.id(body, "tab-body");
4140 Roo.fly(body).addClass("x-tabs-body");
4141 container.appendChild(body);
4145 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
4146 var body = Roo.getDom(id);
4148 body = document.createElement("div");
4151 Roo.fly(body).addClass("x-tabs-item-body");
4152 bodyEl.insertBefore(body, bodyEl.firstChild);
4156 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
4157 var td = document.createElement("td");
4158 stripEl.appendChild(td);
4160 td.className = "x-tabs-closable";
4162 this.closeTpl = new Roo.Template(
4163 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
4164 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
4165 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
4168 var el = this.closeTpl.overwrite(td, {"text": text});
4169 var close = el.getElementsByTagName("div")[0];
4170 var inner = el.getElementsByTagName("em")[0];
4171 return {"el": el, "close": close, "inner": inner};
4174 this.tabTpl = new Roo.Template(
4175 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
4176 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
4179 var el = this.tabTpl.overwrite(td, {"text": text});
4180 var inner = el.getElementsByTagName("em")[0];
4181 return {"el": el, "inner": inner};
4185 * Ext JS Library 1.1.1
4186 * Copyright(c) 2006-2007, Ext JS, LLC.
4188 * Originally Released Under LGPL - original licence link has changed is not relivant.
4191 * <script type="text/javascript">
4196 * @extends Roo.util.Observable
4197 * Simple Button class
4198 * @cfg {String} text The button text
4199 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
4200 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
4201 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
4202 * @cfg {Object} scope The scope of the handler
4203 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
4204 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
4205 * @cfg {Boolean} hidden True to start hidden (defaults to false)
4206 * @cfg {Boolean} disabled True to start disabled (defaults to false)
4207 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
4208 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
4209 applies if enableToggle = true)
4210 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
4211 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
4212 an {@link Roo.util.ClickRepeater} config object (defaults to false).
4214 * Create a new button
4215 * @param {Object} config The config object
4217 Roo.Button = function(renderTo, config)
4221 renderTo = config.renderTo || false;
4224 Roo.apply(this, config);
4228 * Fires when this button is clicked
4229 * @param {Button} this
4230 * @param {EventObject} e The click event
4235 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
4236 * @param {Button} this
4237 * @param {Boolean} pressed
4242 * Fires when the mouse hovers over the button
4243 * @param {Button} this
4244 * @param {Event} e The event object
4249 * Fires when the mouse exits the button
4250 * @param {Button} this
4251 * @param {Event} e The event object
4256 * Fires when the button is rendered
4257 * @param {Button} this
4262 this.menu = Roo.menu.MenuMgr.get(this.menu);
4265 this.render(renderTo);
4268 Roo.util.Observable.call(this);
4271 Roo.extend(Roo.Button, Roo.util.Observable, {
4277 * Read-only. True if this button is hidden
4282 * Read-only. True if this button is disabled
4287 * Read-only. True if this button is pressed (only if enableToggle = true)
4293 * @cfg {Number} tabIndex
4294 * The DOM tabIndex for this button (defaults to undefined)
4296 tabIndex : undefined,
4299 * @cfg {Boolean} enableToggle
4300 * True to enable pressed/not pressed toggling (defaults to false)
4302 enableToggle: false,
4305 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
4309 * @cfg {String} menuAlign
4310 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
4312 menuAlign : "tl-bl?",
4315 * @cfg {String} iconCls
4316 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
4318 iconCls : undefined,
4320 * @cfg {String} type
4321 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
4326 menuClassTarget: 'tr',
4329 * @cfg {String} clickEvent
4330 * The type of event to map to the button's event handler (defaults to 'click')
4332 clickEvent : 'click',
4335 * @cfg {Boolean} handleMouseEvents
4336 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
4338 handleMouseEvents : true,
4341 * @cfg {String} tooltipType
4342 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
4344 tooltipType : 'qtip',
4348 * A CSS class to apply to the button's main element.
4352 * @cfg {Roo.Template} template (Optional)
4353 * An {@link Roo.Template} with which to create the Button's main element. This Template must
4354 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
4355 * require code modifications if required elements (e.g. a button) aren't present.
4359 render : function(renderTo){
4361 if(this.hideParent){
4362 this.parentEl = Roo.get(renderTo);
4366 if(!Roo.Button.buttonTemplate){
4367 // hideous table template
4368 Roo.Button.buttonTemplate = new Roo.Template(
4369 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
4370 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
4371 "</tr></tbody></table>");
4373 this.template = Roo.Button.buttonTemplate;
4375 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
4376 var btnEl = btn.child("button:first");
4377 btnEl.on('focus', this.onFocus, this);
4378 btnEl.on('blur', this.onBlur, this);
4380 btn.addClass(this.cls);
4383 btnEl.setStyle('background-image', 'url(' +this.icon +')');
4386 btnEl.addClass(this.iconCls);
4388 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
4391 if(this.tabIndex !== undefined){
4392 btnEl.dom.tabIndex = this.tabIndex;
4395 if(typeof this.tooltip == 'object'){
4396 Roo.QuickTips.tips(Roo.apply({
4400 btnEl.dom[this.tooltipType] = this.tooltip;
4404 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
4408 this.el.dom.id = this.el.id = this.id;
4411 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
4412 this.menu.on("show", this.onMenuShow, this);
4413 this.menu.on("hide", this.onMenuHide, this);
4415 btn.addClass("x-btn");
4416 if(Roo.isIE && !Roo.isIE7){
4417 this.autoWidth.defer(1, this);
4421 if(this.handleMouseEvents){
4422 btn.on("mouseover", this.onMouseOver, this);
4423 btn.on("mouseout", this.onMouseOut, this);
4424 btn.on("mousedown", this.onMouseDown, this);
4426 btn.on(this.clickEvent, this.onClick, this);
4427 //btn.on("mouseup", this.onMouseUp, this);
4434 Roo.ButtonToggleMgr.register(this);
4436 this.el.addClass("x-btn-pressed");
4439 var repeater = new Roo.util.ClickRepeater(btn,
4440 typeof this.repeat == "object" ? this.repeat : {}
4442 repeater.on("click", this.onClick, this);
4444 this.fireEvent('render', this);
4448 * Returns the button's underlying element
4449 * @return {Roo.Element} The element
4456 * Destroys this Button and removes any listeners.
4458 destroy : function(){
4459 Roo.ButtonToggleMgr.unregister(this);
4460 this.el.removeAllListeners();
4461 this.purgeListeners();
4466 autoWidth : function(){
4468 this.el.setWidth("auto");
4469 if(Roo.isIE7 && Roo.isStrict){
4470 var ib = this.el.child('button');
4471 if(ib && ib.getWidth() > 20){
4473 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
4478 this.el.beginMeasure();
4480 if(this.el.getWidth() < this.minWidth){
4481 this.el.setWidth(this.minWidth);
4484 this.el.endMeasure();
4491 * Assigns this button's click handler
4492 * @param {Function} handler The function to call when the button is clicked
4493 * @param {Object} scope (optional) Scope for the function passed in
4495 setHandler : function(handler, scope){
4496 this.handler = handler;
4501 * Sets this button's text
4502 * @param {String} text The button text
4504 setText : function(text){
4507 this.el.child("td.x-btn-center button.x-btn-text").update(text);
4513 * Gets the text for this button
4514 * @return {String} The button text
4516 getText : function(){
4524 this.hidden = false;
4526 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
4536 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
4541 * Convenience function for boolean show/hide
4542 * @param {Boolean} visible True to show, false to hide
4544 setVisible: function(visible){
4553 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
4554 * @param {Boolean} state (optional) Force a particular state
4556 toggle : function(state){
4557 state = state === undefined ? !this.pressed : state;
4558 if(state != this.pressed){
4560 this.el.addClass("x-btn-pressed");
4561 this.pressed = true;
4562 this.fireEvent("toggle", this, true);
4564 this.el.removeClass("x-btn-pressed");
4565 this.pressed = false;
4566 this.fireEvent("toggle", this, false);
4568 if(this.toggleHandler){
4569 this.toggleHandler.call(this.scope || this, this, state);
4578 this.el.child('button:first').focus();
4582 * Disable this button
4584 disable : function(){
4586 this.el.addClass("x-btn-disabled");
4588 this.disabled = true;
4592 * Enable this button
4594 enable : function(){
4596 this.el.removeClass("x-btn-disabled");
4598 this.disabled = false;
4602 * Convenience function for boolean enable/disable
4603 * @param {Boolean} enabled True to enable, false to disable
4605 setDisabled : function(v){
4606 this[v !== true ? "enable" : "disable"]();
4610 onClick : function(e){
4618 if(this.enableToggle){
4621 if(this.menu && !this.menu.isVisible()){
4622 this.menu.show(this.el, this.menuAlign);
4624 this.fireEvent("click", this, e);
4626 this.el.removeClass("x-btn-over");
4627 this.handler.call(this.scope || this, this, e);
4632 onMouseOver : function(e){
4634 this.el.addClass("x-btn-over");
4635 this.fireEvent('mouseover', this, e);
4639 onMouseOut : function(e){
4640 if(!e.within(this.el, true)){
4641 this.el.removeClass("x-btn-over");
4642 this.fireEvent('mouseout', this, e);
4646 onFocus : function(e){
4648 this.el.addClass("x-btn-focus");
4652 onBlur : function(e){
4653 this.el.removeClass("x-btn-focus");
4656 onMouseDown : function(e){
4657 if(!this.disabled && e.button == 0){
4658 this.el.addClass("x-btn-click");
4659 Roo.get(document).on('mouseup', this.onMouseUp, this);
4663 onMouseUp : function(e){
4665 this.el.removeClass("x-btn-click");
4666 Roo.get(document).un('mouseup', this.onMouseUp, this);
4670 onMenuShow : function(e){
4671 this.el.addClass("x-btn-menu-active");
4674 onMenuHide : function(e){
4675 this.el.removeClass("x-btn-menu-active");
4679 // Private utility class used by Button
4680 Roo.ButtonToggleMgr = function(){
4683 function toggleGroup(btn, state){
4685 var g = groups[btn.toggleGroup];
4686 for(var i = 0, l = g.length; i < l; i++){
4695 register : function(btn){
4696 if(!btn.toggleGroup){
4699 var g = groups[btn.toggleGroup];
4701 g = groups[btn.toggleGroup] = [];
4704 btn.on("toggle", toggleGroup);
4707 unregister : function(btn){
4708 if(!btn.toggleGroup){
4711 var g = groups[btn.toggleGroup];
4714 btn.un("toggle", toggleGroup);
4720 * Ext JS Library 1.1.1
4721 * Copyright(c) 2006-2007, Ext JS, LLC.
4723 * Originally Released Under LGPL - original licence link has changed is not relivant.
4726 * <script type="text/javascript">
4730 * @class Roo.SplitButton
4731 * @extends Roo.Button
4732 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
4733 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
4734 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
4735 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
4736 * @cfg {String} arrowTooltip The title attribute of the arrow
4738 * Create a new menu button
4739 * @param {String/HTMLElement/Element} renderTo The element to append the button to
4740 * @param {Object} config The config object
4742 Roo.SplitButton = function(renderTo, config){
4743 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
4746 * Fires when this button's arrow is clicked
4747 * @param {SplitButton} this
4748 * @param {EventObject} e The click event
4750 this.addEvents({"arrowclick":true});
4753 Roo.extend(Roo.SplitButton, Roo.Button, {
4754 render : function(renderTo){
4755 // this is one sweet looking template!
4756 var tpl = new Roo.Template(
4757 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
4758 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
4759 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
4760 "</tbody></table></td><td>",
4761 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
4762 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
4763 "</tbody></table></td></tr></table>"
4765 var btn = tpl.append(renderTo, [this.text, this.type], true);
4766 var btnEl = btn.child("button");
4768 btn.addClass(this.cls);
4771 btnEl.setStyle('background-image', 'url(' +this.icon +')');
4774 btnEl.addClass(this.iconCls);
4776 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
4780 if(this.handleMouseEvents){
4781 btn.on("mouseover", this.onMouseOver, this);
4782 btn.on("mouseout", this.onMouseOut, this);
4783 btn.on("mousedown", this.onMouseDown, this);
4784 btn.on("mouseup", this.onMouseUp, this);
4786 btn.on(this.clickEvent, this.onClick, this);
4788 if(typeof this.tooltip == 'object'){
4789 Roo.QuickTips.tips(Roo.apply({
4793 btnEl.dom[this.tooltipType] = this.tooltip;
4796 if(this.arrowTooltip){
4797 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
4806 this.el.addClass("x-btn-pressed");
4808 if(Roo.isIE && !Roo.isIE7){
4809 this.autoWidth.defer(1, this);
4814 this.menu.on("show", this.onMenuShow, this);
4815 this.menu.on("hide", this.onMenuHide, this);
4817 this.fireEvent('render', this);
4821 autoWidth : function(){
4823 var tbl = this.el.child("table:first");
4824 var tbl2 = this.el.child("table:last");
4825 this.el.setWidth("auto");
4826 tbl.setWidth("auto");
4827 if(Roo.isIE7 && Roo.isStrict){
4828 var ib = this.el.child('button:first');
4829 if(ib && ib.getWidth() > 20){
4831 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
4836 this.el.beginMeasure();
4838 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
4839 tbl.setWidth(this.minWidth-tbl2.getWidth());
4842 this.el.endMeasure();
4845 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
4849 * Sets this button's click handler
4850 * @param {Function} handler The function to call when the button is clicked
4851 * @param {Object} scope (optional) Scope for the function passed above
4853 setHandler : function(handler, scope){
4854 this.handler = handler;
4859 * Sets this button's arrow click handler
4860 * @param {Function} handler The function to call when the arrow is clicked
4861 * @param {Object} scope (optional) Scope for the function passed above
4863 setArrowHandler : function(handler, scope){
4864 this.arrowHandler = handler;
4873 this.el.child("button:first").focus();
4878 onClick : function(e){
4881 if(e.getTarget(".x-btn-menu-arrow-wrap")){
4882 if(this.menu && !this.menu.isVisible()){
4883 this.menu.show(this.el, this.menuAlign);
4885 this.fireEvent("arrowclick", this, e);
4886 if(this.arrowHandler){
4887 this.arrowHandler.call(this.scope || this, this, e);
4890 this.fireEvent("click", this, e);
4892 this.handler.call(this.scope || this, this, e);
4898 onMouseDown : function(e){
4900 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
4904 onMouseUp : function(e){
4905 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
4911 Roo.MenuButton = Roo.SplitButton;/*
4913 * Ext JS Library 1.1.1
4914 * Copyright(c) 2006-2007, Ext JS, LLC.
4916 * Originally Released Under LGPL - original licence link has changed is not relivant.
4919 * <script type="text/javascript">
4923 * @class Roo.Toolbar
4924 * Basic Toolbar class.
4926 * Creates a new Toolbar
4927 * @param {Object} config The config object
4929 Roo.Toolbar = function(container, buttons, config)
4931 /// old consturctor format still supported..
4932 if(container instanceof Array){ // omit the container for later rendering
4933 buttons = container;
4937 if (typeof(container) == 'object' && container.xtype) {
4939 container = config.container;
4940 buttons = config.buttons; // not really - use items!!
4943 if (config && config.items) {
4944 xitems = config.items;
4945 delete config.items;
4947 Roo.apply(this, config);
4948 this.buttons = buttons;
4951 this.render(container);
4953 Roo.each(xitems, function(b) {
4959 Roo.Toolbar.prototype = {
4961 * @cfg {Roo.data.Store} items
4962 * array of button configs or elements to add
4966 * @cfg {String/HTMLElement/Element} container
4967 * The id or element that will contain the toolbar
4970 render : function(ct){
4971 this.el = Roo.get(ct);
4973 this.el.addClass(this.cls);
4975 // using a table allows for vertical alignment
4976 // 100% width is needed by Safari...
4977 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
4978 this.tr = this.el.child("tr", true);
4980 this.items = new Roo.util.MixedCollection(false, function(o){
4981 return o.id || ("item" + (++autoId));
4984 this.add.apply(this, this.buttons);
4985 delete this.buttons;
4990 * Adds element(s) to the toolbar -- this function takes a variable number of
4991 * arguments of mixed type and adds them to the toolbar.
4992 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
4994 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
4995 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
4996 * <li>Field: Any form field (equivalent to {@link #addField})</li>
4997 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
4998 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
4999 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
5000 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
5001 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
5002 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
5004 * @param {Mixed} arg2
5005 * @param {Mixed} etc.
5008 var a = arguments, l = a.length;
5009 for(var i = 0; i < l; i++){
5014 _add : function(el) {
5017 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
5020 if (el.applyTo){ // some kind of form field
5021 return this.addField(el);
5023 if (el.render){ // some kind of Toolbar.Item
5024 return this.addItem(el);
5026 if (typeof el == "string"){ // string
5027 if(el == "separator" || el == "-"){
5028 return this.addSeparator();
5031 return this.addSpacer();
5034 return this.addFill();
5036 return this.addText(el);
5039 if(el.tagName){ // element
5040 return this.addElement(el);
5042 if(typeof el == "object"){ // must be button config?
5043 return this.addButton(el);
5051 * Add an Xtype element
5052 * @param {Object} xtype Xtype Object
5053 * @return {Object} created Object
5055 addxtype : function(e){
5060 * Returns the Element for this toolbar.
5061 * @return {Roo.Element}
5069 * @return {Roo.Toolbar.Item} The separator item
5071 addSeparator : function(){
5072 return this.addItem(new Roo.Toolbar.Separator());
5076 * Adds a spacer element
5077 * @return {Roo.Toolbar.Spacer} The spacer item
5079 addSpacer : function(){
5080 return this.addItem(new Roo.Toolbar.Spacer());
5084 * Adds a fill element that forces subsequent additions to the right side of the toolbar
5085 * @return {Roo.Toolbar.Fill} The fill item
5087 addFill : function(){
5088 return this.addItem(new Roo.Toolbar.Fill());
5092 * Adds any standard HTML element to the toolbar
5093 * @param {String/HTMLElement/Element} el The element or id of the element to add
5094 * @return {Roo.Toolbar.Item} The element's item
5096 addElement : function(el){
5097 return this.addItem(new Roo.Toolbar.Item(el));
5100 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
5101 * @type Roo.util.MixedCollection
5106 * Adds any Toolbar.Item or subclass
5107 * @param {Roo.Toolbar.Item} item
5108 * @return {Roo.Toolbar.Item} The item
5110 addItem : function(item){
5111 var td = this.nextBlock();
5113 this.items.add(item);
5118 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
5119 * @param {Object/Array} config A button config or array of configs
5120 * @return {Roo.Toolbar.Button/Array}
5122 addButton : function(config){
5123 if(config instanceof Array){
5125 for(var i = 0, len = config.length; i < len; i++) {
5126 buttons.push(this.addButton(config[i]));
5131 if(!(config instanceof Roo.Toolbar.Button)){
5133 new Roo.Toolbar.SplitButton(config) :
5134 new Roo.Toolbar.Button(config);
5136 var td = this.nextBlock();
5143 * Adds text to the toolbar
5144 * @param {String} text The text to add
5145 * @return {Roo.Toolbar.Item} The element's item
5147 addText : function(text){
5148 return this.addItem(new Roo.Toolbar.TextItem(text));
5152 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
5153 * @param {Number} index The index where the item is to be inserted
5154 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
5155 * @return {Roo.Toolbar.Button/Item}
5157 insertButton : function(index, item){
5158 if(item instanceof Array){
5160 for(var i = 0, len = item.length; i < len; i++) {
5161 buttons.push(this.insertButton(index + i, item[i]));
5165 if (!(item instanceof Roo.Toolbar.Button)){
5166 item = new Roo.Toolbar.Button(item);
5168 var td = document.createElement("td");
5169 this.tr.insertBefore(td, this.tr.childNodes[index]);
5171 this.items.insert(index, item);
5176 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
5177 * @param {Object} config
5178 * @return {Roo.Toolbar.Item} The element's item
5180 addDom : function(config, returnEl){
5181 var td = this.nextBlock();
5182 Roo.DomHelper.overwrite(td, config);
5183 var ti = new Roo.Toolbar.Item(td.firstChild);
5190 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
5191 * @type Roo.util.MixedCollection
5196 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
5197 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
5198 * @param {Roo.form.Field} field
5199 * @return {Roo.ToolbarItem}
5203 addField : function(field) {
5206 this.fields = new Roo.util.MixedCollection(false, function(o){
5207 return o.id || ("item" + (++autoId));
5212 var td = this.nextBlock();
5214 var ti = new Roo.Toolbar.Item(td.firstChild);
5217 this.fields.add(field);
5228 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
5229 this.el.child('div').hide();
5237 this.el.child('div').show();
5241 nextBlock : function(){
5242 var td = document.createElement("td");
5243 this.tr.appendChild(td);
5248 destroy : function(){
5249 if(this.items){ // rendered?
5250 Roo.destroy.apply(Roo, this.items.items);
5252 if(this.fields){ // rendered?
5253 Roo.destroy.apply(Roo, this.fields.items);
5255 Roo.Element.uncache(this.el, this.tr);
5260 * @class Roo.Toolbar.Item
5261 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
5263 * Creates a new Item
5264 * @param {HTMLElement} el
5266 Roo.Toolbar.Item = function(el){
5267 this.el = Roo.getDom(el);
5268 this.id = Roo.id(this.el);
5269 this.hidden = false;
5272 Roo.Toolbar.Item.prototype = {
5275 * Get this item's HTML Element
5276 * @return {HTMLElement}
5283 render : function(td){
5285 td.appendChild(this.el);
5289 * Removes and destroys this item.
5291 destroy : function(){
5292 this.td.parentNode.removeChild(this.td);
5299 this.hidden = false;
5300 this.td.style.display = "";
5308 this.td.style.display = "none";
5312 * Convenience function for boolean show/hide.
5313 * @param {Boolean} visible true to show/false to hide
5315 setVisible: function(visible){
5324 * Try to focus this item.
5327 Roo.fly(this.el).focus();
5331 * Disables this item.
5333 disable : function(){
5334 Roo.fly(this.td).addClass("x-item-disabled");
5335 this.disabled = true;
5336 this.el.disabled = true;
5340 * Enables this item.
5342 enable : function(){
5343 Roo.fly(this.td).removeClass("x-item-disabled");
5344 this.disabled = false;
5345 this.el.disabled = false;
5351 * @class Roo.Toolbar.Separator
5352 * @extends Roo.Toolbar.Item
5353 * A simple toolbar separator class
5355 * Creates a new Separator
5357 Roo.Toolbar.Separator = function(){
5358 var s = document.createElement("span");
5359 s.className = "ytb-sep";
5360 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
5362 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
5364 disable:Roo.emptyFn,
5369 * @class Roo.Toolbar.Spacer
5370 * @extends Roo.Toolbar.Item
5371 * A simple element that adds extra horizontal space to a toolbar.
5373 * Creates a new Spacer
5375 Roo.Toolbar.Spacer = function(){
5376 var s = document.createElement("div");
5377 s.className = "ytb-spacer";
5378 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
5380 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
5382 disable:Roo.emptyFn,
5387 * @class Roo.Toolbar.Fill
5388 * @extends Roo.Toolbar.Spacer
5389 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
5391 * Creates a new Spacer
5393 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
5395 render : function(td){
5396 td.style.width = '100%';
5397 Roo.Toolbar.Fill.superclass.render.call(this, td);
5402 * @class Roo.Toolbar.TextItem
5403 * @extends Roo.Toolbar.Item
5404 * A simple class that renders text directly into a toolbar.
5406 * Creates a new TextItem
5407 * @param {String} text
5409 Roo.Toolbar.TextItem = function(text){
5410 if (typeof(text) == 'object') {
5413 var s = document.createElement("span");
5414 s.className = "ytb-text";
5416 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
5418 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
5420 disable:Roo.emptyFn,
5425 * @class Roo.Toolbar.Button
5426 * @extends Roo.Button
5427 * A button that renders into a toolbar.
5429 * Creates a new Button
5430 * @param {Object} config A standard {@link Roo.Button} config object
5432 Roo.Toolbar.Button = function(config){
5433 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
5435 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
5436 render : function(td){
5438 Roo.Toolbar.Button.superclass.render.call(this, td);
5442 * Removes and destroys this button
5444 destroy : function(){
5445 Roo.Toolbar.Button.superclass.destroy.call(this);
5446 this.td.parentNode.removeChild(this.td);
5453 this.hidden = false;
5454 this.td.style.display = "";
5462 this.td.style.display = "none";
5466 * Disables this item
5468 disable : function(){
5469 Roo.fly(this.td).addClass("x-item-disabled");
5470 this.disabled = true;
5476 enable : function(){
5477 Roo.fly(this.td).removeClass("x-item-disabled");
5478 this.disabled = false;
5482 Roo.ToolbarButton = Roo.Toolbar.Button;
5485 * @class Roo.Toolbar.SplitButton
5486 * @extends Roo.SplitButton
5487 * A menu button that renders into a toolbar.
5489 * Creates a new SplitButton
5490 * @param {Object} config A standard {@link Roo.SplitButton} config object
5492 Roo.Toolbar.SplitButton = function(config){
5493 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
5495 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
5496 render : function(td){
5498 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
5502 * Removes and destroys this button
5504 destroy : function(){
5505 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
5506 this.td.parentNode.removeChild(this.td);
5513 this.hidden = false;
5514 this.td.style.display = "";
5522 this.td.style.display = "none";
5527 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
5529 * Ext JS Library 1.1.1
5530 * Copyright(c) 2006-2007, Ext JS, LLC.
5532 * Originally Released Under LGPL - original licence link has changed is not relivant.
5535 * <script type="text/javascript">
5539 * @class Roo.PagingToolbar
5540 * @extends Roo.Toolbar
5541 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
5543 * Create a new PagingToolbar
5544 * @param {Object} config The config object
5546 Roo.PagingToolbar = function(el, ds, config)
5548 // old args format still supported... - xtype is prefered..
5549 if (typeof(el) == 'object' && el.xtype) {
5550 // created from xtype...
5553 el = config.container;
5557 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
5560 this.renderButtons(this.el);
5564 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
5566 * @cfg {Roo.data.Store} dataSource
5567 * The underlying data store providing the paged data
5570 * @cfg {String/HTMLElement/Element} container
5571 * container The id or element that will contain the toolbar
5574 * @cfg {Boolean} displayInfo
5575 * True to display the displayMsg (defaults to false)
5578 * @cfg {Number} pageSize
5579 * The number of records to display per page (defaults to 20)
5583 * @cfg {String} displayMsg
5584 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
5586 displayMsg : 'Displaying {0} - {1} of {2}',
5588 * @cfg {String} emptyMsg
5589 * The message to display when no records are found (defaults to "No data to display")
5591 emptyMsg : 'No data to display',
5593 * Customizable piece of the default paging text (defaults to "Page")
5596 beforePageText : "Page",
5598 * Customizable piece of the default paging text (defaults to "of %0")
5601 afterPageText : "of {0}",
5603 * Customizable piece of the default paging text (defaults to "First Page")
5606 firstText : "First Page",
5608 * Customizable piece of the default paging text (defaults to "Previous Page")
5611 prevText : "Previous Page",
5613 * Customizable piece of the default paging text (defaults to "Next Page")
5616 nextText : "Next Page",
5618 * Customizable piece of the default paging text (defaults to "Last Page")
5621 lastText : "Last Page",
5623 * Customizable piece of the default paging text (defaults to "Refresh")
5626 refreshText : "Refresh",
5629 renderButtons : function(el){
5630 Roo.PagingToolbar.superclass.render.call(this, el);
5631 this.first = this.addButton({
5632 tooltip: this.firstText,
5633 cls: "x-btn-icon x-grid-page-first",
5635 handler: this.onClick.createDelegate(this, ["first"])
5637 this.prev = this.addButton({
5638 tooltip: this.prevText,
5639 cls: "x-btn-icon x-grid-page-prev",
5641 handler: this.onClick.createDelegate(this, ["prev"])
5643 this.addSeparator();
5644 this.add(this.beforePageText);
5645 this.field = Roo.get(this.addDom({
5650 cls: "x-grid-page-number"
5652 this.field.on("keydown", this.onPagingKeydown, this);
5653 this.field.on("focus", function(){this.dom.select();});
5654 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
5655 this.field.setHeight(18);
5656 this.addSeparator();
5657 this.next = this.addButton({
5658 tooltip: this.nextText,
5659 cls: "x-btn-icon x-grid-page-next",
5661 handler: this.onClick.createDelegate(this, ["next"])
5663 this.last = this.addButton({
5664 tooltip: this.lastText,
5665 cls: "x-btn-icon x-grid-page-last",
5667 handler: this.onClick.createDelegate(this, ["last"])
5669 this.addSeparator();
5670 this.loading = this.addButton({
5671 tooltip: this.refreshText,
5672 cls: "x-btn-icon x-grid-loading",
5673 handler: this.onClick.createDelegate(this, ["refresh"])
5676 if(this.displayInfo){
5677 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
5682 updateInfo : function(){
5684 var count = this.ds.getCount();
5685 var msg = count == 0 ?
5689 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
5691 this.displayEl.update(msg);
5696 onLoad : function(ds, r, o){
5697 this.cursor = o.params ? o.params.start : 0;
5698 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
5700 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
5701 this.field.dom.value = ap;
5702 this.first.setDisabled(ap == 1);
5703 this.prev.setDisabled(ap == 1);
5704 this.next.setDisabled(ap == ps);
5705 this.last.setDisabled(ap == ps);
5706 this.loading.enable();
5711 getPageData : function(){
5712 var total = this.ds.getTotalCount();
5715 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
5716 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
5721 onLoadError : function(){
5722 this.loading.enable();
5726 onPagingKeydown : function(e){
5728 var d = this.getPageData();
5730 var v = this.field.dom.value, pageNum;
5731 if(!v || isNaN(pageNum = parseInt(v, 10))){
5732 this.field.dom.value = d.activePage;
5735 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
5736 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
5739 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))
5741 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
5742 this.field.dom.value = pageNum;
5743 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
5746 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
5748 var v = this.field.dom.value, pageNum;
5749 var increment = (e.shiftKey) ? 10 : 1;
5750 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
5752 if(!v || isNaN(pageNum = parseInt(v, 10))) {
5753 this.field.dom.value = d.activePage;
5756 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
5758 this.field.dom.value = parseInt(v, 10) + increment;
5759 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
5760 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
5767 beforeLoad : function(){
5769 this.loading.disable();
5774 onClick : function(which){
5778 ds.load({params:{start: 0, limit: this.pageSize}});
5781 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
5784 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
5787 var total = ds.getTotalCount();
5788 var extra = total % this.pageSize;
5789 var lastStart = extra ? (total - extra) : total-this.pageSize;
5790 ds.load({params:{start: lastStart, limit: this.pageSize}});
5793 ds.load({params:{start: this.cursor, limit: this.pageSize}});
5799 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
5800 * @param {Roo.data.Store} store The data store to unbind
5802 unbind : function(ds){
5803 ds.un("beforeload", this.beforeLoad, this);
5804 ds.un("load", this.onLoad, this);
5805 ds.un("loadexception", this.onLoadError, this);
5806 ds.un("remove", this.updateInfo, this);
5807 ds.un("add", this.updateInfo, this);
5808 this.ds = undefined;
5812 * Binds the paging toolbar to the specified {@link Roo.data.Store}
5813 * @param {Roo.data.Store} store The data store to bind
5815 bind : function(ds){
5816 ds.on("beforeload", this.beforeLoad, this);
5817 ds.on("load", this.onLoad, this);
5818 ds.on("loadexception", this.onLoadError, this);
5819 ds.on("remove", this.updateInfo, this);
5820 ds.on("add", this.updateInfo, this);
5825 * Ext JS Library 1.1.1
5826 * Copyright(c) 2006-2007, Ext JS, LLC.
5828 * Originally Released Under LGPL - original licence link has changed is not relivant.
5831 * <script type="text/javascript">
5835 * @class Roo.Resizable
5836 * @extends Roo.util.Observable
5837 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
5838 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
5839 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
5840 * the element will be wrapped for you automatically.</p>
5841 * <p>Here is the list of valid resize handles:</p>
5844 ------ -------------------
5855 * <p>Here's an example showing the creation of a typical Resizable:</p>
5857 var resizer = new Roo.Resizable("element-id", {
5865 resizer.on("resize", myHandler);
5867 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
5868 * resizer.east.setDisplayed(false);</p>
5869 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
5870 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
5871 * resize operation's new size (defaults to [0, 0])
5872 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
5873 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
5874 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
5875 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
5876 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
5877 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
5878 * @cfg {Number} width The width of the element in pixels (defaults to null)
5879 * @cfg {Number} height The height of the element in pixels (defaults to null)
5880 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
5881 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
5882 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
5883 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
5884 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
5885 * in favor of the handles config option (defaults to false)
5886 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
5887 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
5888 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
5889 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
5890 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
5891 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
5892 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
5893 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
5894 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
5895 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
5896 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
5898 * Create a new resizable component
5899 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
5900 * @param {Object} config configuration options
5902 Roo.Resizable = function(el, config){
5903 this.el = Roo.get(el);
5905 if(config && config.wrap){
5906 config.resizeChild = this.el;
5907 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
5908 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
5909 this.el.setStyle("overflow", "hidden");
5910 this.el.setPositioning(config.resizeChild.getPositioning());
5911 config.resizeChild.clearPositioning();
5912 if(!config.width || !config.height){
5913 var csize = config.resizeChild.getSize();
5914 this.el.setSize(csize.width, csize.height);
5916 if(config.pinned && !config.adjustments){
5917 config.adjustments = "auto";
5921 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
5922 this.proxy.unselectable();
5923 this.proxy.enableDisplayMode('block');
5925 Roo.apply(this, config);
5928 this.disableTrackOver = true;
5929 this.el.addClass("x-resizable-pinned");
5931 // if the element isn't positioned, make it relative
5932 var position = this.el.getStyle("position");
5933 if(position != "absolute" && position != "fixed"){
5934 this.el.setStyle("position", "relative");
5936 if(!this.handles){ // no handles passed, must be legacy style
5937 this.handles = 's,e,se';
5938 if(this.multiDirectional){
5939 this.handles += ',n,w';
5942 if(this.handles == "all"){
5943 this.handles = "n s e w ne nw se sw";
5945 var hs = this.handles.split(/\s*?[,;]\s*?| /);
5946 var ps = Roo.Resizable.positions;
5947 for(var i = 0, len = hs.length; i < len; i++){
5948 if(hs[i] && ps[hs[i]]){
5949 var pos = ps[hs[i]];
5950 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
5954 this.corner = this.southeast;
5956 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
5957 this.updateBox = true;
5960 this.activeHandle = null;
5962 if(this.resizeChild){
5963 if(typeof this.resizeChild == "boolean"){
5964 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
5966 this.resizeChild = Roo.get(this.resizeChild, true);
5970 if(this.adjustments == "auto"){
5971 var rc = this.resizeChild;
5972 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
5973 if(rc && (hw || hn)){
5974 rc.position("relative");
5975 rc.setLeft(hw ? hw.el.getWidth() : 0);
5976 rc.setTop(hn ? hn.el.getHeight() : 0);
5978 this.adjustments = [
5979 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
5980 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
5985 this.dd = this.dynamic ?
5986 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
5987 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
5993 * @event beforeresize
5994 * Fired before resize is allowed. Set enabled to false to cancel resize.
5995 * @param {Roo.Resizable} this
5996 * @param {Roo.EventObject} e The mousedown event
5998 "beforeresize" : true,
6001 * Fired after a resize.
6002 * @param {Roo.Resizable} this
6003 * @param {Number} width The new width
6004 * @param {Number} height The new height
6005 * @param {Roo.EventObject} e The mouseup event
6010 if(this.width !== null && this.height !== null){
6011 this.resizeTo(this.width, this.height);
6013 this.updateChildSize();
6016 this.el.dom.style.zoom = 1;
6018 Roo.Resizable.superclass.constructor.call(this);
6021 Roo.extend(Roo.Resizable, Roo.util.Observable, {
6022 resizeChild : false,
6023 adjustments : [0, 0],
6033 multiDirectional : false,
6034 disableTrackOver : false,
6035 easing : 'easeOutStrong',
6037 heightIncrement : 0,
6041 preserveRatio : false,
6048 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
6050 constrainTo: undefined,
6052 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
6054 resizeRegion: undefined,
6058 * Perform a manual resize
6059 * @param {Number} width
6060 * @param {Number} height
6062 resizeTo : function(width, height){
6063 this.el.setSize(width, height);
6064 this.updateChildSize();
6065 this.fireEvent("resize", this, width, height, null);
6069 startSizing : function(e, handle){
6070 this.fireEvent("beforeresize", this, e);
6071 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
6074 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
6075 this.overlay.unselectable();
6076 this.overlay.enableDisplayMode("block");
6077 this.overlay.on("mousemove", this.onMouseMove, this);
6078 this.overlay.on("mouseup", this.onMouseUp, this);
6080 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
6082 this.resizing = true;
6083 this.startBox = this.el.getBox();
6084 this.startPoint = e.getXY();
6085 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
6086 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
6088 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
6089 this.overlay.show();
6091 if(this.constrainTo) {
6092 var ct = Roo.get(this.constrainTo);
6093 this.resizeRegion = ct.getRegion().adjust(
6094 ct.getFrameWidth('t'),
6095 ct.getFrameWidth('l'),
6096 -ct.getFrameWidth('b'),
6097 -ct.getFrameWidth('r')
6101 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
6103 this.proxy.setBox(this.startBox);
6105 this.proxy.setStyle('visibility', 'visible');
6111 onMouseDown : function(handle, e){
6114 this.activeHandle = handle;
6115 this.startSizing(e, handle);
6120 onMouseUp : function(e){
6121 var size = this.resizeElement();
6122 this.resizing = false;
6124 this.overlay.hide();
6126 this.fireEvent("resize", this, size.width, size.height, e);
6130 updateChildSize : function(){
6131 if(this.resizeChild){
6133 var child = this.resizeChild;
6134 var adj = this.adjustments;
6135 if(el.dom.offsetWidth){
6136 var b = el.getSize(true);
6137 child.setSize(b.width+adj[0], b.height+adj[1]);
6139 // Second call here for IE
6140 // The first call enables instant resizing and
6141 // the second call corrects scroll bars if they
6144 setTimeout(function(){
6145 if(el.dom.offsetWidth){
6146 var b = el.getSize(true);
6147 child.setSize(b.width+adj[0], b.height+adj[1]);
6155 snap : function(value, inc, min){
6156 if(!inc || !value) return value;
6157 var newValue = value;
6158 var m = value % inc;
6161 newValue = value + (inc-m);
6163 newValue = value - m;
6166 return Math.max(min, newValue);
6170 resizeElement : function(){
6171 var box = this.proxy.getBox();
6173 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
6175 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
6177 this.updateChildSize();
6185 constrain : function(v, diff, m, mx){
6188 }else if(v - diff > mx){
6195 onMouseMove : function(e){
6197 try{// try catch so if something goes wrong the user doesn't get hung
6199 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
6203 //var curXY = this.startPoint;
6204 var curSize = this.curSize || this.startBox;
6205 var x = this.startBox.x, y = this.startBox.y;
6207 var w = curSize.width, h = curSize.height;
6209 var mw = this.minWidth, mh = this.minHeight;
6210 var mxw = this.maxWidth, mxh = this.maxHeight;
6211 var wi = this.widthIncrement;
6212 var hi = this.heightIncrement;
6214 var eventXY = e.getXY();
6215 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
6216 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
6218 var pos = this.activeHandle.position;
6223 w = Math.min(Math.max(mw, w), mxw);
6227 h = Math.min(Math.max(mh, h), mxh);
6232 w = Math.min(Math.max(mw, w), mxw);
6233 h = Math.min(Math.max(mh, h), mxh);
6236 diffY = this.constrain(h, diffY, mh, mxh);
6241 diffX = this.constrain(w, diffX, mw, mxw);
6247 w = Math.min(Math.max(mw, w), mxw);
6248 diffY = this.constrain(h, diffY, mh, mxh);
6253 diffX = this.constrain(w, diffX, mw, mxw);
6254 diffY = this.constrain(h, diffY, mh, mxh);
6261 diffX = this.constrain(w, diffX, mw, mxw);
6263 h = Math.min(Math.max(mh, h), mxh);
6269 var sw = this.snap(w, wi, mw);
6270 var sh = this.snap(h, hi, mh);
6271 if(sw != w || sh != h){
6294 if(this.preserveRatio){
6299 h = Math.min(Math.max(mh, h), mxh);
6304 w = Math.min(Math.max(mw, w), mxw);
6309 w = Math.min(Math.max(mw, w), mxw);
6315 w = Math.min(Math.max(mw, w), mxw);
6321 h = Math.min(Math.max(mh, h), mxh);
6329 h = Math.min(Math.max(mh, h), mxh);
6339 h = Math.min(Math.max(mh, h), mxh);
6347 this.proxy.setBounds(x, y, w, h);
6349 this.resizeElement();
6356 handleOver : function(){
6358 this.el.addClass("x-resizable-over");
6363 handleOut : function(){
6365 this.el.removeClass("x-resizable-over");
6370 * Returns the element this component is bound to.
6371 * @return {Roo.Element}
6378 * Returns the resizeChild element (or null).
6379 * @return {Roo.Element}
6381 getResizeChild : function(){
6382 return this.resizeChild;
6386 * Destroys this resizable. If the element was wrapped and
6387 * removeEl is not true then the element remains.
6388 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
6390 destroy : function(removeEl){
6391 this.proxy.remove();
6393 this.overlay.removeAllListeners();
6394 this.overlay.remove();
6396 var ps = Roo.Resizable.positions;
6398 if(typeof ps[k] != "function" && this[ps[k]]){
6399 var h = this[ps[k]];
6400 h.el.removeAllListeners();
6412 // hash to map config positions to true positions
6413 Roo.Resizable.positions = {
6414 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast"
6418 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
6420 // only initialize the template if resizable is used
6421 var tpl = Roo.DomHelper.createTemplate(
6422 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
6425 Roo.Resizable.Handle.prototype.tpl = tpl;
6427 this.position = pos;
6429 this.el = this.tpl.append(rz.el.dom, [this.position], true);
6430 this.el.unselectable();
6432 this.el.setOpacity(0);
6434 this.el.on("mousedown", this.onMouseDown, this);
6435 if(!disableTrackOver){
6436 this.el.on("mouseover", this.onMouseOver, this);
6437 this.el.on("mouseout", this.onMouseOut, this);
6442 Roo.Resizable.Handle.prototype = {
6443 afterResize : function(rz){
6447 onMouseDown : function(e){
6448 this.rz.onMouseDown(this, e);
6451 onMouseOver : function(e){
6452 this.rz.handleOver(this, e);
6455 onMouseOut : function(e){
6456 this.rz.handleOut(this, e);
6460 * Ext JS Library 1.1.1
6461 * Copyright(c) 2006-2007, Ext JS, LLC.
6463 * Originally Released Under LGPL - original licence link has changed is not relivant.
6466 * <script type="text/javascript">
6471 * @extends Roo.Component
6472 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
6474 * Create a new Editor
6475 * @param {Roo.form.Field} field The Field object (or descendant)
6476 * @param {Object} config The config object
6478 Roo.Editor = function(field, config){
6479 Roo.Editor.superclass.constructor.call(this, config);
6483 * @event beforestartedit
6484 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
6485 * false from the handler of this event.
6486 * @param {Editor} this
6487 * @param {Roo.Element} boundEl The underlying element bound to this editor
6488 * @param {Mixed} value The field value being set
6490 "beforestartedit" : true,
6493 * Fires when this editor is displayed
6494 * @param {Roo.Element} boundEl The underlying element bound to this editor
6495 * @param {Mixed} value The starting field value
6499 * @event beforecomplete
6500 * Fires after a change has been made to the field, but before the change is reflected in the underlying
6501 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
6502 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
6503 * event will not fire since no edit actually occurred.
6504 * @param {Editor} this
6505 * @param {Mixed} value The current field value
6506 * @param {Mixed} startValue The original field value
6508 "beforecomplete" : true,
6511 * Fires after editing is complete and any changed value has been written to the underlying field.
6512 * @param {Editor} this
6513 * @param {Mixed} value The current field value
6514 * @param {Mixed} startValue The original field value
6519 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6520 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6521 * @param {Roo.form.Field} this
6522 * @param {Roo.EventObject} e The event object
6528 Roo.extend(Roo.Editor, Roo.Component, {
6530 * @cfg {Boolean/String} autosize
6531 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
6532 * or "height" to adopt the height only (defaults to false)
6535 * @cfg {Boolean} revertInvalid
6536 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
6537 * validation fails (defaults to true)
6540 * @cfg {Boolean} ignoreNoChange
6541 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
6542 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
6543 * will never be ignored.
6546 * @cfg {Boolean} hideEl
6547 * False to keep the bound element visible while the editor is displayed (defaults to true)
6550 * @cfg {Mixed} value
6551 * The data value of the underlying field (defaults to "")
6555 * @cfg {String} alignment
6556 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
6560 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
6561 * for bottom-right shadow (defaults to "frame")
6565 * @cfg {Boolean} constrain True to constrain the editor to the viewport
6569 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
6571 completeOnEnter : false,
6573 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
6575 cancelOnEsc : false,
6577 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
6582 onRender : function(ct, position){
6583 this.el = new Roo.Layer({
6584 shadow: this.shadow,
6590 constrain: this.constrain
6592 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
6593 if(this.field.msgTarget != 'title'){
6594 this.field.msgTarget = 'qtip';
6596 this.field.render(this.el);
6598 this.field.el.dom.setAttribute('autocomplete', 'off');
6600 this.field.on("specialkey", this.onSpecialKey, this);
6601 if(this.swallowKeys){
6602 this.field.el.swallowEvent(['keydown','keypress']);
6605 this.field.on("blur", this.onBlur, this);
6606 if(this.field.grow){
6607 this.field.on("autosize", this.el.sync, this.el, {delay:1});
6611 onSpecialKey : function(field, e){
6612 if(this.completeOnEnter && e.getKey() == e.ENTER){
6614 this.completeEdit();
6615 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
6618 this.fireEvent('specialkey', field, e);
6623 * Starts the editing process and shows the editor.
6624 * @param {String/HTMLElement/Element} el The element to edit
6625 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
6626 * to the innerHTML of el.
6628 startEdit : function(el, value){
6630 this.completeEdit();
6632 this.boundEl = Roo.get(el);
6633 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
6635 this.render(this.parentEl || document.body);
6637 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
6640 this.startValue = v;
6641 this.field.setValue(v);
6643 var sz = this.boundEl.getSize();
6644 switch(this.autoSize){
6646 this.setSize(sz.width, "");
6649 this.setSize("", sz.height);
6652 this.setSize(sz.width, sz.height);
6655 this.el.alignTo(this.boundEl, this.alignment);
6656 this.editing = true;
6658 Roo.QuickTips.disable();
6664 * Sets the height and width of this editor.
6665 * @param {Number} width The new width
6666 * @param {Number} height The new height
6668 setSize : function(w, h){
6669 this.field.setSize(w, h);
6676 * Realigns the editor to the bound field based on the current alignment config value.
6678 realign : function(){
6679 this.el.alignTo(this.boundEl, this.alignment);
6683 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
6684 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
6686 completeEdit : function(remainVisible){
6690 var v = this.getValue();
6691 if(this.revertInvalid !== false && !this.field.isValid()){
6692 v = this.startValue;
6693 this.cancelEdit(true);
6695 if(String(v) === String(this.startValue) && this.ignoreNoChange){
6696 this.editing = false;
6700 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
6701 this.editing = false;
6702 if(this.updateEl && this.boundEl){
6703 this.boundEl.update(v);
6705 if(remainVisible !== true){
6708 this.fireEvent("complete", this, v, this.startValue);
6713 onShow : function(){
6715 if(this.hideEl !== false){
6716 this.boundEl.hide();
6719 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
6720 this.fixIEFocus = true;
6721 this.deferredFocus.defer(50, this);
6725 this.fireEvent("startedit", this.boundEl, this.startValue);
6728 deferredFocus : function(){
6735 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
6736 * reverted to the original starting value.
6737 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
6738 * cancel (defaults to false)
6740 cancelEdit : function(remainVisible){
6742 this.setValue(this.startValue);
6743 if(remainVisible !== true){
6750 onBlur : function(){
6751 if(this.allowBlur !== true && this.editing){
6752 this.completeEdit();
6757 onHide : function(){
6759 this.completeEdit();
6763 if(this.field.collapse){
6764 this.field.collapse();
6767 if(this.hideEl !== false){
6768 this.boundEl.show();
6771 Roo.QuickTips.enable();
6776 * Sets the data value of the editor
6777 * @param {Mixed} value Any valid value supported by the underlying field
6779 setValue : function(v){
6780 this.field.setValue(v);
6784 * Gets the data value of the editor
6785 * @return {Mixed} The data value
6787 getValue : function(){
6788 return this.field.getValue();
6792 * Ext JS Library 1.1.1
6793 * Copyright(c) 2006-2007, Ext JS, LLC.
6795 * Originally Released Under LGPL - original licence link has changed is not relivant.
6798 * <script type="text/javascript">
6802 * @class Roo.BasicDialog
6803 * @extends Roo.util.Observable
6804 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
6806 var dlg = new Roo.BasicDialog("my-dlg", {
6815 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
6816 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
6817 dlg.addButton('Cancel', dlg.hide, dlg);
6820 <b>A Dialog should always be a direct child of the body element.</b>
6821 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
6822 * @cfg {String} title Default text to display in the title bar (defaults to null)
6823 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
6824 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
6825 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
6826 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
6827 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
6828 * (defaults to null with no animation)
6829 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
6830 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
6831 * property for valid values (defaults to 'all')
6832 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
6833 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
6834 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
6835 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
6836 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
6837 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
6838 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
6839 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
6840 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
6841 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
6842 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
6843 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
6844 * draggable = true (defaults to false)
6845 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
6846 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6847 * shadow (defaults to false)
6848 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
6849 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
6850 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
6851 * @cfg {Array} buttons Array of buttons
6852 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
6854 * Create a new BasicDialog.
6855 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
6856 * @param {Object} config Configuration options
6858 Roo.BasicDialog = function(el, config){
6859 this.el = Roo.get(el);
6860 var dh = Roo.DomHelper;
6861 if(!this.el && config && config.autoCreate){
6862 if(typeof config.autoCreate == "object"){
6863 if(!config.autoCreate.id){
6864 config.autoCreate.id = el;
6866 this.el = dh.append(document.body,
6867 config.autoCreate, true);
6869 this.el = dh.append(document.body,
6870 {tag: "div", id: el, style:'visibility:hidden;'}, true);
6874 el.setDisplayed(true);
6875 el.hide = this.hideAction;
6877 el.addClass("x-dlg");
6879 Roo.apply(this, config);
6881 this.proxy = el.createProxy("x-dlg-proxy");
6882 this.proxy.hide = this.hideAction;
6883 this.proxy.setOpacity(.5);
6887 el.setWidth(config.width);
6890 el.setHeight(config.height);
6892 this.size = el.getSize();
6893 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
6894 this.xy = [config.x,config.y];
6896 this.xy = el.getCenterXY(true);
6898 /** The header element @type Roo.Element */
6899 this.header = el.child("> .x-dlg-hd");
6900 /** The body element @type Roo.Element */
6901 this.body = el.child("> .x-dlg-bd");
6902 /** The footer element @type Roo.Element */
6903 this.footer = el.child("> .x-dlg-ft");
6906 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
6909 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
6912 this.header.unselectable();
6914 this.header.update(this.title);
6916 // this element allows the dialog to be focused for keyboard event
6917 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
6918 this.focusEl.swallowEvent("click", true);
6920 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
6922 // wrap the body and footer for special rendering
6923 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
6925 this.bwrap.dom.appendChild(this.footer.dom);
6928 this.bg = this.el.createChild({
6929 tag: "div", cls:"x-dlg-bg",
6930 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
6932 this.centerBg = this.bg.child("div.x-dlg-bg-center");
6935 if(this.autoScroll !== false && !this.autoTabs){
6936 this.body.setStyle("overflow", "auto");
6939 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
6941 if(this.closable !== false){
6942 this.el.addClass("x-dlg-closable");
6943 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
6944 this.close.on("click", this.closeClick, this);
6945 this.close.addClassOnOver("x-dlg-close-over");
6947 if(this.collapsible !== false){
6948 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
6949 this.collapseBtn.on("click", this.collapseClick, this);
6950 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
6951 this.header.on("dblclick", this.collapseClick, this);
6953 if(this.resizable !== false){
6954 this.el.addClass("x-dlg-resizable");
6955 this.resizer = new Roo.Resizable(el, {
6956 minWidth: this.minWidth || 80,
6957 minHeight:this.minHeight || 80,
6958 handles: this.resizeHandles || "all",
6961 this.resizer.on("beforeresize", this.beforeResize, this);
6962 this.resizer.on("resize", this.onResize, this);
6964 if(this.draggable !== false){
6965 el.addClass("x-dlg-draggable");
6966 if (!this.proxyDrag) {
6967 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
6970 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
6972 dd.setHandleElId(this.header.id);
6973 dd.endDrag = this.endMove.createDelegate(this);
6974 dd.startDrag = this.startMove.createDelegate(this);
6975 dd.onDrag = this.onDrag.createDelegate(this);
6980 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
6981 this.mask.enableDisplayMode("block");
6983 this.el.addClass("x-dlg-modal");
6986 this.shadow = new Roo.Shadow({
6987 mode : typeof this.shadow == "string" ? this.shadow : "sides",
6988 offset : this.shadowOffset
6991 this.shadowOffset = 0;
6993 if(Roo.useShims && this.shim !== false){
6994 this.shim = this.el.createShim();
6995 this.shim.hide = this.hideAction;
7004 var bts= this.buttons;
7006 Roo.each(bts, function(b) {
7015 * Fires when a key is pressed
7016 * @param {Roo.BasicDialog} this
7017 * @param {Roo.EventObject} e
7022 * Fires when this dialog is moved by the user.
7023 * @param {Roo.BasicDialog} this
7024 * @param {Number} x The new page X
7025 * @param {Number} y The new page Y
7030 * Fires when this dialog is resized by the user.
7031 * @param {Roo.BasicDialog} this
7032 * @param {Number} width The new width
7033 * @param {Number} height The new height
7038 * Fires before this dialog is hidden.
7039 * @param {Roo.BasicDialog} this
7041 "beforehide" : true,
7044 * Fires when this dialog is hidden.
7045 * @param {Roo.BasicDialog} this
7050 * Fires before this dialog is shown.
7051 * @param {Roo.BasicDialog} this
7053 "beforeshow" : true,
7056 * Fires when this dialog is shown.
7057 * @param {Roo.BasicDialog} this
7061 el.on("keydown", this.onKeyDown, this);
7062 el.on("mousedown", this.toFront, this);
7063 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
7065 Roo.DialogManager.register(this);
7066 Roo.BasicDialog.superclass.constructor.call(this);
7069 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
7070 shadowOffset: Roo.isIE ? 6 : 5,
7074 defaultButton: null,
7075 buttonAlign: "right",
7080 * Sets the dialog title text
7081 * @param {String} text The title text to display
7082 * @return {Roo.BasicDialog} this
7084 setTitle : function(text){
7085 this.header.update(text);
7090 closeClick : function(){
7095 collapseClick : function(){
7096 this[this.collapsed ? "expand" : "collapse"]();
7100 * Collapses the dialog to its minimized state (only the title bar is visible).
7101 * Equivalent to the user clicking the collapse dialog button.
7103 collapse : function(){
7104 if(!this.collapsed){
7105 this.collapsed = true;
7106 this.el.addClass("x-dlg-collapsed");
7107 this.restoreHeight = this.el.getHeight();
7108 this.resizeTo(this.el.getWidth(), this.header.getHeight());
7113 * Expands a collapsed dialog back to its normal state. Equivalent to the user
7114 * clicking the expand dialog button.
7116 expand : function(){
7118 this.collapsed = false;
7119 this.el.removeClass("x-dlg-collapsed");
7120 this.resizeTo(this.el.getWidth(), this.restoreHeight);
7125 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
7126 * @return {Roo.TabPanel} The tabs component
7128 initTabs : function(){
7129 var tabs = this.getTabs();
7130 while(tabs.getTab(0)){
7133 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
7135 tabs.addTab(Roo.id(dom), dom.title);
7143 beforeResize : function(){
7144 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
7148 onResize : function(){
7150 this.syncBodyHeight();
7151 this.adjustAssets();
7153 this.fireEvent("resize", this, this.size.width, this.size.height);
7157 onKeyDown : function(e){
7158 if(this.isVisible()){
7159 this.fireEvent("keydown", this, e);
7164 * Resizes the dialog.
7165 * @param {Number} width
7166 * @param {Number} height
7167 * @return {Roo.BasicDialog} this
7169 resizeTo : function(width, height){
7170 this.el.setSize(width, height);
7171 this.size = {width: width, height: height};
7172 this.syncBodyHeight();
7173 if(this.fixedcenter){
7176 if(this.isVisible()){
7178 this.adjustAssets();
7180 this.fireEvent("resize", this, width, height);
7186 * Resizes the dialog to fit the specified content size.
7187 * @param {Number} width
7188 * @param {Number} height
7189 * @return {Roo.BasicDialog} this
7191 setContentSize : function(w, h){
7192 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
7193 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
7194 //if(!this.el.isBorderBox()){
7195 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
7196 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
7199 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
7200 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
7202 this.resizeTo(w, h);
7207 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
7208 * executed in response to a particular key being pressed while the dialog is active.
7209 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
7210 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
7211 * @param {Function} fn The function to call
7212 * @param {Object} scope (optional) The scope of the function
7213 * @return {Roo.BasicDialog} this
7215 addKeyListener : function(key, fn, scope){
7216 var keyCode, shift, ctrl, alt;
7217 if(typeof key == "object" && !(key instanceof Array)){
7218 keyCode = key["key"];
7219 shift = key["shift"];
7225 var handler = function(dlg, e){
7226 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
7228 if(keyCode instanceof Array){
7229 for(var i = 0, len = keyCode.length; i < len; i++){
7230 if(keyCode[i] == k){
7231 fn.call(scope || window, dlg, k, e);
7237 fn.call(scope || window, dlg, k, e);
7242 this.on("keydown", handler);
7247 * Returns the TabPanel component (creates it if it doesn't exist).
7248 * Note: If you wish to simply check for the existence of tabs without creating them,
7249 * check for a null 'tabs' property.
7250 * @return {Roo.TabPanel} The tabs component
7252 getTabs : function(){
7254 this.el.addClass("x-dlg-auto-tabs");
7255 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
7256 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
7262 * Adds a button to the footer section of the dialog.
7263 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
7264 * object or a valid Roo.DomHelper element config
7265 * @param {Function} handler The function called when the button is clicked
7266 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
7267 * @return {Roo.Button} The new button
7269 addButton : function(config, handler, scope){
7270 var dh = Roo.DomHelper;
7272 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
7274 if(!this.btnContainer){
7275 var tb = this.footer.createChild({
7277 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
7278 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
7280 this.btnContainer = tb.firstChild.firstChild.firstChild;
7285 minWidth: this.minButtonWidth,
7288 if(typeof config == "string"){
7289 bconfig.text = config;
7292 bconfig.dhconfig = config;
7294 Roo.apply(bconfig, config);
7298 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
7299 bconfig.position = Math.max(0, bconfig.position);
7300 fc = this.btnContainer.childNodes[bconfig.position];
7303 var btn = new Roo.Button(
7305 this.btnContainer.insertBefore(document.createElement("td"),fc)
7306 : this.btnContainer.appendChild(document.createElement("td")),
7307 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
7310 this.syncBodyHeight();
7313 * Array of all the buttons that have been added to this dialog via addButton
7318 this.buttons.push(btn);
7323 * Sets the default button to be focused when the dialog is displayed.
7324 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
7325 * @return {Roo.BasicDialog} this
7327 setDefaultButton : function(btn){
7328 this.defaultButton = btn;
7333 getHeaderFooterHeight : function(safe){
7336 height += this.header.getHeight();
7339 var fm = this.footer.getMargins();
7340 height += (this.footer.getHeight()+fm.top+fm.bottom);
7342 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
7343 height += this.centerBg.getPadding("tb");
7348 syncBodyHeight : function(){
7349 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
7350 var height = this.size.height - this.getHeaderFooterHeight(false);
7351 bd.setHeight(height-bd.getMargins("tb"));
7352 var hh = this.header.getHeight();
7353 var h = this.size.height-hh;
7355 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
7356 bw.setHeight(h-cb.getPadding("tb"));
7357 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
7358 bd.setWidth(bw.getWidth(true));
7360 this.tabs.syncHeight();
7362 this.tabs.el.repaint();
7368 * Restores the previous state of the dialog if Roo.state is configured.
7369 * @return {Roo.BasicDialog} this
7371 restoreState : function(){
7372 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
7373 if(box && box.width){
7374 this.xy = [box.x, box.y];
7375 this.resizeTo(box.width, box.height);
7381 beforeShow : function(){
7383 if(this.fixedcenter){
7384 this.xy = this.el.getCenterXY(true);
7387 Roo.get(document.body).addClass("x-body-masked");
7388 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
7395 animShow : function(){
7396 var b = Roo.get(this.animateTarget, true).getBox();
7397 this.proxy.setSize(b.width, b.height);
7398 this.proxy.setLocation(b.x, b.y);
7400 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
7401 true, .35, this.showEl.createDelegate(this));
7406 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
7407 * @return {Roo.BasicDialog} this
7409 show : function(animateTarget){
7410 if (this.fireEvent("beforeshow", this) === false){
7413 if(this.syncHeightBeforeShow){
7414 this.syncBodyHeight();
7415 }else if(this.firstShow){
7416 this.firstShow = false;
7417 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
7419 this.animateTarget = animateTarget || this.animateTarget;
7420 if(!this.el.isVisible()){
7422 if(this.animateTarget){
7432 showEl : function(){
7434 this.el.setXY(this.xy);
7436 this.adjustAssets(true);
7439 // IE peekaboo bug - fix found by Dave Fenwick
7443 this.fireEvent("show", this);
7447 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
7448 * dialog itself will receive focus.
7451 if(this.defaultButton){
7452 this.defaultButton.focus();
7454 this.focusEl.focus();
7459 constrainXY : function(){
7460 if(this.constraintoviewport !== false){
7463 var s = this.container.getSize();
7464 this.viewSize = [s.width, s.height];
7466 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
7469 var s = Roo.get(this.container||document).getScroll();
7471 var x = this.xy[0], y = this.xy[1];
7472 var w = this.size.width, h = this.size.height;
7473 var vw = this.viewSize[0], vh = this.viewSize[1];
7474 // only move it if it needs it
7476 // first validate right/bottom
7477 if(x + w > vw+s.left){
7481 if(y + h > vh+s.top){
7485 // then make sure top/left isn't negative
7497 if(this.isVisible()){
7498 this.el.setLocation(x, y);
7499 this.adjustAssets();
7506 onDrag : function(){
7507 if(!this.proxyDrag){
7508 this.xy = this.el.getXY();
7509 this.adjustAssets();
7514 adjustAssets : function(doShow){
7515 var x = this.xy[0], y = this.xy[1];
7516 var w = this.size.width, h = this.size.height;
7517 if(doShow === true){
7519 this.shadow.show(this.el);
7525 if(this.shadow && this.shadow.isVisible()){
7526 this.shadow.show(this.el);
7528 if(this.shim && this.shim.isVisible()){
7529 this.shim.setBounds(x, y, w, h);
7534 adjustViewport : function(w, h){
7536 w = Roo.lib.Dom.getViewWidth();
7537 h = Roo.lib.Dom.getViewHeight();
7540 this.viewSize = [w, h];
7541 if(this.modal && this.mask.isVisible()){
7542 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
7543 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
7545 if(this.isVisible()){
7551 * Destroys this dialog and all its supporting elements (including any tabs, shim,
7552 * shadow, proxy, mask, etc.) Also removes all event listeners.
7553 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
7555 destroy : function(removeEl){
7556 if(this.isVisible()){
7557 this.animateTarget = null;
7560 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
7562 this.tabs.destroy(removeEl);
7575 for(var i = 0, len = this.buttons.length; i < len; i++){
7576 this.buttons[i].destroy();
7579 this.el.removeAllListeners();
7580 if(removeEl === true){
7584 Roo.DialogManager.unregister(this);
7588 startMove : function(){
7592 if(this.constraintoviewport !== false){
7593 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
7598 endMove : function(){
7599 if(!this.proxyDrag){
7600 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
7602 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
7606 this.adjustAssets();
7608 this.fireEvent("move", this, this.xy[0], this.xy[1]);
7612 * Brings this dialog to the front of any other visible dialogs
7613 * @return {Roo.BasicDialog} this
7615 toFront : function(){
7616 Roo.DialogManager.bringToFront(this);
7621 * Sends this dialog to the back (under) of any other visible dialogs
7622 * @return {Roo.BasicDialog} this
7624 toBack : function(){
7625 Roo.DialogManager.sendToBack(this);
7630 * Centers this dialog in the viewport
7631 * @return {Roo.BasicDialog} this
7633 center : function(){
7634 var xy = this.el.getCenterXY(true);
7635 this.moveTo(xy[0], xy[1]);
7640 * Moves the dialog's top-left corner to the specified point
7643 * @return {Roo.BasicDialog} this
7645 moveTo : function(x, y){
7647 if(this.isVisible()){
7648 this.el.setXY(this.xy);
7649 this.adjustAssets();
7655 * Aligns the dialog to the specified element
7656 * @param {String/HTMLElement/Roo.Element} element The element to align to.
7657 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
7658 * @param {Array} offsets (optional) Offset the positioning by [x, y]
7659 * @return {Roo.BasicDialog} this
7661 alignTo : function(element, position, offsets){
7662 this.xy = this.el.getAlignToXY(element, position, offsets);
7663 if(this.isVisible()){
7664 this.el.setXY(this.xy);
7665 this.adjustAssets();
7671 * Anchors an element to another element and realigns it when the window is resized.
7672 * @param {String/HTMLElement/Roo.Element} element The element to align to.
7673 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
7674 * @param {Array} offsets (optional) Offset the positioning by [x, y]
7675 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
7676 * is a number, it is used as the buffer delay (defaults to 50ms).
7677 * @return {Roo.BasicDialog} this
7679 anchorTo : function(el, alignment, offsets, monitorScroll){
7680 var action = function(){
7681 this.alignTo(el, alignment, offsets);
7683 Roo.EventManager.onWindowResize(action, this);
7684 var tm = typeof monitorScroll;
7685 if(tm != 'undefined'){
7686 Roo.EventManager.on(window, 'scroll', action, this,
7687 {buffer: tm == 'number' ? monitorScroll : 50});
7694 * Returns true if the dialog is visible
7697 isVisible : function(){
7698 return this.el.isVisible();
7702 animHide : function(callback){
7703 var b = Roo.get(this.animateTarget).getBox();
7705 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
7707 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
7708 this.hideEl.createDelegate(this, [callback]));
7713 * @param {Function} callback (optional) Function to call when the dialog is hidden
7714 * @return {Roo.BasicDialog} this
7716 hide : function(callback){
7717 if (this.fireEvent("beforehide", this) === false){
7726 if(this.animateTarget){
7727 this.animHide(callback);
7730 this.hideEl(callback);
7736 hideEl : function(callback){
7740 Roo.get(document.body).removeClass("x-body-masked");
7742 this.fireEvent("hide", this);
7743 if(typeof callback == "function"){
7749 hideAction : function(){
7750 this.setLeft("-10000px");
7751 this.setTop("-10000px");
7752 this.setStyle("visibility", "hidden");
7756 refreshSize : function(){
7757 this.size = this.el.getSize();
7758 this.xy = this.el.getXY();
7759 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
7763 // z-index is managed by the DialogManager and may be overwritten at any time
7764 setZIndex : function(index){
7766 this.mask.setStyle("z-index", index);
7769 this.shim.setStyle("z-index", ++index);
7772 this.shadow.setZIndex(++index);
7774 this.el.setStyle("z-index", ++index);
7776 this.proxy.setStyle("z-index", ++index);
7779 this.resizer.proxy.setStyle("z-index", ++index);
7782 this.lastZIndex = index;
7786 * Returns the element for this dialog
7787 * @return {Roo.Element} The underlying dialog Element
7795 * @class Roo.DialogManager
7796 * Provides global access to BasicDialogs that have been created and
7797 * support for z-indexing (layering) multiple open dialogs.
7799 Roo.DialogManager = function(){
7801 var accessList = [];
7805 var sortDialogs = function(d1, d2){
7806 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
7810 var orderDialogs = function(){
7811 accessList.sort(sortDialogs);
7812 var seed = Roo.DialogManager.zseed;
7813 for(var i = 0, len = accessList.length; i < len; i++){
7814 var dlg = accessList[i];
7816 dlg.setZIndex(seed + (i*10));
7823 * The starting z-index for BasicDialogs (defaults to 9000)
7824 * @type Number The z-index value
7829 register : function(dlg){
7831 accessList.push(dlg);
7835 unregister : function(dlg){
7836 delete list[dlg.id];
7839 if(!accessList.indexOf){
7840 for( i = 0, len = accessList.length; i < len; i++){
7841 if(accessList[i] == dlg){
7842 accessList.splice(i, 1);
7847 i = accessList.indexOf(dlg);
7849 accessList.splice(i, 1);
7855 * Gets a registered dialog by id
7856 * @param {String/Object} id The id of the dialog or a dialog
7857 * @return {Roo.BasicDialog} this
7860 return typeof id == "object" ? id : list[id];
7864 * Brings the specified dialog to the front
7865 * @param {String/Object} dlg The id of the dialog or a dialog
7866 * @return {Roo.BasicDialog} this
7868 bringToFront : function(dlg){
7869 dlg = this.get(dlg);
7872 dlg._lastAccess = new Date().getTime();
7879 * Sends the specified dialog to the back
7880 * @param {String/Object} dlg The id of the dialog or a dialog
7881 * @return {Roo.BasicDialog} this
7883 sendToBack : function(dlg){
7884 dlg = this.get(dlg);
7885 dlg._lastAccess = -(new Date().getTime());
7893 hideAll : function(){
7894 for(var id in list){
7895 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
7904 * @class Roo.LayoutDialog
7905 * @extends Roo.BasicDialog
7906 * Dialog which provides adjustments for working with a layout in a Dialog.
7907 * Add your necessary layout config options to the dialog's config.<br>
7908 * Example usage (including a nested layout):
7911 dialog = new Roo.LayoutDialog("download-dlg", {
7920 // layout config merges with the dialog config
7923 alwaysShowTabs: true
7926 dialog.addKeyListener(27, dialog.hide, dialog);
7927 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
7928 dialog.addButton("Build It!", this.getDownload, this);
7930 // we can even add nested layouts
7931 var innerLayout = new Roo.BorderLayout("dl-inner", {
7941 innerLayout.beginUpdate();
7942 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
7943 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
7944 innerLayout.endUpdate(true);
7946 var layout = dialog.getLayout();
7947 layout.beginUpdate();
7948 layout.add("center", new Roo.ContentPanel("standard-panel",
7949 {title: "Download the Source", fitToFrame:true}));
7950 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
7951 {title: "Build your own roo.js"}));
7952 layout.getRegion("center").showPanel(sp);
7957 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
7958 * @param {Object} config configuration options
7960 Roo.LayoutDialog = function(el, cfg){
7963 if (typeof(cfg) == 'undefined') {
7964 config = Roo.apply({}, el);
7965 el = Roo.get( document.documentElement || document.body).createChild();
7966 //config.autoCreate = true;
7970 config.autoTabs = false;
7971 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
7972 this.body.setStyle({overflow:"hidden", position:"relative"});
7973 this.layout = new Roo.BorderLayout(this.body.dom, config);
7974 this.layout.monitorWindowResize = false;
7975 this.el.addClass("x-dlg-auto-layout");
7976 // fix case when center region overwrites center function
7977 this.center = Roo.BasicDialog.prototype.center;
7978 this.on("show", this.layout.layout, this.layout, true);
7980 var xitems = config.items;
7981 delete config.items;
7982 Roo.each(xitems, this.addxtype, this);
7987 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
7989 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
7992 endUpdate : function(){
7993 this.layout.endUpdate();
7997 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
8000 beginUpdate : function(){
8001 this.layout.beginUpdate();
8005 * Get the BorderLayout for this dialog
8006 * @return {Roo.BorderLayout}
8008 getLayout : function(){
8012 showEl : function(){
8013 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
8015 this.layout.layout();
8020 // Use the syncHeightBeforeShow config option to control this automatically
8021 syncBodyHeight : function(){
8022 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
8023 if(this.layout){this.layout.layout();}
8027 * Add an xtype element (actually adds to the layout.)
8028 * @return {Object} xdata xtype object data.
8031 addxtype : function(c) {
8032 return this.layout.addxtype(c);
8036 * Ext JS Library 1.1.1
8037 * Copyright(c) 2006-2007, Ext JS, LLC.
8039 * Originally Released Under LGPL - original licence link has changed is not relivant.
8042 * <script type="text/javascript">
8046 * @class Roo.MessageBox
8047 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
8051 Roo.Msg.alert('Status', 'Changes saved successfully.');
8053 // Prompt for user data:
8054 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
8056 // process text value...
8060 // Show a dialog using config options:
8062 title:'Save Changes?',
8063 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
8064 buttons: Roo.Msg.YESNOCANCEL,
8071 Roo.MessageBox = function(){
8072 var dlg, opt, mask, waitTimer;
8073 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
8074 var buttons, activeTextEl, bwidth;
8077 var handleButton = function(button){
8079 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
8083 var handleHide = function(){
8085 dlg.el.removeClass(opt.cls);
8088 Roo.TaskMgr.stop(waitTimer);
8094 var updateButtons = function(b){
8097 buttons["ok"].hide();
8098 buttons["cancel"].hide();
8099 buttons["yes"].hide();
8100 buttons["no"].hide();
8101 dlg.footer.dom.style.display = 'none';
8104 dlg.footer.dom.style.display = '';
8105 for(var k in buttons){
8106 if(typeof buttons[k] != "function"){
8109 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
8110 width += buttons[k].el.getWidth()+15;
8120 var handleEsc = function(d, k, e){
8121 if(opt && opt.closable !== false){
8131 * Returns a reference to the underlying {@link Roo.BasicDialog} element
8132 * @return {Roo.BasicDialog} The BasicDialog element
8134 getDialog : function(){
8136 dlg = new Roo.BasicDialog("x-msg-box", {
8141 constraintoviewport:false,
8143 collapsible : false,
8146 width:400, height:100,
8147 buttonAlign:"center",
8148 closeClick : function(){
8149 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
8152 handleButton("cancel");
8156 dlg.on("hide", handleHide);
8158 dlg.addKeyListener(27, handleEsc);
8160 var bt = this.buttonText;
8161 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
8162 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
8163 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
8164 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
8165 bodyEl = dlg.body.createChild({
8167 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
8169 msgEl = bodyEl.dom.firstChild;
8170 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
8171 textboxEl.enableDisplayMode();
8172 textboxEl.addKeyListener([10,13], function(){
8173 if(dlg.isVisible() && opt && opt.buttons){
8176 }else if(opt.buttons.yes){
8177 handleButton("yes");
8181 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
8182 textareaEl.enableDisplayMode();
8183 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
8184 progressEl.enableDisplayMode();
8185 var pf = progressEl.dom.firstChild;
8187 pp = Roo.get(pf.firstChild);
8188 pp.setHeight(pf.offsetHeight);
8196 * Updates the message box body text
8197 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
8198 * the XHTML-compliant non-breaking space character '&#160;')
8199 * @return {Roo.MessageBox} This message box
8201 updateText : function(text){
8202 if(!dlg.isVisible() && !opt.width){
8203 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
8205 msgEl.innerHTML = text || ' ';
8206 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
8207 Math.max(opt.minWidth || this.minWidth, bwidth));
8209 activeTextEl.setWidth(w);
8211 if(dlg.isVisible()){
8212 dlg.fixedcenter = false;
8214 dlg.setContentSize(w, bodyEl.getHeight());
8215 if(dlg.isVisible()){
8216 dlg.fixedcenter = true;
8222 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
8223 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
8224 * @param {Number} value Any number between 0 and 1 (e.g., .5)
8225 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
8226 * @return {Roo.MessageBox} This message box
8228 updateProgress : function(value, text){
8230 this.updateText(text);
8232 if (pp) { // weird bug on my firefox - for some reason this is not defined
8233 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
8239 * Returns true if the message box is currently displayed
8240 * @return {Boolean} True if the message box is visible, else false
8242 isVisible : function(){
8243 return dlg && dlg.isVisible();
8247 * Hides the message box if it is displayed
8250 if(this.isVisible()){
8256 * Displays a new message box, or reinitializes an existing message box, based on the config options
8257 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
8258 * The following config object properties are supported:
8260 Property Type Description
8261 ---------- --------------- ------------------------------------------------------------------------------------
8262 animEl String/Element An id or Element from which the message box should animate as it opens and
8263 closes (defaults to undefined)
8264 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
8265 cancel:'Bar'}), or false to not show any buttons (defaults to false)
8266 closable Boolean False to hide the top-right close button (defaults to true). Note that
8267 progress and wait dialogs will ignore this property and always hide the
8268 close button as they can only be closed programmatically.
8269 cls String A custom CSS class to apply to the message box element
8270 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
8271 displayed (defaults to 75)
8272 fn Function A callback function to execute after closing the dialog. The arguments to the
8273 function will be btn (the name of the button that was clicked, if applicable,
8274 e.g. "ok"), and text (the value of the active text field, if applicable).
8275 Progress and wait dialogs will ignore this option since they do not respond to
8276 user actions and can only be closed programmatically, so any required function
8277 should be called by the same code after it closes the dialog.
8278 icon String A CSS class that provides a background image to be used as an icon for
8279 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
8280 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
8281 minWidth Number The minimum width in pixels of the message box (defaults to 100)
8282 modal Boolean False to allow user interaction with the page while the message box is
8283 displayed (defaults to true)
8284 msg String A string that will replace the existing message box body text (defaults
8285 to the XHTML-compliant non-breaking space character ' ')
8286 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
8287 progress Boolean True to display a progress bar (defaults to false)
8288 progressText String The text to display inside the progress bar if progress = true (defaults to '')
8289 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
8290 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
8291 title String The title text
8292 value String The string value to set into the active textbox element if displayed
8293 wait Boolean True to display a progress bar (defaults to false)
8294 width Number The width of the dialog in pixels
8301 msg: 'Please enter your address:',
8303 buttons: Roo.MessageBox.OKCANCEL,
8306 animEl: 'addAddressBtn'
8309 * @param {Object} config Configuration options
8310 * @return {Roo.MessageBox} This message box
8312 show : function(options){
8313 if(this.isVisible()){
8316 var d = this.getDialog();
8318 d.setTitle(opt.title || " ");
8319 d.close.setDisplayed(opt.closable !== false);
8320 activeTextEl = textboxEl;
8321 opt.prompt = opt.prompt || (opt.multiline ? true : false);
8326 textareaEl.setHeight(typeof opt.multiline == "number" ?
8327 opt.multiline : this.defaultTextHeight);
8328 activeTextEl = textareaEl;
8337 progressEl.setDisplayed(opt.progress === true);
8338 this.updateProgress(0);
8339 activeTextEl.dom.value = opt.value || "";
8341 dlg.setDefaultButton(activeTextEl);
8343 var bs = opt.buttons;
8347 }else if(bs && bs.yes){
8348 db = buttons["yes"];
8350 dlg.setDefaultButton(db);
8352 bwidth = updateButtons(opt.buttons);
8353 this.updateText(opt.msg);
8355 d.el.addClass(opt.cls);
8357 d.proxyDrag = opt.proxyDrag === true;
8358 d.modal = opt.modal !== false;
8359 d.mask = opt.modal !== false ? mask : false;
8361 // force it to the end of the z-index stack so it gets a cursor in FF
8362 document.body.appendChild(dlg.el.dom);
8363 d.animateTarget = null;
8364 d.show(options.animEl);
8370 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
8371 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
8372 * and closing the message box when the process is complete.
8373 * @param {String} title The title bar text
8374 * @param {String} msg The message box body text
8375 * @return {Roo.MessageBox} This message box
8377 progress : function(title, msg){
8384 minWidth: this.minProgressWidth,
8391 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
8392 * If a callback function is passed it will be called after the user clicks the button, and the
8393 * id of the button that was clicked will be passed as the only parameter to the callback
8394 * (could also be the top-right close button).
8395 * @param {String} title The title bar text
8396 * @param {String} msg The message box body text
8397 * @param {Function} fn (optional) The callback function invoked after the message box is closed
8398 * @param {Object} scope (optional) The scope of the callback function
8399 * @return {Roo.MessageBox} This message box
8401 alert : function(title, msg, fn, scope){
8414 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
8415 * interaction while waiting for a long-running process to complete that does not have defined intervals.
8416 * You are responsible for closing the message box when the process is complete.
8417 * @param {String} msg The message box body text
8418 * @param {String} title (optional) The title bar text
8419 * @return {Roo.MessageBox} This message box
8421 wait : function(msg, title){
8432 waitTimer = Roo.TaskMgr.start({
8434 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
8442 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
8443 * If a callback function is passed it will be called after the user clicks either button, and the id of the
8444 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
8445 * @param {String} title The title bar text
8446 * @param {String} msg The message box body text
8447 * @param {Function} fn (optional) The callback function invoked after the message box is closed
8448 * @param {Object} scope (optional) The scope of the callback function
8449 * @return {Roo.MessageBox} This message box
8451 confirm : function(title, msg, fn, scope){
8455 buttons: this.YESNO,
8464 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
8465 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
8466 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
8467 * (could also be the top-right close button) and the text that was entered will be passed as the two
8468 * parameters to the callback.
8469 * @param {String} title The title bar text
8470 * @param {String} msg The message box body text
8471 * @param {Function} fn (optional) The callback function invoked after the message box is closed
8472 * @param {Object} scope (optional) The scope of the callback function
8473 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
8474 * property, or the height in pixels to create the textbox (defaults to false / single-line)
8475 * @return {Roo.MessageBox} This message box
8477 prompt : function(title, msg, fn, scope, multiline){
8481 buttons: this.OKCANCEL,
8486 multiline: multiline,
8493 * Button config that displays a single OK button
8498 * Button config that displays Yes and No buttons
8501 YESNO : {yes:true, no:true},
8503 * Button config that displays OK and Cancel buttons
8506 OKCANCEL : {ok:true, cancel:true},
8508 * Button config that displays Yes, No and Cancel buttons
8511 YESNOCANCEL : {yes:true, no:true, cancel:true},
8514 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
8517 defaultTextHeight : 75,
8519 * The maximum width in pixels of the message box (defaults to 600)
8524 * The minimum width in pixels of the message box (defaults to 100)
8529 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
8530 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
8533 minProgressWidth : 250,
8535 * An object containing the default button text strings that can be overriden for localized language support.
8536 * Supported properties are: ok, cancel, yes and no.
8537 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
8550 * Shorthand for {@link Roo.MessageBox}
8552 Roo.Msg = Roo.MessageBox;/*
8554 * Ext JS Library 1.1.1
8555 * Copyright(c) 2006-2007, Ext JS, LLC.
8557 * Originally Released Under LGPL - original licence link has changed is not relivant.
8560 * <script type="text/javascript">
8563 * @class Roo.QuickTips
8564 * Provides attractive and customizable tooltips for any element.
8567 Roo.QuickTips = function(){
8568 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
8570 var visible = false, disabled = true, inited = false;
8571 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
8573 var onOver = function(e){
8577 var t = e.getTarget();
8578 if(!t || t.nodeType !== 1 || t == document || t == document.body){
8581 if(ce && t == ce.el){
8582 clearTimeout(hideProc);
8585 if(t && tagEls[t.id]){
8586 tagEls[t.id].el = t;
8587 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
8590 var ttp, et = Roo.fly(t);
8591 var ns = cfg.namespace;
8592 if(tm.interceptTitles && t.title){
8595 t.removeAttribute("title");
8598 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
8601 showProc = show.defer(tm.showDelay, tm, [{
8604 width: et.getAttributeNS(ns, cfg.width),
8605 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
8606 title: et.getAttributeNS(ns, cfg.title),
8607 cls: et.getAttributeNS(ns, cfg.cls)
8612 var onOut = function(e){
8613 clearTimeout(showProc);
8614 var t = e.getTarget();
8615 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
8616 hideProc = setTimeout(hide, tm.hideDelay);
8620 var onMove = function(e){
8626 if(tm.trackMouse && ce){
8631 var onDown = function(e){
8632 clearTimeout(showProc);
8633 clearTimeout(hideProc);
8638 tm.enable.defer(100, tm);
8643 var getPad = function(){
8644 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
8647 var show = function(o){
8651 clearTimeout(dismissProc);
8653 if(removeCls){ // in case manually hidden
8654 el.removeClass(removeCls);
8658 el.addClass(ce.cls);
8662 tipTitle.update(ce.title);
8665 tipTitle.update('');
8668 el.dom.style.width = tm.maxWidth+'px';
8669 //tipBody.dom.style.width = '';
8670 tipBodyText.update(o.text);
8671 var p = getPad(), w = ce.width;
8673 var td = tipBodyText.dom;
8674 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
8675 if(aw > tm.maxWidth){
8677 }else if(aw < tm.minWidth){
8683 //tipBody.setWidth(w);
8684 el.setWidth(parseInt(w, 10) + p);
8685 if(ce.autoHide === false){
8686 close.setDisplayed(true);
8691 close.setDisplayed(false);
8697 el.avoidY = xy[1]-18;
8702 el.setStyle("visibility", "visible");
8703 el.fadeIn({callback: afterShow});
8709 var afterShow = function(){
8713 if(tm.autoDismiss && ce.autoHide !== false){
8714 dismissProc = setTimeout(hide, tm.autoDismissDelay);
8719 var hide = function(noanim){
8720 clearTimeout(dismissProc);
8721 clearTimeout(hideProc);
8725 if(noanim !== true && tm.animate){
8726 el.fadeOut({callback: afterHide});
8733 var afterHide = function(){
8736 el.removeClass(removeCls);
8743 * @cfg {Number} minWidth
8744 * The minimum width of the quick tip (defaults to 40)
8748 * @cfg {Number} maxWidth
8749 * The maximum width of the quick tip (defaults to 300)
8753 * @cfg {Boolean} interceptTitles
8754 * True to automatically use the element's DOM title value if available (defaults to false)
8756 interceptTitles : false,
8758 * @cfg {Boolean} trackMouse
8759 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
8763 * @cfg {Boolean} hideOnClick
8764 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
8768 * @cfg {Number} showDelay
8769 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
8773 * @cfg {Number} hideDelay
8774 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
8778 * @cfg {Boolean} autoHide
8779 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
8780 * Used in conjunction with hideDelay.
8785 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
8786 * (defaults to true). Used in conjunction with autoDismissDelay.
8791 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
8793 autoDismissDelay : 5000,
8795 * @cfg {Boolean} animate
8796 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
8801 * @cfg {String} title
8802 * Title text to display (defaults to ''). This can be any valid HTML markup.
8806 * @cfg {String} text
8807 * Body text to display (defaults to ''). This can be any valid HTML markup.
8812 * A CSS class to apply to the base quick tip element (defaults to '').
8816 * @cfg {Number} width
8817 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
8818 * minWidth or maxWidth.
8823 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
8824 * or display QuickTips in a page.
8830 if(!Roo.isReady){ // allow calling of init() before onReady
8831 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
8834 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
8835 el.fxDefaults = {stopFx: true};
8836 // maximum custom styling
8837 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
8838 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
8839 tipTitle = el.child('h3');
8840 tipTitle.enableDisplayMode("block");
8841 tipBody = el.child('div.x-tip-bd');
8842 tipBodyText = el.child('div.x-tip-bd-inner');
8843 //bdLeft = el.child('div.x-tip-bd-left');
8844 //bdRight = el.child('div.x-tip-bd-right');
8845 close = el.child('div.x-tip-close');
8846 close.enableDisplayMode("block");
8847 close.on("click", hide);
8848 var d = Roo.get(document);
8849 d.on("mousedown", onDown);
8850 d.on("mouseover", onOver);
8851 d.on("mouseout", onOut);
8852 d.on("mousemove", onMove);
8853 esc = d.addKeyListener(27, hide);
8856 dd = el.initDD("default", null, {
8857 onDrag : function(){
8861 dd.setHandleElId(tipTitle.id);
8870 * Configures a new quick tip instance and assigns it to a target element. The following config options
8873 Property Type Description
8874 ---------- --------------------- ------------------------------------------------------------------------
8875 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
8877 * @param {Object} config The config object
8879 register : function(config){
8880 var cs = config instanceof Array ? config : arguments;
8881 for(var i = 0, len = cs.length; i < len; i++) {
8883 var target = c.target;
8885 if(target instanceof Array){
8886 for(var j = 0, jlen = target.length; j < jlen; j++){
8887 tagEls[target[j]] = c;
8890 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
8897 * Removes this quick tip from its element and destroys it.
8898 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
8900 unregister : function(el){
8901 delete tagEls[Roo.id(el)];
8905 * Enable this quick tip.
8907 enable : function(){
8908 if(inited && disabled){
8910 if(locks.length < 1){
8917 * Disable this quick tip.
8919 disable : function(){
8921 clearTimeout(showProc);
8922 clearTimeout(hideProc);
8923 clearTimeout(dismissProc);
8931 * Returns true if the quick tip is enabled, else false.
8933 isEnabled : function(){
8951 Roo.QuickTips.tips = Roo.QuickTips.register;/*
8953 * Ext JS Library 1.1.1
8954 * Copyright(c) 2006-2007, Ext JS, LLC.
8956 * Originally Released Under LGPL - original licence link has changed is not relivant.
8959 * <script type="text/javascript">
8964 * @class Roo.tree.TreePanel
8965 * @extends Roo.data.Tree
8967 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
8968 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
8969 * @cfg {Boolean} enableDD true to enable drag and drop
8970 * @cfg {Boolean} enableDrag true to enable just drag
8971 * @cfg {Boolean} enableDrop true to enable just drop
8972 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
8973 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
8974 * @cfg {String} ddGroup The DD group this TreePanel belongs to
8975 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
8976 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
8977 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
8978 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
8979 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
8980 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
8981 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
8982 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
8983 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
8984 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
8985 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
8986 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
8989 * @param {String/HTMLElement/Element} el The container element
8990 * @param {Object} config
8992 Roo.tree.TreePanel = function(el, config){
8999 if (config.loader) {
9000 loader = config.loader;
9001 delete config.loader;
9004 Roo.apply(this, config);
9005 Roo.tree.TreePanel.superclass.constructor.call(this);
9006 this.el = Roo.get(el);
9007 this.el.addClass('x-tree');
9008 //console.log(root);
9010 this.setRootNode( Roo.factory(root, Roo.tree));
9013 this.loader = Roo.factory(loader, Roo.tree);
9016 * Read-only. The id of the container element becomes this TreePanel's id.
9018 this.id = this.el.id;
9022 * Fires before a node is loaded, return false to cancel
9023 * @param {Node} node The node being loaded
9025 "beforeload" : true,
9028 * Fires when a node is loaded
9029 * @param {Node} node The node that was loaded
9034 * Fires when the text for a node is changed
9035 * @param {Node} node The node
9036 * @param {String} text The new text
9037 * @param {String} oldText The old text
9039 "textchange" : true,
9041 * @event beforeexpand
9042 * Fires before a node is expanded, return false to cancel.
9043 * @param {Node} node The node
9044 * @param {Boolean} deep
9045 * @param {Boolean} anim
9047 "beforeexpand" : true,
9049 * @event beforecollapse
9050 * Fires before a node is collapsed, return false to cancel.
9051 * @param {Node} node The node
9052 * @param {Boolean} deep
9053 * @param {Boolean} anim
9055 "beforecollapse" : true,
9058 * Fires when a node is expanded
9059 * @param {Node} node The node
9063 * @event disabledchange
9064 * Fires when the disabled status of a node changes
9065 * @param {Node} node The node
9066 * @param {Boolean} disabled
9068 "disabledchange" : true,
9071 * Fires when a node is collapsed
9072 * @param {Node} node The node
9076 * @event beforeclick
9077 * Fires before click processing on a node. Return false to cancel the default action.
9078 * @param {Node} node The node
9079 * @param {Roo.EventObject} e The event object
9083 * @event checkchange
9084 * Fires when a node with a checkbox's checked property changes
9085 * @param {Node} this This node
9086 * @param {Boolean} checked
9091 * Fires when a node is clicked
9092 * @param {Node} node The node
9093 * @param {Roo.EventObject} e The event object
9098 * Fires when a node is double clicked
9099 * @param {Node} node The node
9100 * @param {Roo.EventObject} e The event object
9104 * @event contextmenu
9105 * Fires when a node is right clicked
9106 * @param {Node} node The node
9107 * @param {Roo.EventObject} e The event object
9111 * @event beforechildrenrendered
9112 * Fires right before the child nodes for a node are rendered
9113 * @param {Node} node The node
9115 "beforechildrenrendered":true,
9118 * Fires when a node starts being dragged
9119 * @param {Roo.tree.TreePanel} this
9120 * @param {Roo.tree.TreeNode} node
9121 * @param {event} e The raw browser event
9126 * Fires when a drag operation is complete
9127 * @param {Roo.tree.TreePanel} this
9128 * @param {Roo.tree.TreeNode} node
9129 * @param {event} e The raw browser event
9134 * Fires when a dragged node is dropped on a valid DD target
9135 * @param {Roo.tree.TreePanel} this
9136 * @param {Roo.tree.TreeNode} node
9137 * @param {DD} dd The dd it was dropped on
9138 * @param {event} e The raw browser event
9142 * @event beforenodedrop
9143 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
9144 * passed to handlers has the following properties:<br />
9145 * <ul style="padding:5px;padding-left:16px;">
9146 * <li>tree - The TreePanel</li>
9147 * <li>target - The node being targeted for the drop</li>
9148 * <li>data - The drag data from the drag source</li>
9149 * <li>point - The point of the drop - append, above or below</li>
9150 * <li>source - The drag source</li>
9151 * <li>rawEvent - Raw mouse event</li>
9152 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
9153 * to be inserted by setting them on this object.</li>
9154 * <li>cancel - Set this to true to cancel the drop.</li>
9156 * @param {Object} dropEvent
9158 "beforenodedrop" : true,
9161 * Fires after a DD object is dropped on a node in this tree. The dropEvent
9162 * passed to handlers has the following properties:<br />
9163 * <ul style="padding:5px;padding-left:16px;">
9164 * <li>tree - The TreePanel</li>
9165 * <li>target - The node being targeted for the drop</li>
9166 * <li>data - The drag data from the drag source</li>
9167 * <li>point - The point of the drop - append, above or below</li>
9168 * <li>source - The drag source</li>
9169 * <li>rawEvent - Raw mouse event</li>
9170 * <li>dropNode - Dropped node(s).</li>
9172 * @param {Object} dropEvent
9176 * @event nodedragover
9177 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
9178 * passed to handlers has the following properties:<br />
9179 * <ul style="padding:5px;padding-left:16px;">
9180 * <li>tree - The TreePanel</li>
9181 * <li>target - The node being targeted for the drop</li>
9182 * <li>data - The drag data from the drag source</li>
9183 * <li>point - The point of the drop - append, above or below</li>
9184 * <li>source - The drag source</li>
9185 * <li>rawEvent - Raw mouse event</li>
9186 * <li>dropNode - Drop node(s) provided by the source.</li>
9187 * <li>cancel - Set this to true to signal drop not allowed.</li>
9189 * @param {Object} dragOverEvent
9191 "nodedragover" : true
9194 if(this.singleExpand){
9195 this.on("beforeexpand", this.restrictExpand, this);
9198 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
9200 animate: Roo.enableFx,
9203 hlDrop : Roo.enableFx,
9209 restrictExpand : function(node){
9210 var p = node.parentNode;
9212 if(p.expandedChild && p.expandedChild.parentNode == p){
9213 p.expandedChild.collapse();
9215 p.expandedChild = node;
9220 setRootNode : function(node){
9221 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
9222 if(!this.rootVisible){
9223 node.ui = new Roo.tree.RootTreeNodeUI(node);
9229 * Returns the container element for this TreePanel
9236 * Returns the default TreeLoader for this TreePanel
9238 getLoader : function(){
9245 expandAll : function(){
9246 this.root.expand(true);
9250 * Collapse all nodes
9252 collapseAll : function(){
9253 this.root.collapse(true);
9257 * Returns the selection model used by this TreePanel
9259 getSelectionModel : function(){
9261 this.selModel = new Roo.tree.DefaultSelectionModel();
9263 return this.selModel;
9267 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
9268 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
9269 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
9272 getChecked : function(a, startNode){
9273 startNode = startNode || this.root;
9276 if(this.attributes.checked){
9277 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
9280 startNode.cascade(f);
9285 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
9286 * @param {String} path
9287 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
9288 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
9289 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
9291 expandPath : function(path, attr, callback){
9292 attr = attr || "id";
9293 var keys = path.split(this.pathSeparator);
9294 var curNode = this.root;
9295 if(curNode.attributes[attr] != keys[1]){ // invalid root
9297 callback(false, null);
9303 if(++index == keys.length){
9305 callback(true, curNode);
9309 var c = curNode.findChild(attr, keys[index]);
9312 callback(false, curNode);
9317 c.expand(false, false, f);
9319 curNode.expand(false, false, f);
9323 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
9324 * @param {String} path
9325 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
9326 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
9327 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
9329 selectPath : function(path, attr, callback){
9330 attr = attr || "id";
9331 var keys = path.split(this.pathSeparator);
9333 if(keys.length > 0){
9334 var f = function(success, node){
9335 if(success && node){
9336 var n = node.findChild(attr, v);
9351 this.expandPath(keys.join(this.pathSeparator), attr, f);
9355 callback(true, this.root);
9360 getTreeEl : function(){
9365 * Trigger rendering of this TreePanel
9367 render : function(){
9369 return this; // stop it rendering more than once!!
9372 this.innerCt = this.el.createChild({tag:"ul",
9373 cls:"x-tree-root-ct " +
9374 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
9376 if(this.containerScroll){
9377 Roo.dd.ScrollManager.register(this.el);
9379 if((this.enableDD || this.enableDrop) && !this.dropZone){
9381 * The dropZone used by this tree if drop is enabled
9382 * @type Roo.tree.TreeDropZone
9384 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
9385 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
9388 if((this.enableDD || this.enableDrag) && !this.dragZone){
9390 * The dragZone used by this tree if drag is enabled
9391 * @type Roo.tree.TreeDragZone
9393 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
9394 ddGroup: this.ddGroup || "TreeDD",
9395 scroll: this.ddScroll
9398 this.getSelectionModel().init(this);
9400 console.log("ROOT not set in tree");
9404 if(!this.rootVisible){
9405 this.root.renderChildren();
9411 * Ext JS Library 1.1.1
9412 * Copyright(c) 2006-2007, Ext JS, LLC.
9414 * Originally Released Under LGPL - original licence link has changed is not relivant.
9417 * <script type="text/javascript">
9422 * @class Roo.tree.DefaultSelectionModel
9423 * @extends Roo.util.Observable
9424 * The default single selection for a TreePanel.
9426 Roo.tree.DefaultSelectionModel = function(){
9427 this.selNode = null;
9431 * @event selectionchange
9432 * Fires when the selected node changes
9433 * @param {DefaultSelectionModel} this
9434 * @param {TreeNode} node the new selection
9436 "selectionchange" : true,
9439 * @event beforeselect
9440 * Fires before the selected node changes, return false to cancel the change
9441 * @param {DefaultSelectionModel} this
9442 * @param {TreeNode} node the new selection
9443 * @param {TreeNode} node the old selection
9445 "beforeselect" : true
9449 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
9450 init : function(tree){
9452 tree.getTreeEl().on("keydown", this.onKeyDown, this);
9453 tree.on("click", this.onNodeClick, this);
9456 onNodeClick : function(node, e){
9457 if (e.ctrlKey && this.selNode == node) {
9458 this.unselect(node);
9466 * @param {TreeNode} node The node to select
9467 * @return {TreeNode} The selected node
9469 select : function(node){
9470 var last = this.selNode;
9471 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
9473 last.ui.onSelectedChange(false);
9475 this.selNode = node;
9476 node.ui.onSelectedChange(true);
9477 this.fireEvent("selectionchange", this, node, last);
9484 * @param {TreeNode} node The node to unselect
9486 unselect : function(node){
9487 if(this.selNode == node){
9488 this.clearSelections();
9493 * Clear all selections
9495 clearSelections : function(){
9496 var n = this.selNode;
9498 n.ui.onSelectedChange(false);
9499 this.selNode = null;
9500 this.fireEvent("selectionchange", this, null);
9506 * Get the selected node
9507 * @return {TreeNode} The selected node
9509 getSelectedNode : function(){
9510 return this.selNode;
9514 * Returns true if the node is selected
9515 * @param {TreeNode} node The node to check
9518 isSelected : function(node){
9519 return this.selNode == node;
9523 * Selects the node above the selected node in the tree, intelligently walking the nodes
9524 * @return TreeNode The new selection
9526 selectPrevious : function(){
9527 var s = this.selNode || this.lastSelNode;
9531 var ps = s.previousSibling;
9533 if(!ps.isExpanded() || ps.childNodes.length < 1){
9534 return this.select(ps);
9536 var lc = ps.lastChild;
9537 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
9540 return this.select(lc);
9542 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
9543 return this.select(s.parentNode);
9549 * Selects the node above the selected node in the tree, intelligently walking the nodes
9550 * @return TreeNode The new selection
9552 selectNext : function(){
9553 var s = this.selNode || this.lastSelNode;
9557 if(s.firstChild && s.isExpanded()){
9558 return this.select(s.firstChild);
9559 }else if(s.nextSibling){
9560 return this.select(s.nextSibling);
9561 }else if(s.parentNode){
9563 s.parentNode.bubble(function(){
9564 if(this.nextSibling){
9565 newS = this.getOwnerTree().selModel.select(this.nextSibling);
9574 onKeyDown : function(e){
9575 var s = this.selNode || this.lastSelNode;
9576 // undesirable, but required
9589 this.selectPrevious();
9593 if(s.hasChildNodes()){
9594 if(!s.isExpanded()){
9596 }else if(s.firstChild){
9597 this.select(s.firstChild, e);
9603 if(s.hasChildNodes() && s.isExpanded()){
9605 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
9606 this.select(s.parentNode, e);
9614 * @class Roo.tree.MultiSelectionModel
9615 * @extends Roo.util.Observable
9616 * Multi selection for a TreePanel.
9618 Roo.tree.MultiSelectionModel = function(){
9623 * @event selectionchange
9624 * Fires when the selected nodes change
9625 * @param {MultiSelectionModel} this
9626 * @param {Array} nodes Array of the selected nodes
9628 "selectionchange" : true
9632 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
9633 init : function(tree){
9635 tree.getTreeEl().on("keydown", this.onKeyDown, this);
9636 tree.on("click", this.onNodeClick, this);
9639 onNodeClick : function(node, e){
9640 this.select(node, e, e.ctrlKey);
9645 * @param {TreeNode} node The node to select
9646 * @param {EventObject} e (optional) An event associated with the selection
9647 * @param {Boolean} keepExisting True to retain existing selections
9648 * @return {TreeNode} The selected node
9650 select : function(node, e, keepExisting){
9651 if(keepExisting !== true){
9652 this.clearSelections(true);
9654 if(this.isSelected(node)){
9655 this.lastSelNode = node;
9658 this.selNodes.push(node);
9659 this.selMap[node.id] = node;
9660 this.lastSelNode = node;
9661 node.ui.onSelectedChange(true);
9662 this.fireEvent("selectionchange", this, this.selNodes);
9668 * @param {TreeNode} node The node to unselect
9670 unselect : function(node){
9671 if(this.selMap[node.id]){
9672 node.ui.onSelectedChange(false);
9673 var sn = this.selNodes;
9676 index = sn.indexOf(node);
9678 for(var i = 0, len = sn.length; i < len; i++){
9686 this.selNodes.splice(index, 1);
9688 delete this.selMap[node.id];
9689 this.fireEvent("selectionchange", this, this.selNodes);
9694 * Clear all selections
9696 clearSelections : function(suppressEvent){
9697 var sn = this.selNodes;
9699 for(var i = 0, len = sn.length; i < len; i++){
9700 sn[i].ui.onSelectedChange(false);
9704 if(suppressEvent !== true){
9705 this.fireEvent("selectionchange", this, this.selNodes);
9711 * Returns true if the node is selected
9712 * @param {TreeNode} node The node to check
9715 isSelected : function(node){
9716 return this.selMap[node.id] ? true : false;
9720 * Returns an array of the selected nodes
9723 getSelectedNodes : function(){
9724 return this.selNodes;
9727 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
9729 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
9731 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
9734 * Ext JS Library 1.1.1
9735 * Copyright(c) 2006-2007, Ext JS, LLC.
9737 * Originally Released Under LGPL - original licence link has changed is not relivant.
9740 * <script type="text/javascript">
9744 * @class Roo.tree.TreeNode
9745 * @extends Roo.data.Node
9746 * @cfg {String} text The text for this node
9747 * @cfg {Boolean} expanded true to start the node expanded
9748 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
9749 * @cfg {Boolean} allowDrop false if this node cannot be drop on
9750 * @cfg {Boolean} disabled true to start the node disabled
9751 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
9752 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
9753 * @cfg {String} cls A css class to be added to the node
9754 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
9755 * @cfg {String} href URL of the link used for the node (defaults to #)
9756 * @cfg {String} hrefTarget target frame for the link
9757 * @cfg {String} qtip An Ext QuickTip for the node
9758 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
9759 * @cfg {Boolean} singleClickExpand True for single click expand on this node
9760 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
9761 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
9762 * (defaults to undefined with no checkbox rendered)
9764 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
9766 Roo.tree.TreeNode = function(attributes){
9767 attributes = attributes || {};
9768 if(typeof attributes == "string"){
9769 attributes = {text: attributes};
9771 this.childrenRendered = false;
9772 this.rendered = false;
9773 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
9774 this.expanded = attributes.expanded === true;
9775 this.isTarget = attributes.isTarget !== false;
9776 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
9777 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
9780 * Read-only. The text for this node. To change it use setText().
9783 this.text = attributes.text;
9785 * True if this node is disabled.
9788 this.disabled = attributes.disabled === true;
9793 * Fires when the text for this node is changed
9794 * @param {Node} this This node
9795 * @param {String} text The new text
9796 * @param {String} oldText The old text
9798 "textchange" : true,
9800 * @event beforeexpand
9801 * Fires before this node is expanded, return false to cancel.
9802 * @param {Node} this This node
9803 * @param {Boolean} deep
9804 * @param {Boolean} anim
9806 "beforeexpand" : true,
9808 * @event beforecollapse
9809 * Fires before this node is collapsed, return false to cancel.
9810 * @param {Node} this This node
9811 * @param {Boolean} deep
9812 * @param {Boolean} anim
9814 "beforecollapse" : true,
9817 * Fires when this node is expanded
9818 * @param {Node} this This node
9822 * @event disabledchange
9823 * Fires when the disabled status of this node changes
9824 * @param {Node} this This node
9825 * @param {Boolean} disabled
9827 "disabledchange" : true,
9830 * Fires when this node is collapsed
9831 * @param {Node} this This node
9835 * @event beforeclick
9836 * Fires before click processing. Return false to cancel the default action.
9837 * @param {Node} this This node
9838 * @param {Roo.EventObject} e The event object
9842 * @event checkchange
9843 * Fires when a node with a checkbox's checked property changes
9844 * @param {Node} this This node
9845 * @param {Boolean} checked
9850 * Fires when this node is clicked
9851 * @param {Node} this This node
9852 * @param {Roo.EventObject} e The event object
9857 * Fires when this node is double clicked
9858 * @param {Node} this This node
9859 * @param {Roo.EventObject} e The event object
9863 * @event contextmenu
9864 * Fires when this node is right clicked
9865 * @param {Node} this This node
9866 * @param {Roo.EventObject} e The event object
9870 * @event beforechildrenrendered
9871 * Fires right before the child nodes for this node are rendered
9872 * @param {Node} this This node
9874 "beforechildrenrendered":true
9877 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
9880 * Read-only. The UI for this node
9883 this.ui = new uiClass(this);
9885 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
9886 preventHScroll: true,
9888 * Returns true if this node is expanded
9891 isExpanded : function(){
9892 return this.expanded;
9896 * Returns the UI object for this node
9897 * @return {TreeNodeUI}
9904 setFirstChild : function(node){
9905 var of = this.firstChild;
9906 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
9907 if(this.childrenRendered && of && node != of){
9908 of.renderIndent(true, true);
9911 this.renderIndent(true, true);
9916 setLastChild : function(node){
9917 var ol = this.lastChild;
9918 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
9919 if(this.childrenRendered && ol && node != ol){
9920 ol.renderIndent(true, true);
9923 this.renderIndent(true, true);
9927 // these methods are overridden to provide lazy rendering support
9929 appendChild : function(){
9930 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
9931 if(node && this.childrenRendered){
9934 this.ui.updateExpandIcon();
9939 removeChild : function(node){
9940 this.ownerTree.getSelectionModel().unselect(node);
9941 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
9942 // if it's been rendered remove dom node
9943 if(this.childrenRendered){
9946 if(this.childNodes.length < 1){
9947 this.collapse(false, false);
9949 this.ui.updateExpandIcon();
9951 if(!this.firstChild) {
9952 this.childrenRendered = false;
9958 insertBefore : function(node, refNode){
9959 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
9960 if(newNode && refNode && this.childrenRendered){
9963 this.ui.updateExpandIcon();
9968 * Sets the text for this node
9969 * @param {String} text
9971 setText : function(text){
9972 var oldText = this.text;
9974 this.attributes.text = text;
9975 if(this.rendered){ // event without subscribing
9976 this.ui.onTextChange(this, text, oldText);
9978 this.fireEvent("textchange", this, text, oldText);
9982 * Triggers selection of this node
9984 select : function(){
9985 this.getOwnerTree().getSelectionModel().select(this);
9989 * Triggers deselection of this node
9991 unselect : function(){
9992 this.getOwnerTree().getSelectionModel().unselect(this);
9996 * Returns true if this node is selected
9999 isSelected : function(){
10000 return this.getOwnerTree().getSelectionModel().isSelected(this);
10004 * Expand this node.
10005 * @param {Boolean} deep (optional) True to expand all children as well
10006 * @param {Boolean} anim (optional) false to cancel the default animation
10007 * @param {Function} callback (optional) A callback to be called when
10008 * expanding this node completes (does not wait for deep expand to complete).
10009 * Called with 1 parameter, this node.
10011 expand : function(deep, anim, callback){
10012 if(!this.expanded){
10013 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
10016 if(!this.childrenRendered){
10017 this.renderChildren();
10019 this.expanded = true;
10020 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
10021 this.ui.animExpand(function(){
10022 this.fireEvent("expand", this);
10023 if(typeof callback == "function"){
10027 this.expandChildNodes(true);
10029 }.createDelegate(this));
10033 this.fireEvent("expand", this);
10034 if(typeof callback == "function"){
10039 if(typeof callback == "function"){
10044 this.expandChildNodes(true);
10048 isHiddenRoot : function(){
10049 return this.isRoot && !this.getOwnerTree().rootVisible;
10053 * Collapse this node.
10054 * @param {Boolean} deep (optional) True to collapse all children as well
10055 * @param {Boolean} anim (optional) false to cancel the default animation
10057 collapse : function(deep, anim){
10058 if(this.expanded && !this.isHiddenRoot()){
10059 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
10062 this.expanded = false;
10063 if((this.getOwnerTree().animate && anim !== false) || anim){
10064 this.ui.animCollapse(function(){
10065 this.fireEvent("collapse", this);
10067 this.collapseChildNodes(true);
10069 }.createDelegate(this));
10072 this.ui.collapse();
10073 this.fireEvent("collapse", this);
10077 var cs = this.childNodes;
10078 for(var i = 0, len = cs.length; i < len; i++) {
10079 cs[i].collapse(true, false);
10085 delayedExpand : function(delay){
10086 if(!this.expandProcId){
10087 this.expandProcId = this.expand.defer(delay, this);
10092 cancelExpand : function(){
10093 if(this.expandProcId){
10094 clearTimeout(this.expandProcId);
10096 this.expandProcId = false;
10100 * Toggles expanded/collapsed state of the node
10102 toggle : function(){
10111 * Ensures all parent nodes are expanded
10113 ensureVisible : function(callback){
10114 var tree = this.getOwnerTree();
10115 tree.expandPath(this.parentNode.getPath(), false, function(){
10116 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
10117 Roo.callback(callback);
10118 }.createDelegate(this));
10122 * Expand all child nodes
10123 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
10125 expandChildNodes : function(deep){
10126 var cs = this.childNodes;
10127 for(var i = 0, len = cs.length; i < len; i++) {
10128 cs[i].expand(deep);
10133 * Collapse all child nodes
10134 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
10136 collapseChildNodes : function(deep){
10137 var cs = this.childNodes;
10138 for(var i = 0, len = cs.length; i < len; i++) {
10139 cs[i].collapse(deep);
10144 * Disables this node
10146 disable : function(){
10147 this.disabled = true;
10149 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
10150 this.ui.onDisableChange(this, true);
10152 this.fireEvent("disabledchange", this, true);
10156 * Enables this node
10158 enable : function(){
10159 this.disabled = false;
10160 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
10161 this.ui.onDisableChange(this, false);
10163 this.fireEvent("disabledchange", this, false);
10167 renderChildren : function(suppressEvent){
10168 if(suppressEvent !== false){
10169 this.fireEvent("beforechildrenrendered", this);
10171 var cs = this.childNodes;
10172 for(var i = 0, len = cs.length; i < len; i++){
10173 cs[i].render(true);
10175 this.childrenRendered = true;
10179 sort : function(fn, scope){
10180 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
10181 if(this.childrenRendered){
10182 var cs = this.childNodes;
10183 for(var i = 0, len = cs.length; i < len; i++){
10184 cs[i].render(true);
10190 render : function(bulkRender){
10191 this.ui.render(bulkRender);
10192 if(!this.rendered){
10193 this.rendered = true;
10195 this.expanded = false;
10196 this.expand(false, false);
10202 renderIndent : function(deep, refresh){
10204 this.ui.childIndent = null;
10206 this.ui.renderIndent();
10207 if(deep === true && this.childrenRendered){
10208 var cs = this.childNodes;
10209 for(var i = 0, len = cs.length; i < len; i++){
10210 cs[i].renderIndent(true, refresh);
10216 * Ext JS Library 1.1.1
10217 * Copyright(c) 2006-2007, Ext JS, LLC.
10219 * Originally Released Under LGPL - original licence link has changed is not relivant.
10222 * <script type="text/javascript">
10226 * @class Roo.tree.AsyncTreeNode
10227 * @extends Roo.tree.TreeNode
10228 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
10230 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
10232 Roo.tree.AsyncTreeNode = function(config){
10233 this.loaded = false;
10234 this.loading = false;
10235 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
10237 * @event beforeload
10238 * Fires before this node is loaded, return false to cancel
10239 * @param {Node} this This node
10241 this.addEvents({'beforeload':true, 'load': true});
10244 * Fires when this node is loaded
10245 * @param {Node} this This node
10248 * The loader used by this node (defaults to using the tree's defined loader)
10253 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
10254 expand : function(deep, anim, callback){
10255 if(this.loading){ // if an async load is already running, waiting til it's done
10257 var f = function(){
10258 if(!this.loading){ // done loading
10259 clearInterval(timer);
10260 this.expand(deep, anim, callback);
10262 }.createDelegate(this);
10263 timer = setInterval(f, 200);
10267 if(this.fireEvent("beforeload", this) === false){
10270 this.loading = true;
10271 this.ui.beforeLoad(this);
10272 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
10274 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
10278 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
10282 * Returns true if this node is currently loading
10283 * @return {Boolean}
10285 isLoading : function(){
10286 return this.loading;
10289 loadComplete : function(deep, anim, callback){
10290 this.loading = false;
10291 this.loaded = true;
10292 this.ui.afterLoad(this);
10293 this.fireEvent("load", this);
10294 this.expand(deep, anim, callback);
10298 * Returns true if this node has been loaded
10299 * @return {Boolean}
10301 isLoaded : function(){
10302 return this.loaded;
10305 hasChildNodes : function(){
10306 if(!this.isLeaf() && !this.loaded){
10309 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
10314 * Trigger a reload for this node
10315 * @param {Function} callback
10317 reload : function(callback){
10318 this.collapse(false, false);
10319 while(this.firstChild){
10320 this.removeChild(this.firstChild);
10322 this.childrenRendered = false;
10323 this.loaded = false;
10324 if(this.isHiddenRoot()){
10325 this.expanded = false;
10327 this.expand(false, false, callback);
10331 * Ext JS Library 1.1.1
10332 * Copyright(c) 2006-2007, Ext JS, LLC.
10334 * Originally Released Under LGPL - original licence link has changed is not relivant.
10337 * <script type="text/javascript">
10341 * @class Roo.tree.TreeNodeUI
10343 * @param {Object} node The node to render
10344 * The TreeNode UI implementation is separate from the
10345 * tree implementation. Unless you are customizing the tree UI,
10346 * you should never have to use this directly.
10348 Roo.tree.TreeNodeUI = function(node){
10350 this.rendered = false;
10351 this.animating = false;
10352 this.emptyIcon = Roo.BLANK_IMAGE_URL;
10355 Roo.tree.TreeNodeUI.prototype = {
10356 removeChild : function(node){
10358 this.ctNode.removeChild(node.ui.getEl());
10362 beforeLoad : function(){
10363 this.addClass("x-tree-node-loading");
10366 afterLoad : function(){
10367 this.removeClass("x-tree-node-loading");
10370 onTextChange : function(node, text, oldText){
10372 this.textNode.innerHTML = text;
10376 onDisableChange : function(node, state){
10377 this.disabled = state;
10379 this.addClass("x-tree-node-disabled");
10381 this.removeClass("x-tree-node-disabled");
10385 onSelectedChange : function(state){
10388 this.addClass("x-tree-selected");
10391 this.removeClass("x-tree-selected");
10395 onMove : function(tree, node, oldParent, newParent, index, refNode){
10396 this.childIndent = null;
10398 var targetNode = newParent.ui.getContainer();
10399 if(!targetNode){//target not rendered
10400 this.holder = document.createElement("div");
10401 this.holder.appendChild(this.wrap);
10404 var insertBefore = refNode ? refNode.ui.getEl() : null;
10406 targetNode.insertBefore(this.wrap, insertBefore);
10408 targetNode.appendChild(this.wrap);
10410 this.node.renderIndent(true);
10414 addClass : function(cls){
10416 Roo.fly(this.elNode).addClass(cls);
10420 removeClass : function(cls){
10422 Roo.fly(this.elNode).removeClass(cls);
10426 remove : function(){
10428 this.holder = document.createElement("div");
10429 this.holder.appendChild(this.wrap);
10433 fireEvent : function(){
10434 return this.node.fireEvent.apply(this.node, arguments);
10437 initEvents : function(){
10438 this.node.on("move", this.onMove, this);
10439 var E = Roo.EventManager;
10440 var a = this.anchor;
10442 var el = Roo.fly(a, '_treeui');
10444 if(Roo.isOpera){ // opera render bug ignores the CSS
10445 el.setStyle("text-decoration", "none");
10448 el.on("click", this.onClick, this);
10449 el.on("dblclick", this.onDblClick, this);
10452 Roo.EventManager.on(this.checkbox,
10453 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
10456 el.on("contextmenu", this.onContextMenu, this);
10458 var icon = Roo.fly(this.iconNode);
10459 icon.on("click", this.onClick, this);
10460 icon.on("dblclick", this.onDblClick, this);
10461 icon.on("contextmenu", this.onContextMenu, this);
10462 E.on(this.ecNode, "click", this.ecClick, this, true);
10464 if(this.node.disabled){
10465 this.addClass("x-tree-node-disabled");
10467 if(this.node.hidden){
10468 this.addClass("x-tree-node-disabled");
10470 var ot = this.node.getOwnerTree();
10471 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
10472 if(dd && (!this.node.isRoot || ot.rootVisible)){
10473 Roo.dd.Registry.register(this.elNode, {
10475 handles: this.getDDHandles(),
10481 getDDHandles : function(){
10482 return [this.iconNode, this.textNode];
10487 this.wrap.style.display = "none";
10493 this.wrap.style.display = "";
10497 onContextMenu : function(e){
10498 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
10499 e.preventDefault();
10501 this.fireEvent("contextmenu", this.node, e);
10505 onClick : function(e){
10510 if(this.fireEvent("beforeclick", this.node, e) !== false){
10511 if(!this.disabled && this.node.attributes.href){
10512 this.fireEvent("click", this.node, e);
10515 e.preventDefault();
10520 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
10521 this.node.toggle();
10524 this.fireEvent("click", this.node, e);
10530 onDblClick : function(e){
10531 e.preventDefault();
10536 this.toggleCheck();
10538 if(!this.animating && this.node.hasChildNodes()){
10539 this.node.toggle();
10541 this.fireEvent("dblclick", this.node, e);
10544 onCheckChange : function(){
10545 var checked = this.checkbox.checked;
10546 this.node.attributes.checked = checked;
10547 this.fireEvent('checkchange', this.node, checked);
10550 ecClick : function(e){
10551 if(!this.animating && this.node.hasChildNodes()){
10552 this.node.toggle();
10556 startDrop : function(){
10557 this.dropping = true;
10560 // delayed drop so the click event doesn't get fired on a drop
10561 endDrop : function(){
10562 setTimeout(function(){
10563 this.dropping = false;
10564 }.createDelegate(this), 50);
10567 expand : function(){
10568 this.updateExpandIcon();
10569 this.ctNode.style.display = "";
10572 focus : function(){
10573 if(!this.node.preventHScroll){
10574 try{this.anchor.focus();
10576 }else if(!Roo.isIE){
10578 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
10579 var l = noscroll.scrollLeft;
10580 this.anchor.focus();
10581 noscroll.scrollLeft = l;
10586 toggleCheck : function(value){
10587 var cb = this.checkbox;
10589 cb.checked = (value === undefined ? !cb.checked : value);
10595 this.anchor.blur();
10599 animExpand : function(callback){
10600 var ct = Roo.get(this.ctNode);
10602 if(!this.node.hasChildNodes()){
10603 this.updateExpandIcon();
10604 this.ctNode.style.display = "";
10605 Roo.callback(callback);
10608 this.animating = true;
10609 this.updateExpandIcon();
10612 callback : function(){
10613 this.animating = false;
10614 Roo.callback(callback);
10617 duration: this.node.ownerTree.duration || .25
10621 highlight : function(){
10622 var tree = this.node.getOwnerTree();
10623 Roo.fly(this.wrap).highlight(
10624 tree.hlColor || "C3DAF9",
10625 {endColor: tree.hlBaseColor}
10629 collapse : function(){
10630 this.updateExpandIcon();
10631 this.ctNode.style.display = "none";
10634 animCollapse : function(callback){
10635 var ct = Roo.get(this.ctNode);
10636 ct.enableDisplayMode('block');
10639 this.animating = true;
10640 this.updateExpandIcon();
10643 callback : function(){
10644 this.animating = false;
10645 Roo.callback(callback);
10648 duration: this.node.ownerTree.duration || .25
10652 getContainer : function(){
10653 return this.ctNode;
10656 getEl : function(){
10660 appendDDGhost : function(ghostNode){
10661 ghostNode.appendChild(this.elNode.cloneNode(true));
10664 getDDRepairXY : function(){
10665 return Roo.lib.Dom.getXY(this.iconNode);
10668 onRender : function(){
10672 render : function(bulkRender){
10673 var n = this.node, a = n.attributes;
10674 var targetNode = n.parentNode ?
10675 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
10677 if(!this.rendered){
10678 this.rendered = true;
10680 this.renderElements(n, a, targetNode, bulkRender);
10683 if(this.textNode.setAttributeNS){
10684 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
10686 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
10689 this.textNode.setAttribute("ext:qtip", a.qtip);
10691 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
10694 }else if(a.qtipCfg){
10695 a.qtipCfg.target = Roo.id(this.textNode);
10696 Roo.QuickTips.register(a.qtipCfg);
10699 if(!this.node.expanded){
10700 this.updateExpandIcon();
10703 if(bulkRender === true) {
10704 targetNode.appendChild(this.wrap);
10709 renderElements : function(n, a, targetNode, bulkRender){
10710 // add some indent caching, this helps performance when rendering a large tree
10711 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
10712 var t = n.getOwnerTree();
10713 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
10714 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
10715 var cb = typeof a.checked == 'boolean';
10716 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
10717 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
10718 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
10719 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
10720 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
10721 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
10722 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
10723 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
10724 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
10725 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
10728 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
10729 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
10730 n.nextSibling.ui.getEl(), buf.join(""));
10732 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
10735 this.elNode = this.wrap.childNodes[0];
10736 this.ctNode = this.wrap.childNodes[1];
10737 var cs = this.elNode.childNodes;
10738 this.indentNode = cs[0];
10739 this.ecNode = cs[1];
10740 this.iconNode = cs[2];
10743 this.checkbox = cs[3];
10746 this.anchor = cs[index];
10747 this.textNode = cs[index].firstChild;
10750 getAnchor : function(){
10751 return this.anchor;
10754 getTextEl : function(){
10755 return this.textNode;
10758 getIconEl : function(){
10759 return this.iconNode;
10762 isChecked : function(){
10763 return this.checkbox ? this.checkbox.checked : false;
10766 updateExpandIcon : function(){
10768 var n = this.node, c1, c2;
10769 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
10770 var hasChild = n.hasChildNodes();
10774 c1 = "x-tree-node-collapsed";
10775 c2 = "x-tree-node-expanded";
10778 c1 = "x-tree-node-expanded";
10779 c2 = "x-tree-node-collapsed";
10782 this.removeClass("x-tree-node-leaf");
10783 this.wasLeaf = false;
10785 if(this.c1 != c1 || this.c2 != c2){
10786 Roo.fly(this.elNode).replaceClass(c1, c2);
10787 this.c1 = c1; this.c2 = c2;
10791 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
10794 this.wasLeaf = true;
10797 var ecc = "x-tree-ec-icon "+cls;
10798 if(this.ecc != ecc){
10799 this.ecNode.className = ecc;
10805 getChildIndent : function(){
10806 if(!this.childIndent){
10810 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
10812 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
10814 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
10819 this.childIndent = buf.join("");
10821 return this.childIndent;
10824 renderIndent : function(){
10827 var p = this.node.parentNode;
10829 indent = p.ui.getChildIndent();
10831 if(this.indentMarkup != indent){ // don't rerender if not required
10832 this.indentNode.innerHTML = indent;
10833 this.indentMarkup = indent;
10835 this.updateExpandIcon();
10840 Roo.tree.RootTreeNodeUI = function(){
10841 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
10843 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
10844 render : function(){
10845 if(!this.rendered){
10846 var targetNode = this.node.ownerTree.innerCt.dom;
10847 this.node.expanded = true;
10848 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
10849 this.wrap = this.ctNode = targetNode.firstChild;
10852 collapse : function(){
10854 expand : function(){
10858 * Ext JS Library 1.1.1
10859 * Copyright(c) 2006-2007, Ext JS, LLC.
10861 * Originally Released Under LGPL - original licence link has changed is not relivant.
10864 * <script type="text/javascript">
10867 * @class Roo.tree.TreeLoader
10868 * @extends Roo.util.Observable
10869 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
10870 * nodes from a specified URL. The response must be a javascript Array definition
10871 * who's elements are node definition objects. eg:
10873 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
10874 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
10877 * A server request is sent, and child nodes are loaded only when a node is expanded.
10878 * The loading node's id is passed to the server under the parameter name "node" to
10879 * enable the server to produce the correct child nodes.
10881 * To pass extra parameters, an event handler may be attached to the "beforeload"
10882 * event, and the parameters specified in the TreeLoader's baseParams property:
10884 myTreeLoader.on("beforeload", function(treeLoader, node) {
10885 this.baseParams.category = node.attributes.category;
10888 * This would pass an HTTP parameter called "category" to the server containing
10889 * the value of the Node's "category" attribute.
10891 * Creates a new Treeloader.
10892 * @param {Object} config A config object containing config properties.
10894 Roo.tree.TreeLoader = function(config){
10895 this.baseParams = {};
10896 this.requestMethod = "POST";
10897 Roo.apply(this, config);
10902 * @event beforeload
10903 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
10904 * @param {Object} This TreeLoader object.
10905 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
10906 * @param {Object} callback The callback function specified in the {@link #load} call.
10911 * Fires when the node has been successfuly loaded.
10912 * @param {Object} This TreeLoader object.
10913 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
10914 * @param {Object} response The response object containing the data from the server.
10918 * @event loadexception
10919 * Fires if the network request failed.
10920 * @param {Object} This TreeLoader object.
10921 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
10922 * @param {Object} response The response object containing the data from the server.
10924 loadexception : true,
10927 * Fires before a node is created, enabling you to return custom Node types
10928 * @param {Object} This TreeLoader object.
10929 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
10934 Roo.tree.TreeLoader.superclass.constructor.call(this);
10937 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
10939 * @cfg {String} dataUrl The URL from which to request a Json string which
10940 * specifies an array of node definition object representing the child nodes
10944 * @cfg {Object} baseParams (optional) An object containing properties which
10945 * specify HTTP parameters to be passed to each request for child nodes.
10948 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
10949 * created by this loader. If the attributes sent by the server have an attribute in this object,
10950 * they take priority.
10953 * @cfg {Object} uiProviders (optional) An object containing properties which
10955 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
10956 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
10957 * <i>uiProvider</i> attribute of a returned child node is a string rather
10958 * than a reference to a TreeNodeUI implementation, this that string value
10959 * is used as a property name in the uiProviders object. You can define the provider named
10960 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
10965 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
10966 * child nodes before loading.
10968 clearOnLoad : true,
10971 * @cfg {String} root (optional) Default to false. Use this to read data from an object
10972 * property on loading, rather than expecting an array. (eg. more compatible to a standard
10973 * Grid query { data : [ .....] }
10978 * @cfg {String} queryParam (optional)
10979 * Name of the query as it will be passed on the querystring (defaults to 'node')
10980 * eg. the request will be ?node=[id]
10987 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
10988 * This is called automatically when a node is expanded, but may be used to reload
10989 * a node (or append new children if the {@link #clearOnLoad} option is false.)
10990 * @param {Roo.tree.TreeNode} node
10991 * @param {Function} callback
10993 load : function(node, callback){
10994 if(this.clearOnLoad){
10995 while(node.firstChild){
10996 node.removeChild(node.firstChild);
10999 if(node.attributes.children){ // preloaded json children
11000 var cs = node.attributes.children;
11001 for(var i = 0, len = cs.length; i < len; i++){
11002 node.appendChild(this.createNode(cs[i]));
11004 if(typeof callback == "function"){
11007 }else if(this.dataUrl){
11008 this.requestData(node, callback);
11012 getParams: function(node){
11013 var buf = [], bp = this.baseParams;
11014 for(var key in bp){
11015 if(typeof bp[key] != "function"){
11016 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
11019 var n = this.queryParam === false ? 'node' : this.queryParam;
11020 buf.push(n + "=", encodeURIComponent(node.id));
11021 return buf.join("");
11024 requestData : function(node, callback){
11025 if(this.fireEvent("beforeload", this, node, callback) !== false){
11026 this.transId = Roo.Ajax.request({
11027 method:this.requestMethod,
11028 url: this.dataUrl||this.url,
11029 success: this.handleResponse,
11030 failure: this.handleFailure,
11032 argument: {callback: callback, node: node},
11033 params: this.getParams(node)
11036 // if the load is cancelled, make sure we notify
11037 // the node that we are done
11038 if(typeof callback == "function"){
11044 isLoading : function(){
11045 return this.transId ? true : false;
11048 abort : function(){
11049 if(this.isLoading()){
11050 Roo.Ajax.abort(this.transId);
11055 createNode : function(attr){
11056 // apply baseAttrs, nice idea Corey!
11057 if(this.baseAttrs){
11058 Roo.applyIf(attr, this.baseAttrs);
11060 if(this.applyLoader !== false){
11061 attr.loader = this;
11063 // uiProvider = depreciated..
11065 if(typeof(attr.uiProvider) == 'string'){
11066 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
11067 /** eval:var:attr */ eval(attr.uiProvider);
11069 if(typeof(this.uiProviders['default']) != 'undefined') {
11070 attr.uiProvider = this.uiProviders['default'];
11073 this.fireEvent('create', this, attr);
11075 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
11077 new Roo.tree.TreeNode(attr) :
11078 new Roo.tree.AsyncTreeNode(attr));
11081 processResponse : function(response, node, callback){
11082 var json = response.responseText;
11085 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
11086 if (this.root !== false) {
11090 for(var i = 0, len = o.length; i < len; i++){
11091 var n = this.createNode(o[i]);
11093 node.appendChild(n);
11096 if(typeof callback == "function"){
11097 callback(this, node);
11100 this.handleFailure(response);
11104 handleResponse : function(response){
11105 this.transId = false;
11106 var a = response.argument;
11107 this.processResponse(response, a.node, a.callback);
11108 this.fireEvent("load", this, a.node, response);
11111 handleFailure : function(response){
11112 this.transId = false;
11113 var a = response.argument;
11114 this.fireEvent("loadexception", this, a.node, response);
11115 if(typeof a.callback == "function"){
11116 a.callback(this, a.node);
11121 * Ext JS Library 1.1.1
11122 * Copyright(c) 2006-2007, Ext JS, LLC.
11124 * Originally Released Under LGPL - original licence link has changed is not relivant.
11127 * <script type="text/javascript">
11131 * @class Roo.tree.TreeFilter
11132 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
11133 * @param {TreePanel} tree
11134 * @param {Object} config (optional)
11136 Roo.tree.TreeFilter = function(tree, config){
11138 this.filtered = {};
11139 Roo.apply(this, config);
11142 Roo.tree.TreeFilter.prototype = {
11149 * Filter the data by a specific attribute.
11150 * @param {String/RegExp} value Either string that the attribute value
11151 * should start with or a RegExp to test against the attribute
11152 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
11153 * @param {TreeNode} startNode (optional) The node to start the filter at.
11155 filter : function(value, attr, startNode){
11156 attr = attr || "text";
11158 if(typeof value == "string"){
11159 var vlen = value.length;
11160 // auto clear empty filter
11161 if(vlen == 0 && this.clearBlank){
11165 value = value.toLowerCase();
11167 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
11169 }else if(value.exec){ // regex?
11171 return value.test(n.attributes[attr]);
11174 throw 'Illegal filter type, must be string or regex';
11176 this.filterBy(f, null, startNode);
11180 * Filter by a function. The passed function will be called with each
11181 * node in the tree (or from the startNode). If the function returns true, the node is kept
11182 * otherwise it is filtered. If a node is filtered, its children are also filtered.
11183 * @param {Function} fn The filter function
11184 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
11186 filterBy : function(fn, scope, startNode){
11187 startNode = startNode || this.tree.root;
11188 if(this.autoClear){
11191 var af = this.filtered, rv = this.reverse;
11192 var f = function(n){
11193 if(n == startNode){
11199 var m = fn.call(scope || n, n);
11207 startNode.cascade(f);
11210 if(typeof id != "function"){
11212 if(n && n.parentNode){
11213 n.parentNode.removeChild(n);
11221 * Clears the current filter. Note: with the "remove" option
11222 * set a filter cannot be cleared.
11224 clear : function(){
11226 var af = this.filtered;
11228 if(typeof id != "function"){
11235 this.filtered = {};
11240 * Ext JS Library 1.1.1
11241 * Copyright(c) 2006-2007, Ext JS, LLC.
11243 * Originally Released Under LGPL - original licence link has changed is not relivant.
11246 * <script type="text/javascript">
11251 * @class Roo.tree.TreeSorter
11252 * Provides sorting of nodes in a TreePanel
11254 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
11255 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
11256 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
11257 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
11258 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
11259 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
11261 * @param {TreePanel} tree
11262 * @param {Object} config
11264 Roo.tree.TreeSorter = function(tree, config){
11265 Roo.apply(this, config);
11266 tree.on("beforechildrenrendered", this.doSort, this);
11267 tree.on("append", this.updateSort, this);
11268 tree.on("insert", this.updateSort, this);
11270 var dsc = this.dir && this.dir.toLowerCase() == "desc";
11271 var p = this.property || "text";
11272 var sortType = this.sortType;
11273 var fs = this.folderSort;
11274 var cs = this.caseSensitive === true;
11275 var leafAttr = this.leafAttr || 'leaf';
11277 this.sortFn = function(n1, n2){
11279 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
11282 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
11286 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
11287 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
11289 return dsc ? +1 : -1;
11291 return dsc ? -1 : +1;
11298 Roo.tree.TreeSorter.prototype = {
11299 doSort : function(node){
11300 node.sort(this.sortFn);
11303 compareNodes : function(n1, n2){
11304 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
11307 updateSort : function(tree, node){
11308 if(node.childrenRendered){
11309 this.doSort.defer(1, this, [node]);
11314 * Ext JS Library 1.1.1
11315 * Copyright(c) 2006-2007, Ext JS, LLC.
11317 * Originally Released Under LGPL - original licence link has changed is not relivant.
11320 * <script type="text/javascript">
11323 if(Roo.dd.DropZone){
11325 Roo.tree.TreeDropZone = function(tree, config){
11326 this.allowParentInsert = false;
11327 this.allowContainerDrop = false;
11328 this.appendOnly = false;
11329 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
11331 this.lastInsertClass = "x-tree-no-status";
11332 this.dragOverData = {};
11335 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
11336 ddGroup : "TreeDD",
11338 expandDelay : 1000,
11340 expandNode : function(node){
11341 if(node.hasChildNodes() && !node.isExpanded()){
11342 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
11346 queueExpand : function(node){
11347 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
11350 cancelExpand : function(){
11351 if(this.expandProcId){
11352 clearTimeout(this.expandProcId);
11353 this.expandProcId = false;
11357 isValidDropPoint : function(n, pt, dd, e, data){
11358 if(!n || !data){ return false; }
11359 var targetNode = n.node;
11360 var dropNode = data.node;
11361 // default drop rules
11362 if(!(targetNode && targetNode.isTarget && pt)){
11365 if(pt == "append" && targetNode.allowChildren === false){
11368 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
11371 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
11374 // reuse the object
11375 var overEvent = this.dragOverData;
11376 overEvent.tree = this.tree;
11377 overEvent.target = targetNode;
11378 overEvent.data = data;
11379 overEvent.point = pt;
11380 overEvent.source = dd;
11381 overEvent.rawEvent = e;
11382 overEvent.dropNode = dropNode;
11383 overEvent.cancel = false;
11384 var result = this.tree.fireEvent("nodedragover", overEvent);
11385 return overEvent.cancel === false && result !== false;
11388 getDropPoint : function(e, n, dd){
11391 return tn.allowChildren !== false ? "append" : false; // always append for root
11393 var dragEl = n.ddel;
11394 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
11395 var y = Roo.lib.Event.getPageY(e);
11396 var noAppend = tn.allowChildren === false || tn.isLeaf();
11397 if(this.appendOnly || tn.parentNode.allowChildren === false){
11398 return noAppend ? false : "append";
11400 var noBelow = false;
11401 if(!this.allowParentInsert){
11402 noBelow = tn.hasChildNodes() && tn.isExpanded();
11404 var q = (b - t) / (noAppend ? 2 : 3);
11405 if(y >= t && y < (t + q)){
11407 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
11414 onNodeEnter : function(n, dd, e, data){
11415 this.cancelExpand();
11418 onNodeOver : function(n, dd, e, data){
11419 var pt = this.getDropPoint(e, n, dd);
11422 // auto node expand check
11423 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
11424 this.queueExpand(node);
11425 }else if(pt != "append"){
11426 this.cancelExpand();
11429 // set the insert point style on the target node
11430 var returnCls = this.dropNotAllowed;
11431 if(this.isValidDropPoint(n, pt, dd, e, data)){
11436 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
11437 cls = "x-tree-drag-insert-above";
11438 }else if(pt == "below"){
11439 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
11440 cls = "x-tree-drag-insert-below";
11442 returnCls = "x-tree-drop-ok-append";
11443 cls = "x-tree-drag-append";
11445 if(this.lastInsertClass != cls){
11446 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
11447 this.lastInsertClass = cls;
11454 onNodeOut : function(n, dd, e, data){
11455 this.cancelExpand();
11456 this.removeDropIndicators(n);
11459 onNodeDrop : function(n, dd, e, data){
11460 var point = this.getDropPoint(e, n, dd);
11461 var targetNode = n.node;
11462 targetNode.ui.startDrop();
11463 if(!this.isValidDropPoint(n, point, dd, e, data)){
11464 targetNode.ui.endDrop();
11467 // first try to find the drop node
11468 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
11471 target: targetNode,
11476 dropNode: dropNode,
11479 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
11480 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
11481 targetNode.ui.endDrop();
11484 // allow target changing
11485 targetNode = dropEvent.target;
11486 if(point == "append" && !targetNode.isExpanded()){
11487 targetNode.expand(false, null, function(){
11488 this.completeDrop(dropEvent);
11489 }.createDelegate(this));
11491 this.completeDrop(dropEvent);
11496 completeDrop : function(de){
11497 var ns = de.dropNode, p = de.point, t = de.target;
11498 if(!(ns instanceof Array)){
11502 for(var i = 0, len = ns.length; i < len; i++){
11505 t.parentNode.insertBefore(n, t);
11506 }else if(p == "below"){
11507 t.parentNode.insertBefore(n, t.nextSibling);
11513 if(this.tree.hlDrop){
11517 this.tree.fireEvent("nodedrop", de);
11520 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
11521 if(this.tree.hlDrop){
11522 dropNode.ui.focus();
11523 dropNode.ui.highlight();
11525 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
11528 getTree : function(){
11532 removeDropIndicators : function(n){
11535 Roo.fly(el).removeClass([
11536 "x-tree-drag-insert-above",
11537 "x-tree-drag-insert-below",
11538 "x-tree-drag-append"]);
11539 this.lastInsertClass = "_noclass";
11543 beforeDragDrop : function(target, e, id){
11544 this.cancelExpand();
11548 afterRepair : function(data){
11549 if(data && Roo.enableFx){
11550 data.node.ui.highlight();
11558 * Ext JS Library 1.1.1
11559 * Copyright(c) 2006-2007, Ext JS, LLC.
11561 * Originally Released Under LGPL - original licence link has changed is not relivant.
11564 * <script type="text/javascript">
11568 if(Roo.dd.DragZone){
11569 Roo.tree.TreeDragZone = function(tree, config){
11570 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
11574 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
11575 ddGroup : "TreeDD",
11577 onBeforeDrag : function(data, e){
11579 return n && n.draggable && !n.disabled;
11582 onInitDrag : function(e){
11583 var data = this.dragData;
11584 this.tree.getSelectionModel().select(data.node);
11585 this.proxy.update("");
11586 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
11587 this.tree.fireEvent("startdrag", this.tree, data.node, e);
11590 getRepairXY : function(e, data){
11591 return data.node.ui.getDDRepairXY();
11594 onEndDrag : function(data, e){
11595 this.tree.fireEvent("enddrag", this.tree, data.node, e);
11598 onValidDrop : function(dd, e, id){
11599 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
11603 beforeInvalidDrop : function(e, id){
11604 // this scrolls the original position back into view
11605 var sm = this.tree.getSelectionModel();
11606 sm.clearSelections();
11607 sm.select(this.dragData.node);
11612 * Ext JS Library 1.1.1
11613 * Copyright(c) 2006-2007, Ext JS, LLC.
11615 * Originally Released Under LGPL - original licence link has changed is not relivant.
11618 * <script type="text/javascript">
11621 * @class Roo.tree.TreeEditor
11622 * @extends Roo.Editor
11623 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
11624 * as the editor field.
11626 * @param {TreePanel} tree
11627 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
11629 Roo.tree.TreeEditor = function(tree, config){
11630 config = config || {};
11631 var field = config.events ? config : new Roo.form.TextField(config);
11632 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
11636 tree.on('beforeclick', this.beforeNodeClick, this);
11637 tree.getTreeEl().on('mousedown', this.hide, this);
11638 this.on('complete', this.updateNode, this);
11639 this.on('beforestartedit', this.fitToTree, this);
11640 this.on('startedit', this.bindScroll, this, {delay:10});
11641 this.on('specialkey', this.onSpecialKey, this);
11644 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
11646 * @cfg {String} alignment
11647 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
11653 * @cfg {Boolean} hideEl
11654 * True to hide the bound element while the editor is displayed (defaults to false)
11658 * @cfg {String} cls
11659 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
11661 cls: "x-small-editor x-tree-editor",
11663 * @cfg {Boolean} shim
11664 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
11670 * @cfg {Number} maxWidth
11671 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
11672 * the containing tree element's size, it will be automatically limited for you to the container width, taking
11673 * scroll and client offsets into account prior to each edit.
11680 fitToTree : function(ed, el){
11681 var td = this.tree.getTreeEl().dom, nd = el.dom;
11682 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
11683 td.scrollLeft = nd.offsetLeft;
11687 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
11688 this.setSize(w, '');
11692 triggerEdit : function(node){
11693 this.completeEdit();
11694 this.editNode = node;
11695 this.startEdit(node.ui.textNode, node.text);
11699 bindScroll : function(){
11700 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
11704 beforeNodeClick : function(node, e){
11705 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
11706 this.lastClick = new Date();
11707 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
11709 this.triggerEdit(node);
11715 updateNode : function(ed, value){
11716 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
11717 this.editNode.setText(value);
11721 onHide : function(){
11722 Roo.tree.TreeEditor.superclass.onHide.call(this);
11724 this.editNode.ui.focus();
11729 onSpecialKey : function(field, e){
11730 var k = e.getKey();
11734 }else if(k == e.ENTER && !e.hasModifier()){
11736 this.completeEdit();
11739 });//<Script type="text/javascript">
11742 * Ext JS Library 1.1.1
11743 * Copyright(c) 2006-2007, Ext JS, LLC.
11745 * Originally Released Under LGPL - original licence link has changed is not relivant.
11748 * <script type="text/javascript">
11752 * Not documented??? - probably should be...
11755 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
11756 //focus: Roo.emptyFn, // prevent odd scrolling behavior
11758 renderElements : function(n, a, targetNode, bulkRender){
11759 //consel.log("renderElements?");
11760 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
11762 var t = n.getOwnerTree();
11763 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
11765 var cols = t.columns;
11766 var bw = t.borderWidth;
11768 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
11769 var cb = typeof a.checked == "boolean";
11770 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
11771 var colcls = 'x-t-' + tid + '-c0';
11773 '<li class="x-tree-node">',
11776 '<div class="x-tree-node-el ', a.cls,'">',
11778 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
11781 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
11782 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
11783 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
11784 (a.icon ? ' x-tree-node-inline-icon' : ''),
11785 (a.iconCls ? ' '+a.iconCls : ''),
11786 '" unselectable="on" />',
11787 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
11788 (a.checked ? 'checked="checked" />' : ' />')) : ''),
11790 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
11791 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
11792 '<span unselectable="on" qtip="' + tx + '">',
11796 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
11797 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
11800 for(var i = 1, len = cols.length; i < len; i++){
11802 colcls = 'x-t-' + tid + '-c' +i;
11803 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
11804 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
11805 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
11811 '<div class="x-clear"></div></div>',
11812 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
11815 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
11816 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
11817 n.nextSibling.ui.getEl(), buf.join(""));
11819 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
11821 var el = this.wrap.firstChild;
11823 this.elNode = el.firstChild;
11824 this.ranchor = el.childNodes[1];
11825 this.ctNode = this.wrap.childNodes[1];
11826 var cs = el.firstChild.childNodes;
11827 this.indentNode = cs[0];
11828 this.ecNode = cs[1];
11829 this.iconNode = cs[2];
11832 this.checkbox = cs[3];
11835 this.anchor = cs[index];
11837 this.textNode = cs[index].firstChild;
11839 //el.on("click", this.onClick, this);
11840 //el.on("dblclick", this.onDblClick, this);
11843 // console.log(this);
11845 initEvents : function(){
11846 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
11849 var a = this.ranchor;
11851 var el = Roo.get(a);
11853 if(Roo.isOpera){ // opera render bug ignores the CSS
11854 el.setStyle("text-decoration", "none");
11857 el.on("click", this.onClick, this);
11858 el.on("dblclick", this.onDblClick, this);
11859 el.on("contextmenu", this.onContextMenu, this);
11863 /*onSelectedChange : function(state){
11866 this.addClass("x-tree-selected");
11869 this.removeClass("x-tree-selected");
11872 addClass : function(cls){
11874 Roo.fly(this.elRow).addClass(cls);
11880 removeClass : function(cls){
11882 Roo.fly(this.elRow).removeClass(cls);
11888 });//<Script type="text/javascript">
11892 * Ext JS Library 1.1.1
11893 * Copyright(c) 2006-2007, Ext JS, LLC.
11895 * Originally Released Under LGPL - original licence link has changed is not relivant.
11898 * <script type="text/javascript">
11903 * @class Roo.tree.ColumnTree
11904 * @extends Roo.data.TreePanel
11905 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
11906 * @cfg {int} borderWidth compined right/left border allowance
11908 * @param {String/HTMLElement/Element} el The container element
11909 * @param {Object} config
11911 Roo.tree.ColumnTree = function(el, config)
11913 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
11917 * Fire this event on a container when it resizes
11918 * @param {int} w Width
11919 * @param {int} h Height
11923 this.on('resize', this.onResize, this);
11926 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
11930 borderWidth: Roo.isBorderBox ? 0 : 2,
11933 render : function(){
11934 // add the header.....
11936 Roo.tree.ColumnTree.superclass.render.apply(this);
11938 this.el.addClass('x-column-tree');
11940 this.headers = this.el.createChild(
11941 {cls:'x-tree-headers'},this.innerCt.dom);
11943 var cols = this.columns, c;
11944 var totalWidth = 0;
11946 var len = cols.length;
11947 for(var i = 0; i < len; i++){
11949 totalWidth += c.width;
11950 this.headEls.push(this.headers.createChild({
11951 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
11953 cls:'x-tree-hd-text',
11956 style:'width:'+(c.width-this.borderWidth)+'px;'
11959 this.headers.createChild({cls:'x-clear'});
11960 // prevent floats from wrapping when clipped
11961 this.headers.setWidth(totalWidth);
11962 //this.innerCt.setWidth(totalWidth);
11963 this.innerCt.setStyle({ overflow: 'auto' });
11964 this.onResize(this.width, this.height);
11968 onResize : function(w,h)
11973 this.innerCt.setWidth(this.width);
11974 this.innerCt.setHeight(this.height-20);
11977 var cols = this.columns, c;
11978 var totalWidth = 0;
11980 var len = cols.length;
11981 for(var i = 0; i < len; i++){
11983 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
11984 // it's the expander..
11985 expEl = this.headEls[i];
11988 totalWidth += c.width;
11992 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
11994 this.headers.setWidth(w-20);
12003 * Ext JS Library 1.1.1
12004 * Copyright(c) 2006-2007, Ext JS, LLC.
12006 * Originally Released Under LGPL - original licence link has changed is not relivant.
12009 * <script type="text/javascript">
12013 * @class Roo.menu.Menu
12014 * @extends Roo.util.Observable
12015 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
12016 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
12018 * Creates a new Menu
12019 * @param {Object} config Configuration options
12021 Roo.menu.Menu = function(config){
12022 Roo.apply(this, config);
12023 this.id = this.id || Roo.id();
12026 * @event beforeshow
12027 * Fires before this menu is displayed
12028 * @param {Roo.menu.Menu} this
12032 * @event beforehide
12033 * Fires before this menu is hidden
12034 * @param {Roo.menu.Menu} this
12039 * Fires after this menu is displayed
12040 * @param {Roo.menu.Menu} this
12045 * Fires after this menu is hidden
12046 * @param {Roo.menu.Menu} this
12051 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
12052 * @param {Roo.menu.Menu} this
12053 * @param {Roo.menu.Item} menuItem The menu item that was clicked
12054 * @param {Roo.EventObject} e
12059 * Fires when the mouse is hovering over this menu
12060 * @param {Roo.menu.Menu} this
12061 * @param {Roo.EventObject} e
12062 * @param {Roo.menu.Item} menuItem The menu item that was clicked
12067 * Fires when the mouse exits this menu
12068 * @param {Roo.menu.Menu} this
12069 * @param {Roo.EventObject} e
12070 * @param {Roo.menu.Item} menuItem The menu item that was clicked
12075 * Fires when a menu item contained in this menu is clicked
12076 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
12077 * @param {Roo.EventObject} e
12081 if (this.registerMenu) {
12082 Roo.menu.MenuMgr.register(this);
12085 var mis = this.items;
12086 this.items = new Roo.util.MixedCollection();
12088 this.add.apply(this, mis);
12092 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
12094 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
12098 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
12099 * for bottom-right shadow (defaults to "sides")
12103 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
12104 * this menu (defaults to "tl-tr?")
12106 subMenuAlign : "tl-tr?",
12108 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
12109 * relative to its element of origin (defaults to "tl-bl?")
12111 defaultAlign : "tl-bl?",
12113 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
12115 allowOtherMenus : false,
12117 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
12119 registerMenu : true,
12124 render : function(){
12128 var el = this.el = new Roo.Layer({
12130 shadow:this.shadow,
12132 parentEl: this.parentEl || document.body,
12136 this.keyNav = new Roo.menu.MenuNav(this);
12139 el.addClass("x-menu-plain");
12142 el.addClass(this.cls);
12144 // generic focus element
12145 this.focusEl = el.createChild({
12146 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
12148 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
12149 ul.on("click", this.onClick, this);
12150 ul.on("mouseover", this.onMouseOver, this);
12151 ul.on("mouseout", this.onMouseOut, this);
12152 this.items.each(function(item){
12153 var li = document.createElement("li");
12154 li.className = "x-menu-list-item";
12155 ul.dom.appendChild(li);
12156 item.render(li, this);
12163 autoWidth : function(){
12164 var el = this.el, ul = this.ul;
12168 var w = this.width;
12171 }else if(Roo.isIE){
12172 el.setWidth(this.minWidth);
12173 var t = el.dom.offsetWidth; // force recalc
12174 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
12179 delayAutoWidth : function(){
12182 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
12184 this.awTask.delay(20);
12189 findTargetItem : function(e){
12190 var t = e.getTarget(".x-menu-list-item", this.ul, true);
12191 if(t && t.menuItemId){
12192 return this.items.get(t.menuItemId);
12197 onClick : function(e){
12199 if(t = this.findTargetItem(e)){
12201 this.fireEvent("click", this, t, e);
12206 setActiveItem : function(item, autoExpand){
12207 if(item != this.activeItem){
12208 if(this.activeItem){
12209 this.activeItem.deactivate();
12211 this.activeItem = item;
12212 item.activate(autoExpand);
12213 }else if(autoExpand){
12219 tryActivate : function(start, step){
12220 var items = this.items;
12221 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
12222 var item = items.get(i);
12223 if(!item.disabled && item.canActivate){
12224 this.setActiveItem(item, false);
12232 onMouseOver : function(e){
12234 if(t = this.findTargetItem(e)){
12235 if(t.canActivate && !t.disabled){
12236 this.setActiveItem(t, true);
12239 this.fireEvent("mouseover", this, e, t);
12243 onMouseOut : function(e){
12245 if(t = this.findTargetItem(e)){
12246 if(t == this.activeItem && t.shouldDeactivate(e)){
12247 this.activeItem.deactivate();
12248 delete this.activeItem;
12251 this.fireEvent("mouseout", this, e, t);
12255 * Read-only. Returns true if the menu is currently displayed, else false.
12258 isVisible : function(){
12259 return this.el && !this.hidden;
12263 * Displays this menu relative to another element
12264 * @param {String/HTMLElement/Roo.Element} element The element to align to
12265 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
12266 * the element (defaults to this.defaultAlign)
12267 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
12269 show : function(el, pos, parentMenu){
12270 this.parentMenu = parentMenu;
12274 this.fireEvent("beforeshow", this);
12275 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
12279 * Displays this menu at a specific xy position
12280 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
12281 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
12283 showAt : function(xy, parentMenu, /* private: */_e){
12284 this.parentMenu = parentMenu;
12289 this.fireEvent("beforeshow", this);
12290 xy = this.el.adjustForConstraints(xy);
12294 this.hidden = false;
12296 this.fireEvent("show", this);
12299 focus : function(){
12301 this.doFocus.defer(50, this);
12305 doFocus : function(){
12307 this.focusEl.focus();
12312 * Hides this menu and optionally all parent menus
12313 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
12315 hide : function(deep){
12316 if(this.el && this.isVisible()){
12317 this.fireEvent("beforehide", this);
12318 if(this.activeItem){
12319 this.activeItem.deactivate();
12320 this.activeItem = null;
12323 this.hidden = true;
12324 this.fireEvent("hide", this);
12326 if(deep === true && this.parentMenu){
12327 this.parentMenu.hide(true);
12332 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
12333 * Any of the following are valid:
12335 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
12336 * <li>An HTMLElement object which will be converted to a menu item</li>
12337 * <li>A menu item config object that will be created as a new menu item</li>
12338 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
12339 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
12344 var menu = new Roo.menu.Menu();
12346 // Create a menu item to add by reference
12347 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
12349 // Add a bunch of items at once using different methods.
12350 // Only the last item added will be returned.
12351 var item = menu.add(
12352 menuItem, // add existing item by ref
12353 'Dynamic Item', // new TextItem
12354 '-', // new separator
12355 { text: 'Config Item' } // new item by config
12358 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
12359 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
12362 var a = arguments, l = a.length, item;
12363 for(var i = 0; i < l; i++){
12365 if(el.render){ // some kind of Item
12366 item = this.addItem(el);
12367 }else if(typeof el == "string"){ // string
12368 if(el == "separator" || el == "-"){
12369 item = this.addSeparator();
12371 item = this.addText(el);
12373 }else if(el.tagName || el.el){ // element
12374 item = this.addElement(el);
12375 }else if(typeof el == "object"){ // must be menu item config?
12376 item = this.addMenuItem(el);
12383 * Returns this menu's underlying {@link Roo.Element} object
12384 * @return {Roo.Element} The element
12386 getEl : function(){
12394 * Adds a separator bar to the menu
12395 * @return {Roo.menu.Item} The menu item that was added
12397 addSeparator : function(){
12398 return this.addItem(new Roo.menu.Separator());
12402 * Adds an {@link Roo.Element} object to the menu
12403 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
12404 * @return {Roo.menu.Item} The menu item that was added
12406 addElement : function(el){
12407 return this.addItem(new Roo.menu.BaseItem(el));
12411 * Adds an existing object based on {@link Roo.menu.Item} to the menu
12412 * @param {Roo.menu.Item} item The menu item to add
12413 * @return {Roo.menu.Item} The menu item that was added
12415 addItem : function(item){
12416 this.items.add(item);
12418 var li = document.createElement("li");
12419 li.className = "x-menu-list-item";
12420 this.ul.dom.appendChild(li);
12421 item.render(li, this);
12422 this.delayAutoWidth();
12428 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
12429 * @param {Object} config A MenuItem config object
12430 * @return {Roo.menu.Item} The menu item that was added
12432 addMenuItem : function(config){
12433 if(!(config instanceof Roo.menu.Item)){
12434 if(typeof config.checked == "boolean"){ // must be check menu item config?
12435 config = new Roo.menu.CheckItem(config);
12437 config = new Roo.menu.Item(config);
12440 return this.addItem(config);
12444 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
12445 * @param {String} text The text to display in the menu item
12446 * @return {Roo.menu.Item} The menu item that was added
12448 addText : function(text){
12449 return this.addItem(new Roo.menu.TextItem(text));
12453 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
12454 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
12455 * @param {Roo.menu.Item} item The menu item to add
12456 * @return {Roo.menu.Item} The menu item that was added
12458 insert : function(index, item){
12459 this.items.insert(index, item);
12461 var li = document.createElement("li");
12462 li.className = "x-menu-list-item";
12463 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
12464 item.render(li, this);
12465 this.delayAutoWidth();
12471 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
12472 * @param {Roo.menu.Item} item The menu item to remove
12474 remove : function(item){
12475 this.items.removeKey(item.id);
12480 * Removes and destroys all items in the menu
12482 removeAll : function(){
12484 while(f = this.items.first()){
12490 // MenuNav is a private utility class used internally by the Menu
12491 Roo.menu.MenuNav = function(menu){
12492 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
12493 this.scope = this.menu = menu;
12496 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
12497 doRelay : function(e, h){
12498 var k = e.getKey();
12499 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
12500 this.menu.tryActivate(0, 1);
12503 return h.call(this.scope || this, e, this.menu);
12506 up : function(e, m){
12507 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
12508 m.tryActivate(m.items.length-1, -1);
12512 down : function(e, m){
12513 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
12514 m.tryActivate(0, 1);
12518 right : function(e, m){
12520 m.activeItem.expandMenu(true);
12524 left : function(e, m){
12526 if(m.parentMenu && m.parentMenu.activeItem){
12527 m.parentMenu.activeItem.activate();
12531 enter : function(e, m){
12533 e.stopPropagation();
12534 m.activeItem.onClick(e);
12535 m.fireEvent("click", this, m.activeItem);
12541 * Ext JS Library 1.1.1
12542 * Copyright(c) 2006-2007, Ext JS, LLC.
12544 * Originally Released Under LGPL - original licence link has changed is not relivant.
12547 * <script type="text/javascript">
12551 * @class Roo.menu.MenuMgr
12552 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
12555 Roo.menu.MenuMgr = function(){
12556 var menus, active, groups = {}, attached = false, lastShow = new Date();
12558 // private - called when first menu is created
12561 active = new Roo.util.MixedCollection();
12562 Roo.get(document).addKeyListener(27, function(){
12563 if(active.length > 0){
12570 function hideAll(){
12571 if(active && active.length > 0){
12572 var c = active.clone();
12573 c.each(function(m){
12580 function onHide(m){
12582 if(active.length < 1){
12583 Roo.get(document).un("mousedown", onMouseDown);
12589 function onShow(m){
12590 var last = active.last();
12591 lastShow = new Date();
12594 Roo.get(document).on("mousedown", onMouseDown);
12598 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
12599 m.parentMenu.activeChild = m;
12600 }else if(last && last.isVisible()){
12601 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
12606 function onBeforeHide(m){
12608 m.activeChild.hide();
12610 if(m.autoHideTimer){
12611 clearTimeout(m.autoHideTimer);
12612 delete m.autoHideTimer;
12617 function onBeforeShow(m){
12618 var pm = m.parentMenu;
12619 if(!pm && !m.allowOtherMenus){
12621 }else if(pm && pm.activeChild && active != m){
12622 pm.activeChild.hide();
12627 function onMouseDown(e){
12628 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
12634 function onBeforeCheck(mi, state){
12636 var g = groups[mi.group];
12637 for(var i = 0, l = g.length; i < l; i++){
12639 g[i].setChecked(false);
12648 * Hides all menus that are currently visible
12650 hideAll : function(){
12655 register : function(menu){
12659 menus[menu.id] = menu;
12660 menu.on("beforehide", onBeforeHide);
12661 menu.on("hide", onHide);
12662 menu.on("beforeshow", onBeforeShow);
12663 menu.on("show", onShow);
12664 var g = menu.group;
12665 if(g && menu.events["checkchange"]){
12669 groups[g].push(menu);
12670 menu.on("checkchange", onCheck);
12675 * Returns a {@link Roo.menu.Menu} object
12676 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
12677 * be used to generate and return a new Menu instance.
12679 get : function(menu){
12680 if(typeof menu == "string"){ // menu id
12681 return menus[menu];
12682 }else if(menu.events){ // menu instance
12684 }else if(typeof menu.length == 'number'){ // array of menu items?
12685 return new Roo.menu.Menu({items:menu});
12686 }else{ // otherwise, must be a config
12687 return new Roo.menu.Menu(menu);
12692 unregister : function(menu){
12693 delete menus[menu.id];
12694 menu.un("beforehide", onBeforeHide);
12695 menu.un("hide", onHide);
12696 menu.un("beforeshow", onBeforeShow);
12697 menu.un("show", onShow);
12698 var g = menu.group;
12699 if(g && menu.events["checkchange"]){
12700 groups[g].remove(menu);
12701 menu.un("checkchange", onCheck);
12706 registerCheckable : function(menuItem){
12707 var g = menuItem.group;
12712 groups[g].push(menuItem);
12713 menuItem.on("beforecheckchange", onBeforeCheck);
12718 unregisterCheckable : function(menuItem){
12719 var g = menuItem.group;
12721 groups[g].remove(menuItem);
12722 menuItem.un("beforecheckchange", onBeforeCheck);
12728 * Ext JS Library 1.1.1
12729 * Copyright(c) 2006-2007, Ext JS, LLC.
12731 * Originally Released Under LGPL - original licence link has changed is not relivant.
12734 * <script type="text/javascript">
12739 * @class Roo.menu.BaseItem
12740 * @extends Roo.Component
12741 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
12742 * management and base configuration options shared by all menu components.
12744 * Creates a new BaseItem
12745 * @param {Object} config Configuration options
12747 Roo.menu.BaseItem = function(config){
12748 Roo.menu.BaseItem.superclass.constructor.call(this, config);
12753 * Fires when this item is clicked
12754 * @param {Roo.menu.BaseItem} this
12755 * @param {Roo.EventObject} e
12760 * Fires when this item is activated
12761 * @param {Roo.menu.BaseItem} this
12765 * @event deactivate
12766 * Fires when this item is deactivated
12767 * @param {Roo.menu.BaseItem} this
12773 this.on("click", this.handler, this.scope, true);
12777 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
12779 * @cfg {Function} handler
12780 * A function that will handle the click event of this menu item (defaults to undefined)
12783 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
12785 canActivate : false,
12787 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
12789 activeClass : "x-menu-item-active",
12791 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
12793 hideOnClick : true,
12795 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
12800 ctype: "Roo.menu.BaseItem",
12803 actionMode : "container",
12806 render : function(container, parentMenu){
12807 this.parentMenu = parentMenu;
12808 Roo.menu.BaseItem.superclass.render.call(this, container);
12809 this.container.menuItemId = this.id;
12813 onRender : function(container, position){
12814 this.el = Roo.get(this.el);
12815 container.dom.appendChild(this.el.dom);
12819 onClick : function(e){
12820 if(!this.disabled && this.fireEvent("click", this, e) !== false
12821 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
12822 this.handleClick(e);
12829 activate : function(){
12833 var li = this.container;
12834 li.addClass(this.activeClass);
12835 this.region = li.getRegion().adjust(2, 2, -2, -2);
12836 this.fireEvent("activate", this);
12841 deactivate : function(){
12842 this.container.removeClass(this.activeClass);
12843 this.fireEvent("deactivate", this);
12847 shouldDeactivate : function(e){
12848 return !this.region || !this.region.contains(e.getPoint());
12852 handleClick : function(e){
12853 if(this.hideOnClick){
12854 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
12859 expandMenu : function(autoActivate){
12864 hideMenu : function(){
12869 * Ext JS Library 1.1.1
12870 * Copyright(c) 2006-2007, Ext JS, LLC.
12872 * Originally Released Under LGPL - original licence link has changed is not relivant.
12875 * <script type="text/javascript">
12879 * @class Roo.menu.Adapter
12880 * @extends Roo.menu.BaseItem
12881 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
12882 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
12884 * Creates a new Adapter
12885 * @param {Object} config Configuration options
12887 Roo.menu.Adapter = function(component, config){
12888 Roo.menu.Adapter.superclass.constructor.call(this, config);
12889 this.component = component;
12891 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
12893 canActivate : true,
12896 onRender : function(container, position){
12897 this.component.render(container);
12898 this.el = this.component.getEl();
12902 activate : function(){
12906 this.component.focus();
12907 this.fireEvent("activate", this);
12912 deactivate : function(){
12913 this.fireEvent("deactivate", this);
12917 disable : function(){
12918 this.component.disable();
12919 Roo.menu.Adapter.superclass.disable.call(this);
12923 enable : function(){
12924 this.component.enable();
12925 Roo.menu.Adapter.superclass.enable.call(this);
12929 * Ext JS Library 1.1.1
12930 * Copyright(c) 2006-2007, Ext JS, LLC.
12932 * Originally Released Under LGPL - original licence link has changed is not relivant.
12935 * <script type="text/javascript">
12939 * @class Roo.menu.TextItem
12940 * @extends Roo.menu.BaseItem
12941 * Adds a static text string to a menu, usually used as either a heading or group separator.
12943 * Creates a new TextItem
12944 * @param {String} text The text to display
12946 Roo.menu.TextItem = function(text){
12948 Roo.menu.TextItem.superclass.constructor.call(this);
12951 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
12953 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
12955 hideOnClick : false,
12957 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
12959 itemCls : "x-menu-text",
12962 onRender : function(){
12963 var s = document.createElement("span");
12964 s.className = this.itemCls;
12965 s.innerHTML = this.text;
12967 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
12971 * Ext JS Library 1.1.1
12972 * Copyright(c) 2006-2007, Ext JS, LLC.
12974 * Originally Released Under LGPL - original licence link has changed is not relivant.
12977 * <script type="text/javascript">
12981 * @class Roo.menu.Separator
12982 * @extends Roo.menu.BaseItem
12983 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
12984 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
12986 * @param {Object} config Configuration options
12988 Roo.menu.Separator = function(config){
12989 Roo.menu.Separator.superclass.constructor.call(this, config);
12992 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
12994 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
12996 itemCls : "x-menu-sep",
12998 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
13000 hideOnClick : false,
13003 onRender : function(li){
13004 var s = document.createElement("span");
13005 s.className = this.itemCls;
13006 s.innerHTML = " ";
13008 li.addClass("x-menu-sep-li");
13009 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
13013 * Ext JS Library 1.1.1
13014 * Copyright(c) 2006-2007, Ext JS, LLC.
13016 * Originally Released Under LGPL - original licence link has changed is not relivant.
13019 * <script type="text/javascript">
13022 * @class Roo.menu.Item
13023 * @extends Roo.menu.BaseItem
13024 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
13025 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
13026 * activation and click handling.
13028 * Creates a new Item
13029 * @param {Object} config Configuration options
13031 Roo.menu.Item = function(config){
13032 Roo.menu.Item.superclass.constructor.call(this, config);
13034 this.menu = Roo.menu.MenuMgr.get(this.menu);
13037 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
13039 * @cfg {String} icon
13040 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
13043 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
13045 itemCls : "x-menu-item",
13047 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
13049 canActivate : true,
13051 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
13054 // doc'd in BaseItem
13058 ctype: "Roo.menu.Item",
13061 onRender : function(container, position){
13062 var el = document.createElement("a");
13063 el.hideFocus = true;
13064 el.unselectable = "on";
13065 el.href = this.href || "#";
13066 if(this.hrefTarget){
13067 el.target = this.hrefTarget;
13069 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
13070 el.innerHTML = String.format(
13071 '<img src="{0}" class="x-menu-item-icon {2}" />{1}',
13072 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || '');
13074 Roo.menu.Item.superclass.onRender.call(this, container, position);
13078 * Sets the text to display in this menu item
13079 * @param {String} text The text to display
13081 setText : function(text){
13084 this.el.update(String.format(
13085 '<img src="{0}" class="x-menu-item-icon {2}">{1}',
13086 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
13087 this.parentMenu.autoWidth();
13092 handleClick : function(e){
13093 if(!this.href){ // if no link defined, stop the event automatically
13096 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
13100 activate : function(autoExpand){
13101 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
13111 shouldDeactivate : function(e){
13112 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
13113 if(this.menu && this.menu.isVisible()){
13114 return !this.menu.getEl().getRegion().contains(e.getPoint());
13122 deactivate : function(){
13123 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
13128 expandMenu : function(autoActivate){
13129 if(!this.disabled && this.menu){
13130 clearTimeout(this.hideTimer);
13131 delete this.hideTimer;
13132 if(!this.menu.isVisible() && !this.showTimer){
13133 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
13134 }else if (this.menu.isVisible() && autoActivate){
13135 this.menu.tryActivate(0, 1);
13141 deferExpand : function(autoActivate){
13142 delete this.showTimer;
13143 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
13145 this.menu.tryActivate(0, 1);
13150 hideMenu : function(){
13151 clearTimeout(this.showTimer);
13152 delete this.showTimer;
13153 if(!this.hideTimer && this.menu && this.menu.isVisible()){
13154 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
13159 deferHide : function(){
13160 delete this.hideTimer;
13165 * Ext JS Library 1.1.1
13166 * Copyright(c) 2006-2007, Ext JS, LLC.
13168 * Originally Released Under LGPL - original licence link has changed is not relivant.
13171 * <script type="text/javascript">
13175 * @class Roo.menu.CheckItem
13176 * @extends Roo.menu.Item
13177 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
13179 * Creates a new CheckItem
13180 * @param {Object} config Configuration options
13182 Roo.menu.CheckItem = function(config){
13183 Roo.menu.CheckItem.superclass.constructor.call(this, config);
13186 * @event beforecheckchange
13187 * Fires before the checked value is set, providing an opportunity to cancel if needed
13188 * @param {Roo.menu.CheckItem} this
13189 * @param {Boolean} checked The new checked value that will be set
13191 "beforecheckchange" : true,
13193 * @event checkchange
13194 * Fires after the checked value has been set
13195 * @param {Roo.menu.CheckItem} this
13196 * @param {Boolean} checked The checked value that was set
13198 "checkchange" : true
13200 if(this.checkHandler){
13201 this.on('checkchange', this.checkHandler, this.scope);
13204 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
13206 * @cfg {String} group
13207 * All check items with the same group name will automatically be grouped into a single-select
13208 * radio button group (defaults to '')
13211 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
13213 itemCls : "x-menu-item x-menu-check-item",
13215 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
13217 groupClass : "x-menu-group-item",
13220 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
13221 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
13222 * initialized with checked = true will be rendered as checked.
13227 ctype: "Roo.menu.CheckItem",
13230 onRender : function(c){
13231 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
13233 this.el.addClass(this.groupClass);
13235 Roo.menu.MenuMgr.registerCheckable(this);
13237 this.checked = false;
13238 this.setChecked(true, true);
13243 destroy : function(){
13245 Roo.menu.MenuMgr.unregisterCheckable(this);
13247 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
13251 * Set the checked state of this item
13252 * @param {Boolean} checked The new checked value
13253 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
13255 setChecked : function(state, suppressEvent){
13256 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
13257 if(this.container){
13258 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
13260 this.checked = state;
13261 if(suppressEvent !== true){
13262 this.fireEvent("checkchange", this, state);
13268 handleClick : function(e){
13269 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
13270 this.setChecked(!this.checked);
13272 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
13276 * Ext JS Library 1.1.1
13277 * Copyright(c) 2006-2007, Ext JS, LLC.
13279 * Originally Released Under LGPL - original licence link has changed is not relivant.
13282 * <script type="text/javascript">
13286 * @class Roo.menu.DateItem
13287 * @extends Roo.menu.Adapter
13288 * A menu item that wraps the {@link Roo.DatPicker} component.
13290 * Creates a new DateItem
13291 * @param {Object} config Configuration options
13293 Roo.menu.DateItem = function(config){
13294 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
13295 /** The Roo.DatePicker object @type Roo.DatePicker */
13296 this.picker = this.component;
13297 this.addEvents({select: true});
13299 this.picker.on("render", function(picker){
13300 picker.getEl().swallowEvent("click");
13301 picker.container.addClass("x-menu-date-item");
13304 this.picker.on("select", this.onSelect, this);
13307 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
13309 onSelect : function(picker, date){
13310 this.fireEvent("select", this, date, picker);
13311 Roo.menu.DateItem.superclass.handleClick.call(this);
13315 * Ext JS Library 1.1.1
13316 * Copyright(c) 2006-2007, Ext JS, LLC.
13318 * Originally Released Under LGPL - original licence link has changed is not relivant.
13321 * <script type="text/javascript">
13325 * @class Roo.menu.ColorItem
13326 * @extends Roo.menu.Adapter
13327 * A menu item that wraps the {@link Roo.ColorPalette} component.
13329 * Creates a new ColorItem
13330 * @param {Object} config Configuration options
13332 Roo.menu.ColorItem = function(config){
13333 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
13334 /** The Roo.ColorPalette object @type Roo.ColorPalette */
13335 this.palette = this.component;
13336 this.relayEvents(this.palette, ["select"]);
13337 if(this.selectHandler){
13338 this.on('select', this.selectHandler, this.scope);
13341 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
13343 * Ext JS Library 1.1.1
13344 * Copyright(c) 2006-2007, Ext JS, LLC.
13346 * Originally Released Under LGPL - original licence link has changed is not relivant.
13349 * <script type="text/javascript">
13354 * @class Roo.menu.DateMenu
13355 * @extends Roo.menu.Menu
13356 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
13358 * Creates a new DateMenu
13359 * @param {Object} config Configuration options
13361 Roo.menu.DateMenu = function(config){
13362 Roo.menu.DateMenu.superclass.constructor.call(this, config);
13364 var di = new Roo.menu.DateItem(config);
13367 * The {@link Roo.DatePicker} instance for this DateMenu
13370 this.picker = di.picker;
13373 * @param {DatePicker} picker
13374 * @param {Date} date
13376 this.relayEvents(di, ["select"]);
13378 this.on('beforeshow', function(){
13380 this.picker.hideMonthPicker(true);
13384 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
13388 * Ext JS Library 1.1.1
13389 * Copyright(c) 2006-2007, Ext JS, LLC.
13391 * Originally Released Under LGPL - original licence link has changed is not relivant.
13394 * <script type="text/javascript">
13399 * @class Roo.menu.ColorMenu
13400 * @extends Roo.menu.Menu
13401 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
13403 * Creates a new ColorMenu
13404 * @param {Object} config Configuration options
13406 Roo.menu.ColorMenu = function(config){
13407 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
13409 var ci = new Roo.menu.ColorItem(config);
13412 * The {@link Roo.ColorPalette} instance for this ColorMenu
13413 * @type ColorPalette
13415 this.palette = ci.palette;
13418 * @param {ColorPalette} palette
13419 * @param {String} color
13421 this.relayEvents(ci, ["select"]);
13423 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
13425 * Ext JS Library 1.1.1
13426 * Copyright(c) 2006-2007, Ext JS, LLC.
13428 * Originally Released Under LGPL - original licence link has changed is not relivant.
13431 * <script type="text/javascript">
13435 * @class Roo.form.Field
13436 * @extends Roo.BoxComponent
13437 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
13439 * Creates a new Field
13440 * @param {Object} config Configuration options
13442 Roo.form.Field = function(config){
13443 Roo.form.Field.superclass.constructor.call(this, config);
13446 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
13448 * @cfg {String} fieldLabel Label to use when rendering a form.
13451 * @cfg {String} qtip Mouse over tip
13455 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13457 invalidClass : "x-form-invalid",
13459 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
13461 invalidText : "The value in this field is invalid",
13463 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
13465 focusClass : "x-form-focus",
13467 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
13468 automatic validation (defaults to "keyup").
13470 validationEvent : "keyup",
13472 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
13474 validateOnBlur : true,
13476 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
13478 validationDelay : 250,
13480 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
13481 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
13483 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
13485 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
13487 fieldClass : "x-form-field",
13489 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
13492 ----------- ----------------------------------------------------------------------
13493 qtip Display a quick tip when the user hovers over the field
13494 title Display a default browser title attribute popup
13495 under Add a block div beneath the field containing the error text
13496 side Add an error icon to the right of the field with a popup on hover
13497 [element id] Add the error text directly to the innerHTML of the specified element
13500 msgTarget : 'qtip',
13502 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
13507 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
13512 * @cfg {Boolean} disabled True to disable the field (defaults to false).
13517 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
13519 inputType : undefined,
13522 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
13524 tabIndex : undefined,
13527 isFormField : true,
13532 * @property {Roo.Element} fieldEl
13533 * Element Containing the rendered Field (with label etc.)
13536 * @cfg {Mixed} value A value to initialize this field with.
13541 * @cfg {String} name The field's HTML name attribute.
13544 * @cfg {String} cls A CSS class to apply to the field's underlying element.
13548 initComponent : function(){
13549 Roo.form.Field.superclass.initComponent.call(this);
13553 * Fires when this field receives input focus.
13554 * @param {Roo.form.Field} this
13559 * Fires when this field loses input focus.
13560 * @param {Roo.form.Field} this
13564 * @event specialkey
13565 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13566 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13567 * @param {Roo.form.Field} this
13568 * @param {Roo.EventObject} e The event object
13573 * Fires just before the field blurs if the field value has changed.
13574 * @param {Roo.form.Field} this
13575 * @param {Mixed} newValue The new value
13576 * @param {Mixed} oldValue The original value
13581 * Fires after the field has been marked as invalid.
13582 * @param {Roo.form.Field} this
13583 * @param {String} msg The validation message
13588 * Fires after the field has been validated with no errors.
13589 * @param {Roo.form.Field} this
13596 * Returns the name attribute of the field if available
13597 * @return {String} name The field name
13599 getName: function(){
13600 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
13604 onRender : function(ct, position){
13605 Roo.form.Field.superclass.onRender.call(this, ct, position);
13607 var cfg = this.getAutoCreate();
13609 cfg.name = this.name || this.id;
13611 if(this.inputType){
13612 cfg.type = this.inputType;
13614 this.el = ct.createChild(cfg, position);
13616 var type = this.el.dom.type;
13618 if(type == 'password'){
13621 this.el.addClass('x-form-'+type);
13624 this.el.dom.readOnly = true;
13626 if(this.tabIndex !== undefined){
13627 this.el.dom.setAttribute('tabIndex', this.tabIndex);
13630 this.el.addClass([this.fieldClass, this.cls]);
13635 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
13636 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
13637 * @return {Roo.form.Field} this
13639 applyTo : function(target){
13640 this.allowDomMove = false;
13641 this.el = Roo.get(target);
13642 this.render(this.el.dom.parentNode);
13647 initValue : function(){
13648 if(this.value !== undefined){
13649 this.setValue(this.value);
13650 }else if(this.el.dom.value.length > 0){
13651 this.setValue(this.el.dom.value);
13656 * Returns true if this field has been changed since it was originally loaded and is not disabled.
13658 isDirty : function() {
13659 if(this.disabled) {
13662 return String(this.getValue()) !== String(this.originalValue);
13666 afterRender : function(){
13667 Roo.form.Field.superclass.afterRender.call(this);
13672 fireKey : function(e){
13673 if(e.isNavKeyPress()){
13674 this.fireEvent("specialkey", this, e);
13679 * Resets the current field value to the originally loaded value and clears any validation messages
13681 reset : function(){
13682 this.setValue(this.originalValue);
13683 this.clearInvalid();
13687 initEvents : function(){
13688 this.el.on(Roo.isIE ? "keydown" : "keypress", this.fireKey, this);
13689 this.el.on("focus", this.onFocus, this);
13690 this.el.on("blur", this.onBlur, this);
13692 // reference to original value for reset
13693 this.originalValue = this.getValue();
13697 onFocus : function(){
13698 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
13699 this.el.addClass(this.focusClass);
13701 if(!this.hasFocus){
13702 this.hasFocus = true;
13703 this.startValue = this.getValue();
13704 this.fireEvent("focus", this);
13708 beforeBlur : Roo.emptyFn,
13711 onBlur : function(){
13713 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
13714 this.el.removeClass(this.focusClass);
13716 this.hasFocus = false;
13717 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
13720 var v = this.getValue();
13721 if(String(v) !== String(this.startValue)){
13722 this.fireEvent('change', this, v, this.startValue);
13724 this.fireEvent("blur", this);
13728 * Returns whether or not the field value is currently valid
13729 * @param {Boolean} preventMark True to disable marking the field invalid
13730 * @return {Boolean} True if the value is valid, else false
13732 isValid : function(preventMark){
13736 var restore = this.preventMark;
13737 this.preventMark = preventMark === true;
13738 var v = this.validateValue(this.processValue(this.getRawValue()));
13739 this.preventMark = restore;
13744 * Validates the field value
13745 * @return {Boolean} True if the value is valid, else false
13747 validate : function(){
13748 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
13749 this.clearInvalid();
13755 processValue : function(value){
13760 // Subclasses should provide the validation implementation by overriding this
13761 validateValue : function(value){
13766 * Mark this field as invalid
13767 * @param {String} msg The validation message
13769 markInvalid : function(msg){
13770 if(!this.rendered || this.preventMark){ // not rendered
13773 this.el.addClass(this.invalidClass);
13774 msg = msg || this.invalidText;
13775 switch(this.msgTarget){
13777 this.el.dom.qtip = msg;
13778 this.el.dom.qclass = 'x-form-invalid-tip';
13779 if(Roo.QuickTips){ // fix for floating editors interacting with DND
13780 Roo.QuickTips.enable();
13784 this.el.dom.title = msg;
13788 var elp = this.el.findParent('.x-form-element', 5, true);
13789 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
13790 this.errorEl.setWidth(elp.getWidth(true)-20);
13792 this.errorEl.update(msg);
13793 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
13796 if(!this.errorIcon){
13797 var elp = this.el.findParent('.x-form-element', 5, true);
13798 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
13800 this.alignErrorIcon();
13801 this.errorIcon.dom.qtip = msg;
13802 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
13803 this.errorIcon.show();
13804 this.on('resize', this.alignErrorIcon, this);
13807 var t = Roo.getDom(this.msgTarget);
13809 t.style.display = this.msgDisplay;
13812 this.fireEvent('invalid', this, msg);
13816 alignErrorIcon : function(){
13817 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
13821 * Clear any invalid styles/messages for this field
13823 clearInvalid : function(){
13824 if(!this.rendered || this.preventMark){ // not rendered
13827 this.el.removeClass(this.invalidClass);
13828 switch(this.msgTarget){
13830 this.el.dom.qtip = '';
13833 this.el.dom.title = '';
13837 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
13841 if(this.errorIcon){
13842 this.errorIcon.dom.qtip = '';
13843 this.errorIcon.hide();
13844 this.un('resize', this.alignErrorIcon, this);
13848 var t = Roo.getDom(this.msgTarget);
13850 t.style.display = 'none';
13853 this.fireEvent('valid', this);
13857 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
13858 * @return {Mixed} value The field value
13860 getRawValue : function(){
13861 var v = this.el.getValue();
13862 if(v === this.emptyText){
13869 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
13870 * @return {Mixed} value The field value
13872 getValue : function(){
13873 var v = this.el.getValue();
13874 if(v === this.emptyText || v === undefined){
13881 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
13882 * @param {Mixed} value The value to set
13884 setRawValue : function(v){
13885 return this.el.dom.value = (v === null || v === undefined ? '' : v);
13889 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
13890 * @param {Mixed} value The value to set
13892 setValue : function(v){
13895 this.el.dom.value = (v === null || v === undefined ? '' : v);
13900 adjustSize : function(w, h){
13901 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
13902 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
13906 adjustWidth : function(tag, w){
13907 tag = tag.toLowerCase();
13908 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
13909 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
13910 if(tag == 'input'){
13913 if(tag = 'textarea'){
13916 }else if(Roo.isOpera){
13917 if(tag == 'input'){
13920 if(tag = 'textarea'){
13930 // anything other than normal should be considered experimental
13931 Roo.form.Field.msgFx = {
13933 show: function(msgEl, f){
13934 msgEl.setDisplayed('block');
13937 hide : function(msgEl, f){
13938 msgEl.setDisplayed(false).update('');
13943 show: function(msgEl, f){
13944 msgEl.slideIn('t', {stopFx:true});
13947 hide : function(msgEl, f){
13948 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
13953 show: function(msgEl, f){
13954 msgEl.fixDisplay();
13955 msgEl.alignTo(f.el, 'tl-tr');
13956 msgEl.slideIn('l', {stopFx:true});
13959 hide : function(msgEl, f){
13960 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
13965 * Ext JS Library 1.1.1
13966 * Copyright(c) 2006-2007, Ext JS, LLC.
13968 * Originally Released Under LGPL - original licence link has changed is not relivant.
13971 * <script type="text/javascript">
13976 * @class Roo.form.TextField
13977 * @extends Roo.form.Field
13978 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
13979 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
13981 * Creates a new TextField
13982 * @param {Object} config Configuration options
13984 Roo.form.TextField = function(config){
13985 Roo.form.TextField.superclass.constructor.call(this, config);
13989 * Fires when the autosize function is triggered. The field may or may not have actually changed size
13990 * according to the default logic, but this event provides a hook for the developer to apply additional
13991 * logic at runtime to resize the field if needed.
13992 * @param {Roo.form.Field} this This text field
13993 * @param {Number} width The new field width
13999 Roo.extend(Roo.form.TextField, Roo.form.Field, {
14001 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
14005 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
14009 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
14013 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
14017 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
14021 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
14023 disableKeyFilter : false,
14025 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
14029 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
14033 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
14035 maxLength : Number.MAX_VALUE,
14037 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
14039 minLengthText : "The minimum length for this field is {0}",
14041 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
14043 maxLengthText : "The maximum length for this field is {0}",
14045 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
14047 selectOnFocus : false,
14049 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
14051 blankText : "This field is required",
14053 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
14054 * If available, this function will be called only after the basic validators all return true, and will be passed the
14055 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
14059 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
14060 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
14061 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
14065 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
14069 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
14073 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
14074 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
14076 emptyClass : 'x-form-empty-field',
14079 initEvents : function(){
14080 Roo.form.TextField.superclass.initEvents.call(this);
14081 if(this.validationEvent == 'keyup'){
14082 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
14083 this.el.on('keyup', this.filterValidation, this);
14085 else if(this.validationEvent !== false){
14086 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
14088 if(this.selectOnFocus || this.emptyText){
14089 this.on("focus", this.preFocus, this);
14090 if(this.emptyText){
14091 this.on('blur', this.postBlur, this);
14092 this.applyEmptyText();
14095 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
14096 this.el.on("keypress", this.filterKeys, this);
14099 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
14100 this.el.on("click", this.autoSize, this);
14104 processValue : function(value){
14105 if(this.stripCharsRe){
14106 var newValue = value.replace(this.stripCharsRe, '');
14107 if(newValue !== value){
14108 this.setRawValue(newValue);
14115 filterValidation : function(e){
14116 if(!e.isNavKeyPress()){
14117 this.validationTask.delay(this.validationDelay);
14122 onKeyUp : function(e){
14123 if(!e.isNavKeyPress()){
14129 * Resets the current field value to the originally-loaded value and clears any validation messages.
14130 * Also adds emptyText and emptyClass if the original value was blank.
14132 reset : function(){
14133 Roo.form.TextField.superclass.reset.call(this);
14134 this.applyEmptyText();
14137 applyEmptyText : function(){
14138 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
14139 this.setRawValue(this.emptyText);
14140 this.el.addClass(this.emptyClass);
14145 preFocus : function(){
14146 if(this.emptyText){
14147 if(this.el.dom.value == this.emptyText){
14148 this.setRawValue('');
14150 this.el.removeClass(this.emptyClass);
14152 if(this.selectOnFocus){
14153 this.el.dom.select();
14158 postBlur : function(){
14159 this.applyEmptyText();
14163 filterKeys : function(e){
14164 var k = e.getKey();
14165 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
14168 var c = e.getCharCode(), cc = String.fromCharCode(c);
14169 if(Roo.isIE && (e.isSpecialKey() || !cc)){
14172 if(!this.maskRe.test(cc)){
14177 setValue : function(v){
14178 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
14179 this.el.removeClass(this.emptyClass);
14181 Roo.form.TextField.superclass.setValue.apply(this, arguments);
14182 this.applyEmptyText();
14187 * Validates a value according to the field's validation rules and marks the field as invalid
14188 * if the validation fails
14189 * @param {Mixed} value The value to validate
14190 * @return {Boolean} True if the value is valid, else false
14192 validateValue : function(value){
14193 if(value.length < 1 || value === this.emptyText){ // if it's blank
14194 if(this.allowBlank){
14195 this.clearInvalid();
14198 this.markInvalid(this.blankText);
14202 if(value.length < this.minLength){
14203 this.markInvalid(String.format(this.minLengthText, this.minLength));
14206 if(value.length > this.maxLength){
14207 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
14211 var vt = Roo.form.VTypes;
14212 if(!vt[this.vtype](value, this)){
14213 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
14217 if(typeof this.validator == "function"){
14218 var msg = this.validator(value);
14220 this.markInvalid(msg);
14224 if(this.regex && !this.regex.test(value)){
14225 this.markInvalid(this.regexText);
14232 * Selects text in this field
14233 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
14234 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
14236 selectText : function(start, end){
14237 var v = this.getRawValue();
14239 start = start === undefined ? 0 : start;
14240 end = end === undefined ? v.length : end;
14241 var d = this.el.dom;
14242 if(d.setSelectionRange){
14243 d.setSelectionRange(start, end);
14244 }else if(d.createTextRange){
14245 var range = d.createTextRange();
14246 range.moveStart("character", start);
14247 range.moveEnd("character", v.length-end);
14254 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
14255 * This only takes effect if grow = true, and fires the autosize event.
14257 autoSize : function(){
14258 if(!this.grow || !this.rendered){
14262 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
14265 var v = el.dom.value;
14266 var d = document.createElement('div');
14267 d.appendChild(document.createTextNode(v));
14271 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
14272 this.el.setWidth(w);
14273 this.fireEvent("autosize", this, w);
14277 * Ext JS Library 1.1.1
14278 * Copyright(c) 2006-2007, Ext JS, LLC.
14280 * Originally Released Under LGPL - original licence link has changed is not relivant.
14283 * <script type="text/javascript">
14287 * @class Roo.form.Hidden
14288 * @extends Roo.form.TextField
14289 * Simple Hidden element used on forms
14291 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
14294 * Creates a new Hidden form element.
14295 * @param {Object} config Configuration options
14300 // easy hidden field...
14301 Roo.form.Hidden = function(config){
14302 Roo.form.Hidden.superclass.constructor.call(this, config);
14305 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
14307 inputType: 'hidden',
14310 labelSeparator: '',
14312 itemCls : 'x-form-item-display-none'
14320 * Ext JS Library 1.1.1
14321 * Copyright(c) 2006-2007, Ext JS, LLC.
14323 * Originally Released Under LGPL - original licence link has changed is not relivant.
14326 * <script type="text/javascript">
14330 * @class Roo.form.TriggerField
14331 * @extends Roo.form.TextField
14332 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
14333 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
14334 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
14335 * for which you can provide a custom implementation. For example:
14337 var trigger = new Roo.form.TriggerField();
14338 trigger.onTriggerClick = myTriggerFn;
14339 trigger.applyTo('my-field');
14342 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
14343 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
14344 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
14345 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
14347 * Create a new TriggerField.
14348 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
14349 * to the base TextField)
14351 Roo.form.TriggerField = function(config){
14352 this.mimicing = false;
14353 Roo.form.TriggerField.superclass.constructor.call(this, config);
14356 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
14358 * @cfg {String} triggerClass A CSS class to apply to the trigger
14361 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
14362 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
14364 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
14366 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
14370 /** @cfg {Boolean} grow @hide */
14371 /** @cfg {Number} growMin @hide */
14372 /** @cfg {Number} growMax @hide */
14378 autoSize: Roo.emptyFn,
14382 deferHeight : true,
14385 actionMode : 'wrap',
14387 onResize : function(w, h){
14388 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
14389 if(typeof w == 'number'){
14390 this.el.setWidth(this.adjustWidth('input', w - this.trigger.getWidth()));
14395 adjustSize : Roo.BoxComponent.prototype.adjustSize,
14398 getResizeEl : function(){
14403 getPositionEl : function(){
14408 alignErrorIcon : function(){
14409 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
14413 onRender : function(ct, position){
14414 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
14415 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
14416 this.trigger = this.wrap.createChild(this.triggerConfig ||
14417 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
14418 if(this.hideTrigger){
14419 this.trigger.setDisplayed(false);
14421 this.initTrigger();
14423 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
14428 initTrigger : function(){
14429 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
14430 this.trigger.addClassOnOver('x-form-trigger-over');
14431 this.trigger.addClassOnClick('x-form-trigger-click');
14435 onDestroy : function(){
14437 this.trigger.removeAllListeners();
14438 this.trigger.remove();
14441 this.wrap.remove();
14443 Roo.form.TriggerField.superclass.onDestroy.call(this);
14447 onFocus : function(){
14448 Roo.form.TriggerField.superclass.onFocus.call(this);
14449 if(!this.mimicing){
14450 this.wrap.addClass('x-trigger-wrap-focus');
14451 this.mimicing = true;
14452 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
14453 if(this.monitorTab){
14454 this.el.on("keydown", this.checkTab, this);
14460 checkTab : function(e){
14461 if(e.getKey() == e.TAB){
14462 this.triggerBlur();
14467 onBlur : function(){
14472 mimicBlur : function(e, t){
14473 if(!this.wrap.contains(t) && this.validateBlur()){
14474 this.triggerBlur();
14479 triggerBlur : function(){
14480 this.mimicing = false;
14481 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
14482 if(this.monitorTab){
14483 this.el.un("keydown", this.checkTab, this);
14485 this.wrap.removeClass('x-trigger-wrap-focus');
14486 Roo.form.TriggerField.superclass.onBlur.call(this);
14490 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
14491 validateBlur : function(e, t){
14496 onDisable : function(){
14497 Roo.form.TriggerField.superclass.onDisable.call(this);
14499 this.wrap.addClass('x-item-disabled');
14504 onEnable : function(){
14505 Roo.form.TriggerField.superclass.onEnable.call(this);
14507 this.wrap.removeClass('x-item-disabled');
14512 onShow : function(){
14513 var ae = this.getActionEl();
14516 ae.dom.style.display = '';
14517 ae.dom.style.visibility = 'visible';
14523 onHide : function(){
14524 var ae = this.getActionEl();
14525 ae.dom.style.display = 'none';
14529 * The function that should handle the trigger's click event. This method does nothing by default until overridden
14530 * by an implementing function.
14532 * @param {EventObject} e
14534 onTriggerClick : Roo.emptyFn
14537 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
14538 // to be extended by an implementing class. For an example of implementing this class, see the custom
14539 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
14540 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
14541 initComponent : function(){
14542 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
14544 this.triggerConfig = {
14545 tag:'span', cls:'x-form-twin-triggers', cn:[
14546 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
14547 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
14551 getTrigger : function(index){
14552 return this.triggers[index];
14555 initTrigger : function(){
14556 var ts = this.trigger.select('.x-form-trigger', true);
14557 this.wrap.setStyle('overflow', 'hidden');
14558 var triggerField = this;
14559 ts.each(function(t, all, index){
14560 t.hide = function(){
14561 var w = triggerField.wrap.getWidth();
14562 this.dom.style.display = 'none';
14563 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
14565 t.show = function(){
14566 var w = triggerField.wrap.getWidth();
14567 this.dom.style.display = '';
14568 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
14570 var triggerIndex = 'Trigger'+(index+1);
14572 if(this['hide'+triggerIndex]){
14573 t.dom.style.display = 'none';
14575 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
14576 t.addClassOnOver('x-form-trigger-over');
14577 t.addClassOnClick('x-form-trigger-click');
14579 this.triggers = ts.elements;
14582 onTrigger1Click : Roo.emptyFn,
14583 onTrigger2Click : Roo.emptyFn
14586 * Ext JS Library 1.1.1
14587 * Copyright(c) 2006-2007, Ext JS, LLC.
14589 * Originally Released Under LGPL - original licence link has changed is not relivant.
14592 * <script type="text/javascript">
14596 * @class Roo.form.TextArea
14597 * @extends Roo.form.TextField
14598 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
14599 * support for auto-sizing.
14601 * Creates a new TextArea
14602 * @param {Object} config Configuration options
14604 Roo.form.TextArea = function(config){
14605 Roo.form.TextArea.superclass.constructor.call(this, config);
14606 // these are provided exchanges for backwards compat
14607 // minHeight/maxHeight were replaced by growMin/growMax to be
14608 // compatible with TextField growing config values
14609 if(this.minHeight !== undefined){
14610 this.growMin = this.minHeight;
14612 if(this.maxHeight !== undefined){
14613 this.growMax = this.maxHeight;
14617 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
14619 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
14623 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
14627 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
14628 * in the field (equivalent to setting overflow: hidden, defaults to false)
14630 preventScrollbars: false,
14632 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
14633 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
14637 onRender : function(ct, position){
14639 this.defaultAutoCreate = {
14641 style:"width:300px;height:60px;",
14642 autocomplete: "off"
14645 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
14647 this.textSizeEl = Roo.DomHelper.append(document.body, {
14648 tag: "pre", cls: "x-form-grow-sizer"
14650 if(this.preventScrollbars){
14651 this.el.setStyle("overflow", "hidden");
14653 this.el.setHeight(this.growMin);
14657 onDestroy : function(){
14658 if(this.textSizeEl){
14659 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
14661 Roo.form.TextArea.superclass.onDestroy.call(this);
14665 onKeyUp : function(e){
14666 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
14672 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
14673 * This only takes effect if grow = true, and fires the autosize event if the height changes.
14675 autoSize : function(){
14676 if(!this.grow || !this.textSizeEl){
14680 var v = el.dom.value;
14681 var ts = this.textSizeEl;
14684 ts.appendChild(document.createTextNode(v));
14687 Roo.fly(ts).setWidth(this.el.getWidth());
14689 v = "  ";
14692 v = v.replace(/\n/g, '<p> </p>');
14694 v += " \n ";
14697 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
14698 if(h != this.lastHeight){
14699 this.lastHeight = h;
14700 this.el.setHeight(h);
14701 this.fireEvent("autosize", this, h);
14706 * Ext JS Library 1.1.1
14707 * Copyright(c) 2006-2007, Ext JS, LLC.
14709 * Originally Released Under LGPL - original licence link has changed is not relivant.
14712 * <script type="text/javascript">
14717 * @class Roo.form.NumberField
14718 * @extends Roo.form.TextField
14719 * Numeric text field that provides automatic keystroke filtering and numeric validation.
14721 * Creates a new NumberField
14722 * @param {Object} config Configuration options
14724 Roo.form.NumberField = function(config){
14725 Roo.form.NumberField.superclass.constructor.call(this, config);
14728 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
14730 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
14732 fieldClass: "x-form-field x-form-num-field",
14734 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
14736 allowDecimals : true,
14738 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
14740 decimalSeparator : ".",
14742 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
14744 decimalPrecision : 2,
14746 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
14748 allowNegative : true,
14750 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
14752 minValue : Number.NEGATIVE_INFINITY,
14754 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
14756 maxValue : Number.MAX_VALUE,
14758 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
14760 minText : "The minimum value for this field is {0}",
14762 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
14764 maxText : "The maximum value for this field is {0}",
14766 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
14767 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
14769 nanText : "{0} is not a valid number",
14772 initEvents : function(){
14773 Roo.form.NumberField.superclass.initEvents.call(this);
14774 var allowed = "0123456789";
14775 if(this.allowDecimals){
14776 allowed += this.decimalSeparator;
14778 if(this.allowNegative){
14781 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
14782 var keyPress = function(e){
14783 var k = e.getKey();
14784 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
14787 var c = e.getCharCode();
14788 if(allowed.indexOf(String.fromCharCode(c)) === -1){
14792 this.el.on("keypress", keyPress, this);
14796 validateValue : function(value){
14797 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
14800 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
14803 var num = this.parseValue(value);
14805 this.markInvalid(String.format(this.nanText, value));
14808 if(num < this.minValue){
14809 this.markInvalid(String.format(this.minText, this.minValue));
14812 if(num > this.maxValue){
14813 this.markInvalid(String.format(this.maxText, this.maxValue));
14819 getValue : function(){
14820 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
14824 parseValue : function(value){
14825 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
14826 return isNaN(value) ? '' : value;
14830 fixPrecision : function(value){
14831 var nan = isNaN(value);
14832 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
14833 return nan ? '' : value;
14835 return parseFloat(value).toFixed(this.decimalPrecision);
14838 setValue : function(v){
14839 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
14843 decimalPrecisionFcn : function(v){
14844 return Math.floor(v);
14847 beforeBlur : function(){
14848 var v = this.parseValue(this.getRawValue());
14850 this.setValue(this.fixPrecision(v));
14855 * Ext JS Library 1.1.1
14856 * Copyright(c) 2006-2007, Ext JS, LLC.
14858 * Originally Released Under LGPL - original licence link has changed is not relivant.
14861 * <script type="text/javascript">
14865 * @class Roo.form.DateField
14866 * @extends Roo.form.TriggerField
14867 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
14869 * Create a new DateField
14870 * @param {Object} config
14872 Roo.form.DateField = function(config){
14873 Roo.form.DateField.superclass.constructor.call(this, config);
14879 * Fires when a date is selected
14880 * @param {Roo.form.DateField} combo This combo box
14881 * @param {Date} date The date selected
14888 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
14889 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
14890 this.ddMatch = null;
14891 if(this.disabledDates){
14892 var dd = this.disabledDates;
14894 for(var i = 0; i < dd.length; i++){
14896 if(i != dd.length-1) re += "|";
14898 this.ddMatch = new RegExp(re + ")");
14902 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
14904 * @cfg {String} format
14905 * The default date format string which can be overriden for localization support. The format must be
14906 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14910 * @cfg {String} altFormats
14911 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14912 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14914 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14916 * @cfg {Array} disabledDays
14917 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
14919 disabledDays : null,
14921 * @cfg {String} disabledDaysText
14922 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
14924 disabledDaysText : "Disabled",
14926 * @cfg {Array} disabledDates
14927 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
14928 * expression so they are very powerful. Some examples:
14930 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
14931 * <li>["03/08", "09/16"] would disable those days for every year</li>
14932 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
14933 * <li>["03/../2006"] would disable every day in March 2006</li>
14934 * <li>["^03"] would disable every day in every March</li>
14936 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
14937 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
14939 disabledDates : null,
14941 * @cfg {String} disabledDatesText
14942 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
14944 disabledDatesText : "Disabled",
14946 * @cfg {Date/String} minValue
14947 * The minimum allowed date. Can be either a Javascript date object or a string date in a
14948 * valid format (defaults to null).
14952 * @cfg {Date/String} maxValue
14953 * The maximum allowed date. Can be either a Javascript date object or a string date in a
14954 * valid format (defaults to null).
14958 * @cfg {String} minText
14959 * The error text to display when the date in the cell is before minValue (defaults to
14960 * 'The date in this field must be after {minValue}').
14962 minText : "The date in this field must be equal to or after {0}",
14964 * @cfg {String} maxText
14965 * The error text to display when the date in the cell is after maxValue (defaults to
14966 * 'The date in this field must be before {maxValue}').
14968 maxText : "The date in this field must be equal to or before {0}",
14970 * @cfg {String} invalidText
14971 * The error text to display when the date in the field is invalid (defaults to
14972 * '{value} is not a valid date - it must be in the format {format}').
14974 invalidText : "{0} is not a valid date - it must be in the format {1}",
14976 * @cfg {String} triggerClass
14977 * An additional CSS class used to style the trigger button. The trigger will always get the
14978 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
14979 * which displays a calendar icon).
14981 triggerClass : 'x-form-date-trigger',
14985 * @cfg {bool} useIso
14986 * if enabled, then the date field will use a hidden field to store the
14987 * real value as iso formated date. default (false)
14991 * @cfg {String/Object} autoCreate
14992 * A DomHelper element spec, or true for a default element spec (defaults to
14993 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
14996 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
14999 hiddenField: false,
15001 onRender : function(ct, position)
15003 Roo.form.DateField.superclass.onRender.call(this, ct, position);
15005 this.el.dom.removeAttribute('name');
15006 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
15008 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
15009 // prevent input submission
15010 this.hiddenName = this.name;
15017 validateValue : function(value)
15019 value = this.formatDate(value);
15020 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
15023 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
15026 var svalue = value;
15027 value = this.parseDate(value);
15029 this.markInvalid(String.format(this.invalidText, svalue, this.format));
15032 var time = value.getTime();
15033 if(this.minValue && time < this.minValue.getTime()){
15034 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
15037 if(this.maxValue && time > this.maxValue.getTime()){
15038 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
15041 if(this.disabledDays){
15042 var day = value.getDay();
15043 for(var i = 0; i < this.disabledDays.length; i++) {
15044 if(day === this.disabledDays[i]){
15045 this.markInvalid(this.disabledDaysText);
15050 var fvalue = this.formatDate(value);
15051 if(this.ddMatch && this.ddMatch.test(fvalue)){
15052 this.markInvalid(String.format(this.disabledDatesText, fvalue));
15059 // Provides logic to override the default TriggerField.validateBlur which just returns true
15060 validateBlur : function(){
15061 return !this.menu || !this.menu.isVisible();
15065 * Returns the current date value of the date field.
15066 * @return {Date} The date value
15068 getValue : function(){
15070 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
15074 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
15075 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
15076 * (the default format used is "m/d/y").
15079 //All of these calls set the same date value (May 4, 2006)
15081 //Pass a date object:
15082 var dt = new Date('5/4/06');
15083 dateField.setValue(dt);
15085 //Pass a date string (default format):
15086 dateField.setValue('5/4/06');
15088 //Pass a date string (custom format):
15089 dateField.format = 'Y-m-d';
15090 dateField.setValue('2006-5-4');
15092 * @param {String/Date} date The date or valid date string
15094 setValue : function(date){
15095 if (this.hiddenField) {
15096 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
15098 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
15102 parseDate : function(value){
15103 if(!value || value instanceof Date){
15106 var v = Date.parseDate(value, this.format);
15107 if(!v && this.altFormats){
15108 if(!this.altFormatsArray){
15109 this.altFormatsArray = this.altFormats.split("|");
15111 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15112 v = Date.parseDate(value, this.altFormatsArray[i]);
15119 formatDate : function(date, fmt){
15120 return (!date || !(date instanceof Date)) ?
15121 date : date.dateFormat(fmt || this.format);
15126 select: function(m, d){
15128 this.fireEvent('select', this, d);
15130 show : function(){ // retain focus styling
15134 this.focus.defer(10, this);
15135 var ml = this.menuListeners;
15136 this.menu.un("select", ml.select, this);
15137 this.menu.un("show", ml.show, this);
15138 this.menu.un("hide", ml.hide, this);
15143 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
15144 onTriggerClick : function(){
15148 if(this.menu == null){
15149 this.menu = new Roo.menu.DateMenu();
15151 Roo.apply(this.menu.picker, {
15152 showClear: this.allowBlank,
15153 minDate : this.minValue,
15154 maxDate : this.maxValue,
15155 disabledDatesRE : this.ddMatch,
15156 disabledDatesText : this.disabledDatesText,
15157 disabledDays : this.disabledDays,
15158 disabledDaysText : this.disabledDaysText,
15159 format : this.format,
15160 minText : String.format(this.minText, this.formatDate(this.minValue)),
15161 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
15163 this.menu.on(Roo.apply({}, this.menuListeners, {
15166 this.menu.picker.setValue(this.getValue() || new Date());
15167 this.menu.show(this.el, "tl-bl?");
15170 beforeBlur : function(){
15171 var v = this.parseDate(this.getRawValue());
15177 /** @cfg {Boolean} grow @hide */
15178 /** @cfg {Number} growMin @hide */
15179 /** @cfg {Number} growMax @hide */
15186 * Ext JS Library 1.1.1
15187 * Copyright(c) 2006-2007, Ext JS, LLC.
15189 * Originally Released Under LGPL - original licence link has changed is not relivant.
15192 * <script type="text/javascript">
15197 * @class Roo.form.ComboBox
15198 * @extends Roo.form.TriggerField
15199 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
15201 * Create a new ComboBox.
15202 * @param {Object} config Configuration options
15204 Roo.form.ComboBox = function(config){
15205 Roo.form.ComboBox.superclass.constructor.call(this, config);
15209 * Fires when the dropdown list is expanded
15210 * @param {Roo.form.ComboBox} combo This combo box
15215 * Fires when the dropdown list is collapsed
15216 * @param {Roo.form.ComboBox} combo This combo box
15220 * @event beforeselect
15221 * Fires before a list item is selected. Return false to cancel the selection.
15222 * @param {Roo.form.ComboBox} combo This combo box
15223 * @param {Roo.data.Record} record The data record returned from the underlying store
15224 * @param {Number} index The index of the selected item in the dropdown list
15226 'beforeselect' : true,
15229 * Fires when a list item is selected
15230 * @param {Roo.form.ComboBox} combo This combo box
15231 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
15232 * @param {Number} index The index of the selected item in the dropdown list
15236 * @event beforequery
15237 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
15238 * The event object passed has these properties:
15239 * @param {Roo.form.ComboBox} combo This combo box
15240 * @param {String} query The query
15241 * @param {Boolean} forceAll true to force "all" query
15242 * @param {Boolean} cancel true to cancel the query
15243 * @param {Object} e The query event object
15245 'beforequery': true
15247 if(this.transform){
15248 this.allowDomMove = false;
15249 var s = Roo.getDom(this.transform);
15250 if(!this.hiddenName){
15251 this.hiddenName = s.name;
15254 this.mode = 'local';
15255 var d = [], opts = s.options;
15256 for(var i = 0, len = opts.length;i < len; i++){
15258 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
15260 this.value = value;
15262 d.push([value, o.text]);
15264 this.store = new Roo.data.SimpleStore({
15266 fields: ['value', 'text'],
15269 this.valueField = 'value';
15270 this.displayField = 'text';
15272 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
15273 if(!this.lazyRender){
15274 this.target = true;
15275 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
15276 s.parentNode.removeChild(s); // remove it
15277 this.render(this.el.parentNode);
15279 s.parentNode.removeChild(s); // remove it
15284 this.store = Roo.factory(this.store, Roo.data);
15287 this.selectedIndex = -1;
15288 if(this.mode == 'local'){
15289 if(config.queryDelay === undefined){
15290 this.queryDelay = 10;
15292 if(config.minChars === undefined){
15298 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
15300 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
15303 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
15304 * rendering into an Roo.Editor, defaults to false)
15307 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
15308 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
15311 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
15314 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
15315 * the dropdown list (defaults to undefined, with no header element)
15319 * @cfg {String/Roo.Template} tpl The template to use to render the output
15323 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
15325 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
15327 listWidth: undefined,
15329 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
15330 * mode = 'remote' or 'text' if mode = 'local')
15332 displayField: undefined,
15334 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
15335 * mode = 'remote' or 'value' if mode = 'local').
15336 * Note: use of a valueField requires the user make a selection
15337 * in order for a value to be mapped.
15339 valueField: undefined,
15341 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
15342 * field's data value (defaults to the underlying DOM element's name)
15344 hiddenName: undefined,
15346 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
15350 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
15352 selectedClass: 'x-combo-selected',
15354 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
15355 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
15356 * which displays a downward arrow icon).
15358 triggerClass : 'x-form-arrow-trigger',
15360 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
15364 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
15365 * anchor positions (defaults to 'tl-bl')
15367 listAlign: 'tl-bl?',
15369 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
15373 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
15374 * query specified by the allQuery config option (defaults to 'query')
15376 triggerAction: 'query',
15378 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
15379 * (defaults to 4, does not apply if editable = false)
15383 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
15384 * delay (typeAheadDelay) if it matches a known value (defaults to false)
15388 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
15389 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
15393 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
15394 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
15398 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
15399 * when editable = true (defaults to false)
15401 selectOnFocus:false,
15403 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
15405 queryParam: 'query',
15407 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
15408 * when mode = 'remote' (defaults to 'Loading...')
15410 loadingText: 'Loading...',
15412 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
15416 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
15420 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
15421 * traditional select (defaults to true)
15425 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
15429 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
15433 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
15434 * listWidth has a higher value)
15438 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
15439 * allow the user to set arbitrary text into the field (defaults to false)
15441 forceSelection:false,
15443 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
15444 * if typeAhead = true (defaults to 250)
15446 typeAheadDelay : 250,
15448 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
15449 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
15451 valueNotFoundText : undefined,
15453 * @cfg {bool} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
15455 blockFocus : false,
15458 * @cfg {bool} disableClear Disable showing of clear button.
15460 disableClear : false,
15463 onRender : function(ct, position){
15464 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
15465 if(this.hiddenName){
15466 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
15468 this.hiddenField.value =
15469 this.hiddenValue !== undefined ? this.hiddenValue :
15470 this.value !== undefined ? this.value : '';
15472 // prevent input submission
15473 this.el.dom.removeAttribute('name');
15476 this.el.dom.setAttribute('autocomplete', 'off');
15479 var cls = 'x-combo-list';
15481 this.list = new Roo.Layer({
15482 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
15485 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
15486 this.list.setWidth(lw);
15487 this.list.swallowEvent('mousewheel');
15488 this.assetHeight = 0;
15491 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
15492 this.assetHeight += this.header.getHeight();
15495 this.innerList = this.list.createChild({cls:cls+'-inner'});
15496 this.innerList.on('mouseover', this.onViewOver, this);
15497 this.innerList.on('mousemove', this.onViewMove, this);
15498 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15500 if(this.allowBlank && !this.pageSize && !this.disableClear){
15501 this.footer = this.list.createChild({cls:cls+'-ft'});
15502 this.pageTb = new Roo.Toolbar(this.footer);
15506 this.footer = this.list.createChild({cls:cls+'-ft'});
15507 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
15508 {pageSize: this.pageSize});
15512 if (this.pageTb && this.allowBlank && !this.disableClear) {
15514 this.pageTb.add(new Roo.Toolbar.Fill(), {
15515 cls: 'x-btn-icon x-btn-clear',
15517 handler: function()
15520 _this.clearValue();
15521 _this.onSelect(false, -1);
15526 this.assetHeight += this.footer.getHeight();
15531 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
15534 this.view = new Roo.View(this.innerList, this.tpl, {
15535 singleSelect:true, store: this.store, selectedClass: this.selectedClass
15538 this.view.on('click', this.onViewClick, this);
15540 this.store.on('beforeload', this.onBeforeLoad, this);
15541 this.store.on('load', this.onLoad, this);
15542 this.store.on('loadexception', this.collapse, this);
15544 if(this.resizable){
15545 this.resizer = new Roo.Resizable(this.list, {
15546 pinned:true, handles:'se'
15548 this.resizer.on('resize', function(r, w, h){
15549 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
15550 this.listWidth = w;
15551 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
15552 this.restrictHeight();
15554 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
15556 if(!this.editable){
15557 this.editable = true;
15558 this.setEditable(false);
15563 initEvents : function(){
15564 Roo.form.ComboBox.superclass.initEvents.call(this);
15566 this.keyNav = new Roo.KeyNav(this.el, {
15567 "up" : function(e){
15568 this.inKeyMode = true;
15572 "down" : function(e){
15573 if(!this.isExpanded()){
15574 this.onTriggerClick();
15576 this.inKeyMode = true;
15581 "enter" : function(e){
15582 this.onViewClick();
15586 "esc" : function(e){
15590 "tab" : function(e){
15591 this.onViewClick(false);
15597 doRelay : function(foo, bar, hname){
15598 if(hname == 'down' || this.scope.isExpanded()){
15599 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15606 this.queryDelay = Math.max(this.queryDelay || 10,
15607 this.mode == 'local' ? 10 : 250);
15608 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15609 if(this.typeAhead){
15610 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15612 if(this.editable !== false){
15613 this.el.on("keyup", this.onKeyUp, this);
15615 if(this.forceSelection){
15616 this.on('blur', this.doForce, this);
15620 onDestroy : function(){
15622 this.view.setStore(null);
15623 this.view.el.removeAllListeners();
15624 this.view.el.remove();
15625 this.view.purgeListeners();
15628 this.list.destroy();
15631 this.store.un('beforeload', this.onBeforeLoad, this);
15632 this.store.un('load', this.onLoad, this);
15633 this.store.un('loadexception', this.collapse, this);
15635 Roo.form.ComboBox.superclass.onDestroy.call(this);
15639 fireKey : function(e){
15640 if(e.isNavKeyPress() && !this.list.isVisible()){
15641 this.fireEvent("specialkey", this, e);
15646 onResize: function(w, h){
15647 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
15648 if(this.list && this.listWidth === undefined){
15649 var lw = Math.max(w, this.minListWidth);
15650 this.list.setWidth(lw);
15651 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15656 * Allow or prevent the user from directly editing the field text. If false is passed,
15657 * the user will only be able to select from the items defined in the dropdown list. This method
15658 * is the runtime equivalent of setting the 'editable' config option at config time.
15659 * @param {Boolean} value True to allow the user to directly edit the field text
15661 setEditable : function(value){
15662 if(value == this.editable){
15665 this.editable = value;
15667 this.el.dom.setAttribute('readOnly', true);
15668 this.el.on('mousedown', this.onTriggerClick, this);
15669 this.el.addClass('x-combo-noedit');
15671 this.el.dom.setAttribute('readOnly', false);
15672 this.el.un('mousedown', this.onTriggerClick, this);
15673 this.el.removeClass('x-combo-noedit');
15678 onBeforeLoad : function(){
15679 if(!this.hasFocus){
15682 this.innerList.update(this.loadingText ?
15683 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
15684 this.restrictHeight();
15685 this.selectedIndex = -1;
15689 onLoad : function(){
15690 if(!this.hasFocus){
15693 if(this.store.getCount() > 0){
15695 this.restrictHeight();
15696 if(this.lastQuery == this.allQuery){
15698 this.el.dom.select();
15700 if(!this.selectByValue(this.value, true)){
15701 this.select(0, true);
15705 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
15706 this.taTask.delay(this.typeAheadDelay);
15710 this.onEmptyResults();
15716 onTypeAhead : function(){
15717 if(this.store.getCount() > 0){
15718 var r = this.store.getAt(0);
15719 var newValue = r.data[this.displayField];
15720 var len = newValue.length;
15721 var selStart = this.getRawValue().length;
15722 if(selStart != len){
15723 this.setRawValue(newValue);
15724 this.selectText(selStart, newValue.length);
15730 onSelect : function(record, index){
15731 if(this.fireEvent('beforeselect', this, record, index) !== false){
15732 this.setFromData(index > -1 ? record.data : false);
15734 this.fireEvent('select', this, record, index);
15739 * Returns the currently selected field value or empty string if no value is set.
15740 * @return {String} value The selected value
15742 getValue : function(){
15743 if(this.valueField){
15744 return typeof this.value != 'undefined' ? this.value : '';
15746 return Roo.form.ComboBox.superclass.getValue.call(this);
15751 * Clears any text/value currently set in the field
15753 clearValue : function(){
15754 if(this.hiddenField){
15755 this.hiddenField.value = '';
15758 this.setRawValue('');
15759 this.lastSelectionText = '';
15760 this.applyEmptyText();
15764 * Sets the specified value into the field. If the value finds a match, the corresponding record text
15765 * will be displayed in the field. If the value does not match the data value of an existing item,
15766 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
15767 * Otherwise the field will be blank (although the value will still be set).
15768 * @param {String} value The value to match
15770 setValue : function(v){
15772 if(this.valueField){
15773 var r = this.findRecord(this.valueField, v);
15775 text = r.data[this.displayField];
15776 }else if(this.valueNotFoundText !== undefined){
15777 text = this.valueNotFoundText;
15780 this.lastSelectionText = text;
15781 if(this.hiddenField){
15782 this.hiddenField.value = v;
15784 Roo.form.ComboBox.superclass.setValue.call(this, text);
15788 * @property {Object} the last set data for the element
15793 * Sets the value of the field based on a object which is related to the record format for the store.
15794 * @param {Object} value the value to set as. or false on reset?
15796 setFromData : function(o){
15797 var dv = ''; // display value
15798 var vv = ''; // value value..
15800 if (this.displayField) {
15801 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15803 // this is an error condition!!!
15804 console.log('no value field set for '+ this.name);
15807 if(this.valueField){
15808 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
15810 if(this.hiddenField){
15811 this.hiddenField.value = vv;
15813 this.lastSelectionText = dv;
15814 Roo.form.ComboBox.superclass.setValue.call(this, dv);
15818 // no hidden field.. - we store the value in 'value', but still display
15819 // display field!!!!
15820 this.lastSelectionText = dv;
15821 Roo.form.ComboBox.superclass.setValue.call(this, dv);
15827 reset : function(){
15828 // overridden so that last data is reset..
15829 this.setValue(this.originalValue);
15830 this.clearInvalid();
15831 this.lastData = false;
15834 findRecord : function(prop, value){
15836 if(this.store.getCount() > 0){
15837 this.store.each(function(r){
15838 if(r.data[prop] == value){
15848 onViewMove : function(e, t){
15849 this.inKeyMode = false;
15853 onViewOver : function(e, t){
15854 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
15857 var item = this.view.findItemFromChild(t);
15859 var index = this.view.indexOf(item);
15860 this.select(index, false);
15865 onViewClick : function(doFocus){
15866 var index = this.view.getSelectedIndexes()[0];
15867 var r = this.store.getAt(index);
15869 this.onSelect(r, index);
15871 if(doFocus !== false && !this.blockFocus){
15877 restrictHeight : function(){
15878 this.innerList.dom.style.height = '';
15879 var inner = this.innerList.dom;
15880 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
15881 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
15882 this.list.beginUpdate();
15883 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
15884 this.list.alignTo(this.el, this.listAlign);
15885 this.list.endUpdate();
15889 onEmptyResults : function(){
15894 * Returns true if the dropdown list is expanded, else false.
15896 isExpanded : function(){
15897 return this.list.isVisible();
15901 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
15902 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15903 * @param {String} value The data value of the item to select
15904 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15905 * selected item if it is not currently in view (defaults to true)
15906 * @return {Boolean} True if the value matched an item in the list, else false
15908 selectByValue : function(v, scrollIntoView){
15909 if(v !== undefined && v !== null){
15910 var r = this.findRecord(this.valueField || this.displayField, v);
15912 this.select(this.store.indexOf(r), scrollIntoView);
15920 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
15921 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
15922 * @param {Number} index The zero-based index of the list item to select
15923 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
15924 * selected item if it is not currently in view (defaults to true)
15926 select : function(index, scrollIntoView){
15927 this.selectedIndex = index;
15928 this.view.select(index);
15929 if(scrollIntoView !== false){
15930 var el = this.view.getNode(index);
15932 this.innerList.scrollChildIntoView(el, false);
15938 selectNext : function(){
15939 var ct = this.store.getCount();
15941 if(this.selectedIndex == -1){
15943 }else if(this.selectedIndex < ct-1){
15944 this.select(this.selectedIndex+1);
15950 selectPrev : function(){
15951 var ct = this.store.getCount();
15953 if(this.selectedIndex == -1){
15955 }else if(this.selectedIndex != 0){
15956 this.select(this.selectedIndex-1);
15962 onKeyUp : function(e){
15963 if(this.editable !== false && !e.isSpecialKey()){
15964 this.lastKey = e.getKey();
15965 this.dqTask.delay(this.queryDelay);
15970 validateBlur : function(){
15971 return !this.list || !this.list.isVisible();
15975 initQuery : function(){
15976 this.doQuery(this.getRawValue());
15980 doForce : function(){
15981 if(this.el.dom.value.length > 0){
15982 this.el.dom.value =
15983 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
15984 this.applyEmptyText();
15989 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
15990 * query allowing the query action to be canceled if needed.
15991 * @param {String} query The SQL query to execute
15992 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
15993 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
15994 * saved in the current store (defaults to false)
15996 doQuery : function(q, forceAll){
15997 if(q === undefined || q === null){
16002 forceAll: forceAll,
16006 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
16010 forceAll = qe.forceAll;
16011 if(forceAll === true || (q.length >= this.minChars)){
16012 if(this.lastQuery != q){
16013 this.lastQuery = q;
16014 if(this.mode == 'local'){
16015 this.selectedIndex = -1;
16017 this.store.clearFilter();
16019 this.store.filter(this.displayField, q);
16023 this.store.baseParams[this.queryParam] = q;
16025 params: this.getParams(q)
16030 this.selectedIndex = -1;
16037 getParams : function(q){
16039 //p[this.queryParam] = q;
16042 p.limit = this.pageSize;
16048 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
16050 collapse : function(){
16051 if(!this.isExpanded()){
16055 Roo.get(document).un('mousedown', this.collapseIf, this);
16056 Roo.get(document).un('mousewheel', this.collapseIf, this);
16057 this.fireEvent('collapse', this);
16061 collapseIf : function(e){
16062 if(!e.within(this.wrap) && !e.within(this.list)){
16068 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
16070 expand : function(){
16071 if(this.isExpanded() || !this.hasFocus){
16074 this.list.alignTo(this.el, this.listAlign);
16076 Roo.get(document).on('mousedown', this.collapseIf, this);
16077 Roo.get(document).on('mousewheel', this.collapseIf, this);
16078 this.fireEvent('expand', this);
16082 // Implements the default empty TriggerField.onTriggerClick function
16083 onTriggerClick : function(){
16087 if(this.isExpanded()){
16089 if (!this.blockFocus) {
16094 this.hasFocus = true;
16095 if(this.triggerAction == 'all') {
16096 this.doQuery(this.allQuery, true);
16098 this.doQuery(this.getRawValue());
16100 if (!this.blockFocus) {
16107 * @cfg {Boolean} grow
16111 * @cfg {Number} growMin
16115 * @cfg {Number} growMax
16124 * Ext JS Library 1.1.1
16125 * Copyright(c) 2006-2007, Ext JS, LLC.
16127 * Originally Released Under LGPL - original licence link has changed is not relivant.
16130 * <script type="text/javascript">
16133 * @class Roo.form.Checkbox
16134 * @extends Roo.form.Field
16135 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
16137 * Creates a new Checkbox
16138 * @param {Object} config Configuration options
16140 Roo.form.Checkbox = function(config){
16141 Roo.form.Checkbox.superclass.constructor.call(this, config);
16145 * Fires when the checkbox is checked or unchecked.
16146 * @param {Roo.form.Checkbox} this This checkbox
16147 * @param {Boolean} checked The new checked value
16153 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
16155 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
16157 focusClass : undefined,
16159 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
16161 fieldClass: "x-form-field",
16163 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
16167 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
16168 * {tag: "input", type: "checkbox", autocomplete: "off"})
16170 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
16172 * @cfg {String} boxLabel The text that appears beside the checkbox
16176 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
16180 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16182 valueOff: '0', // value when not checked..
16184 actionMode : 'viewEl',
16187 itemCls : 'x-menu-check-item x-form-item',
16188 groupClass : 'x-menu-group-item',
16189 inputType : 'hidden',
16192 inSetChecked: false, // check that we are not calling self...
16194 inputElement: false, // real input element?
16195 basedOn: false, // ????
16197 isFormField: true, // not sure where this is needed!!!!
16199 onResize : function(){
16200 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
16201 if(!this.boxLabel){
16202 this.el.alignTo(this.wrap, 'c-c');
16206 initEvents : function(){
16207 Roo.form.Checkbox.superclass.initEvents.call(this);
16208 this.el.on("click", this.onClick, this);
16209 this.el.on("change", this.onClick, this);
16213 getResizeEl : function(){
16217 getPositionEl : function(){
16222 onRender : function(ct, position){
16223 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
16225 if(this.inputValue !== undefined){
16226 this.el.dom.value = this.inputValue;
16229 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
16230 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
16231 var viewEl = this.wrap.createChild({
16232 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
16233 this.viewEl = viewEl;
16234 this.wrap.on('click', this.onClick, this);
16236 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
16237 this.el.on('propertychange', this.setFromHidden, this); //ie
16242 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
16243 // viewEl.on('click', this.onClick, this);
16245 //if(this.checked){
16246 this.setChecked(this.checked);
16248 //this.checked = this.el.dom;
16254 initValue : Roo.emptyFn,
16257 * Returns the checked state of the checkbox.
16258 * @return {Boolean} True if checked, else false
16260 getValue : function(){
16262 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
16264 return this.valueOff;
16269 onClick : function(){
16270 this.setChecked(!this.checked);
16272 //if(this.el.dom.checked != this.checked){
16273 // this.setValue(this.el.dom.checked);
16278 * Sets the checked state of the checkbox.
16279 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
16281 setValue : function(v,suppressEvent){
16282 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
16283 //if(this.el && this.el.dom){
16284 // this.el.dom.checked = this.checked;
16285 // this.el.dom.defaultChecked = this.checked;
16287 this.setChecked(v === this.inputValue);
16288 //this.fireEvent("check", this, this.checked);
16291 setChecked : function(state,suppressEvent)
16293 if (this.inSetChecked) {
16294 this.checked = state;
16300 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
16302 this.checked = state;
16303 if(suppressEvent !== true){
16304 this.fireEvent('checkchange', this, state);
16306 this.inSetChecked = true;
16307 this.el.dom.value = state ? this.inputValue : this.valueOff;
16308 this.inSetChecked = false;
16311 // handle setting of hidden value by some other method!!?!?
16312 setFromHidden: function()
16317 //console.log("SET FROM HIDDEN");
16318 //alert('setFrom hidden');
16319 this.setValue(this.el.dom.value);
16322 onDestroy : function()
16325 Roo.get(this.viewEl).remove();
16328 Roo.form.Checkbox.superclass.onDestroy.call(this);
16333 * Ext JS Library 1.1.1
16334 * Copyright(c) 2006-2007, Ext JS, LLC.
16336 * Originally Released Under LGPL - original licence link has changed is not relivant.
16339 * <script type="text/javascript">
16343 * @class Roo.form.Radio
16344 * @extends Roo.form.Checkbox
16345 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
16346 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
16348 * Creates a new Radio
16349 * @param {Object} config Configuration options
16351 Roo.form.Radio = function(){
16352 Roo.form.Radio.superclass.constructor.apply(this, arguments);
16354 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
16355 inputType: 'radio',
16358 * If this radio is part of a group, it will return the selected value
16361 getGroupValue : function(){
16362 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
16364 });//<script type="text/javascript">
16367 * Ext JS Library 1.1.1
16368 * Copyright(c) 2006-2007, Ext JS, LLC.
16369 * licensing@extjs.com
16371 * http://www.extjs.com/license
16377 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
16378 * - IE ? - no idea how much works there.
16386 * @class Ext.form.HtmlEditor
16387 * @extends Ext.form.Field
16388 * Provides a lightweight HTML Editor component.
16389 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
16391 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
16392 * supported by this editor.</b><br/><br/>
16393 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
16394 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16396 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
16398 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
16402 * @cfg {String} createLinkText The default text for the create link prompt
16404 createLinkText : 'Please enter the URL for the link:',
16406 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
16408 defaultLinkValue : 'http:/'+'/',
16414 // private properties
16415 validationEvent : false,
16417 initialized : false,
16419 sourceEditMode : false,
16420 onFocus : Roo.emptyFn,
16422 hideMode:'offsets',
16423 defaultAutoCreate : {
16425 style:"width:500px;height:300px;",
16426 autocomplete: "off"
16430 initComponent : function(){
16433 * @event initialize
16434 * Fires when the editor is fully initialized (including the iframe)
16435 * @param {HtmlEditor} this
16440 * Fires when the editor is first receives the focus. Any insertion must wait
16441 * until after this event.
16442 * @param {HtmlEditor} this
16446 * @event beforesync
16447 * Fires before the textarea is updated with content from the editor iframe. Return false
16448 * to cancel the sync.
16449 * @param {HtmlEditor} this
16450 * @param {String} html
16454 * @event beforepush
16455 * Fires before the iframe editor is updated with content from the textarea. Return false
16456 * to cancel the push.
16457 * @param {HtmlEditor} this
16458 * @param {String} html
16463 * Fires when the textarea is updated with content from the editor iframe.
16464 * @param {HtmlEditor} this
16465 * @param {String} html
16470 * Fires when the iframe editor is updated with content from the textarea.
16471 * @param {HtmlEditor} this
16472 * @param {String} html
16476 * @event editmodechange
16477 * Fires when the editor switches edit modes
16478 * @param {HtmlEditor} this
16479 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
16481 editmodechange: true,
16483 * @event editorevent
16484 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16485 * @param {HtmlEditor} this
16492 * Protected method that will not generally be called directly. It
16493 * is called when the editor creates its toolbar. Override this method if you need to
16494 * add custom toolbar buttons.
16495 * @param {HtmlEditor} editor
16497 createToolbar : function(editor){
16498 if (!editor.toolbars || !editor.toolbars.length) {
16499 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
16502 for (var i =0 ; i < editor.toolbars.length;i++) {
16503 editor.toolbars[i].init(editor);
16510 * Protected method that will not generally be called directly. It
16511 * is called when the editor initializes the iframe with HTML contents. Override this method if you
16512 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16514 getDocMarkup : function(){
16515 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
16519 onRender : function(ct, position){
16520 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
16521 this.el.dom.style.border = '0 none';
16522 this.el.dom.setAttribute('tabIndex', -1);
16523 this.el.addClass('x-hidden');
16524 if(Roo.isIE){ // fix IE 1px bogus margin
16525 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16527 this.wrap = this.el.wrap({
16528 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16531 this.frameId = Roo.id();
16532 this.createToolbar(this);
16539 var iframe = this.wrap.createChild({
16542 name: this.frameId,
16543 frameBorder : 'no',
16544 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
16547 // console.log(iframe);
16548 //this.wrap.dom.appendChild(iframe);
16550 this.iframe = iframe.dom;
16552 this.assignDocWin();
16554 this.doc.designMode = 'on';
16557 this.doc.write(this.getDocMarkup());
16561 var task = { // must defer to wait for browser to be ready
16563 //console.log("run task?" + this.doc.readyState);
16564 this.assignDocWin();
16565 if(this.doc.body || this.doc.readyState == 'complete'){
16569 this.doc.designMode="on";
16573 Roo.TaskMgr.stop(task);
16574 this.initEditor.defer(10, this);
16581 Roo.TaskMgr.start(task);
16584 this.setSize(this.el.getSize());
16589 onResize : function(w, h){
16590 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
16591 if(this.el && this.iframe){
16592 if(typeof w == 'number'){
16593 var aw = w - this.wrap.getFrameWidth('lr');
16594 this.el.setWidth(this.adjustWidth('textarea', aw));
16595 this.iframe.style.width = aw + 'px';
16597 if(typeof h == 'number'){
16599 for (var i =0; i < this.toolbars.length;i++) {
16600 // fixme - ask toolbars for heights?
16601 tbh += this.toolbars[i].tb.el.getHeight();
16607 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16608 this.el.setHeight(this.adjustWidth('textarea', ah));
16609 this.iframe.style.height = ah + 'px';
16611 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
16618 * Toggles the editor between standard and source edit mode.
16619 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16621 toggleSourceEdit : function(sourceEditMode){
16623 this.sourceEditMode = sourceEditMode === true;
16625 if(this.sourceEditMode){
16628 this.iframe.className = 'x-hidden';
16629 this.el.removeClass('x-hidden');
16630 this.el.dom.removeAttribute('tabIndex');
16635 this.iframe.className = '';
16636 this.el.addClass('x-hidden');
16637 this.el.dom.setAttribute('tabIndex', -1);
16640 this.setSize(this.wrap.getSize());
16641 this.fireEvent('editmodechange', this, this.sourceEditMode);
16644 // private used internally
16645 createLink : function(){
16646 var url = prompt(this.createLinkText, this.defaultLinkValue);
16647 if(url && url != 'http:/'+'/'){
16648 this.relayCmd('createlink', url);
16652 // private (for BoxComponent)
16653 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16655 // private (for BoxComponent)
16656 getResizeEl : function(){
16660 // private (for BoxComponent)
16661 getPositionEl : function(){
16666 initEvents : function(){
16667 this.originalValue = this.getValue();
16671 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16674 markInvalid : Roo.emptyFn,
16676 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16679 clearInvalid : Roo.emptyFn,
16681 setValue : function(v){
16682 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
16687 * Protected method that will not generally be called directly. If you need/want
16688 * custom HTML cleanup, this is the method you should override.
16689 * @param {String} html The HTML to be cleaned
16690 * return {String} The cleaned HTML
16692 cleanHtml : function(html){
16693 html = String(html);
16694 if(html.length > 5){
16695 if(Roo.isSafari){ // strip safari nonsense
16696 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16699 if(html == ' '){
16706 * Protected method that will not generally be called directly. Syncs the contents
16707 * of the editor iframe with the textarea.
16709 syncValue : function(){
16710 if(this.initialized){
16711 var bd = (this.doc.body || this.doc.documentElement);
16712 var html = bd.innerHTML;
16714 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16715 var m = bs.match(/text-align:(.*?);/i);
16717 html = '<div style="'+m[0]+'">' + html + '</div>';
16720 html = this.cleanHtml(html);
16721 if(this.fireEvent('beforesync', this, html) !== false){
16722 this.el.dom.value = html;
16723 this.fireEvent('sync', this, html);
16729 * Protected method that will not generally be called directly. Pushes the value of the textarea
16730 * into the iframe editor.
16732 pushValue : function(){
16733 if(this.initialized){
16734 var v = this.el.dom.value;
16738 if(this.fireEvent('beforepush', this, v) !== false){
16739 (this.doc.body || this.doc.documentElement).innerHTML = v;
16740 this.fireEvent('push', this, v);
16746 deferFocus : function(){
16747 this.focus.defer(10, this);
16751 focus : function(){
16752 if(this.win && !this.sourceEditMode){
16759 assignDocWin: function()
16761 var iframe = this.iframe;
16764 this.doc = iframe.contentWindow.document;
16765 this.win = iframe.contentWindow;
16767 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16768 this.win = Roo.get(this.frameId).dom.contentWindow;
16773 initEditor : function(){
16774 //console.log("INIT EDITOR");
16775 this.assignDocWin();
16779 this.doc.designMode="on";
16781 this.doc.write(this.getDocMarkup());
16784 var dbody = (this.doc.body || this.doc.documentElement);
16785 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16786 // this copies styles from the containing element into thsi one..
16787 // not sure why we need all of this..
16788 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16789 ss['background-attachment'] = 'fixed'; // w3c
16790 dbody.bgProperties = 'fixed'; // ie
16791 Roo.DomHelper.applyStyles(dbody, ss);
16792 Roo.EventManager.on(this.doc, {
16793 'mousedown': this.onEditorEvent,
16794 'dblclick': this.onEditorEvent,
16795 'click': this.onEditorEvent,
16796 'keyup': this.onEditorEvent,
16801 Roo.EventManager.on(this.doc, 'keypress', this.applyCommand, this);
16803 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16804 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16806 this.initialized = true;
16808 this.fireEvent('initialize', this);
16813 onDestroy : function(){
16819 for (var i =0; i < this.toolbars.length;i++) {
16820 // fixme - ask toolbars for heights?
16821 this.toolbars[i].onDestroy();
16824 this.wrap.dom.innerHTML = '';
16825 this.wrap.remove();
16830 onFirstFocus : function(){
16832 this.assignDocWin();
16835 this.activated = true;
16836 for (var i =0; i < this.toolbars.length;i++) {
16837 this.toolbars[i].onFirstFocus();
16840 if(Roo.isGecko){ // prevent silly gecko errors
16842 var s = this.win.getSelection();
16843 if(!s.focusNode || s.focusNode.nodeType != 3){
16844 var r = s.getRangeAt(0);
16845 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16850 this.execCmd('useCSS', true);
16851 this.execCmd('styleWithCSS', false);
16854 this.fireEvent('activate', this);
16858 adjustFont: function(btn){
16859 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16860 //if(Roo.isSafari){ // safari
16863 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16864 if(Roo.isSafari){ // safari
16865 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16866 v = (v < 10) ? 10 : v;
16867 v = (v > 48) ? 48 : v;
16868 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16873 v = Math.max(1, v+adjust);
16875 this.execCmd('FontSize', v );
16878 onEditorEvent : function(e){
16879 this.fireEvent('editorevent', this, e);
16880 // this.updateToolbar();
16884 insertTag : function(tg)
16886 // could be a bit smarter... -> wrap the current selected tRoo..
16888 this.execCmd("formatblock", tg);
16892 insertText : function(txt)
16896 range = this.createRange();
16897 range.deleteContents();
16898 //alert(Sender.getAttribute('label'));
16900 range.insertNode(this.doc.createTextNode(txt));
16904 relayBtnCmd : function(btn){
16905 this.relayCmd(btn.cmd);
16909 * Executes a Midas editor command on the editor document and performs necessary focus and
16910 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16911 * @param {String} cmd The Midas command
16912 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16914 relayCmd : function(cmd, value){
16916 this.execCmd(cmd, value);
16917 this.fireEvent('editorevent', this);
16918 //this.updateToolbar();
16923 * Executes a Midas editor command directly on the editor document.
16924 * For visual commands, you should use {@link #relayCmd} instead.
16925 * <b>This should only be called after the editor is initialized.</b>
16926 * @param {String} cmd The Midas command
16927 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16929 execCmd : function(cmd, value){
16930 this.doc.execCommand(cmd, false, value === undefined ? null : value);
16935 applyCommand : function(e){
16937 var c = e.getCharCode(), cmd;
16939 c = String.fromCharCode(c);
16955 e.preventDefault();
16962 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16964 * @param {String} text
16966 insertAtCursor : function(text){
16967 if(!this.activated){
16972 var r = this.doc.selection.createRange();
16979 }else if(Roo.isGecko || Roo.isOpera){
16981 this.execCmd('InsertHTML', text);
16983 }else if(Roo.isSafari){
16984 this.execCmd('InsertText', text);
16990 fixKeys : function(){ // load time branching for fastest keydown performance
16992 return function(e){
16993 var k = e.getKey(), r;
16996 r = this.doc.selection.createRange();
16999 r.pasteHTML('    ');
17002 }else if(k == e.ENTER){
17003 r = this.doc.selection.createRange();
17005 var target = r.parentElement();
17006 if(!target || target.tagName.toLowerCase() != 'li'){
17008 r.pasteHTML('<br />');
17015 }else if(Roo.isOpera){
17016 return function(e){
17017 var k = e.getKey();
17021 this.execCmd('InsertHTML','    ');
17025 }else if(Roo.isSafari){
17026 return function(e){
17027 var k = e.getKey();
17030 this.execCmd('InsertText','\t');
17037 getAllAncestors: function()
17039 var p = this.getSelectedNode();
17042 a.push(p); // push blank onto stack..
17043 p = this.getParentElement();
17047 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17051 a.push(this.doc.body);
17055 lastSelNode : false,
17058 getSelection : function()
17060 this.assignDocWin();
17061 return Roo.isIE ? this.doc.selection : this.win.getSelection();
17064 getSelectedNode: function()
17066 // this may only work on Gecko!!!
17068 // should we cache this!!!!
17073 var range = this.createRange(this.getSelection());
17076 var parent = range.parentElement();
17078 var testRange = range.duplicate();
17079 testRange.moveToElementText(parent);
17080 if (testRange.inRange(range)) {
17083 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17086 parent = parent.parentElement;
17092 var ar = range.endContainer.childNodes;
17094 ar = range.commonAncestorContainer.childNodes;
17095 //alert(ar.length);
17098 var other_nodes = [];
17099 var has_other_nodes = false;
17100 for (var i=0;i<ar.length;i++) {
17101 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
17104 // fullly contained node.
17106 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17111 // probably selected..
17112 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17113 other_nodes.push(ar[i]);
17116 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
17121 has_other_nodes = true;
17123 if (!nodes.length && other_nodes.length) {
17124 nodes= other_nodes;
17126 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17132 createRange: function(sel)
17134 // this has strange effects when using with
17135 // top toolbar - not sure if it's a great idea.
17136 //this.editor.contentWindow.focus();
17137 if (typeof sel != "undefined") {
17139 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17141 return this.doc.createRange();
17144 return this.doc.createRange();
17147 getParentElement: function()
17150 this.assignDocWin();
17151 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17153 var range = this.createRange(sel);
17156 var p = range.commonAncestorContainer;
17157 while (p.nodeType == 3) { // text node
17169 // BC Hacks - cause I cant work out what i was trying to do..
17170 rangeIntersectsNode : function(range, node)
17172 var nodeRange = node.ownerDocument.createRange();
17174 nodeRange.selectNode(node);
17177 nodeRange.selectNodeContents(node);
17180 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
17181 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
17183 rangeCompareNode : function(range, node) {
17184 var nodeRange = node.ownerDocument.createRange();
17186 nodeRange.selectNode(node);
17188 nodeRange.selectNodeContents(node);
17190 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
17191 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
17193 if (nodeIsBefore && !nodeIsAfter)
17195 if (!nodeIsBefore && nodeIsAfter)
17197 if (nodeIsBefore && nodeIsAfter)
17205 // hide stuff that is not compatible
17219 * @event specialkey
17223 * @cfg {String} fieldClass @hide
17226 * @cfg {String} focusClass @hide
17229 * @cfg {String} autoCreate @hide
17232 * @cfg {String} inputType @hide
17235 * @cfg {String} invalidClass @hide
17238 * @cfg {String} invalidText @hide
17241 * @cfg {String} msgFx @hide
17244 * @cfg {String} validateOnBlur @hide
17246 });// <script type="text/javascript">
17249 * Ext JS Library 1.1.1
17250 * Copyright(c) 2006-2007, Ext JS, LLC.
17256 * @class Roo.form.HtmlEditorToolbar1
17261 new Roo.form.HtmlEditor({
17264 new Roo.form.HtmlEditorToolbar1({
17265 disable : { fonts: 1 , format: 1, ..., ... , ...],
17271 * @cfg {Object} disable List of elements to disable..
17272 * @cfg {Array} btns List of additional buttons.
17276 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17279 Roo.form.HtmlEditor.ToolbarStandard = function(config)
17282 Roo.apply(this, config);
17283 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17284 // dont call parent... till later.
17287 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
17295 * @cfg {Object} disable List of toolbar elements to disable
17300 * @cfg {Array} fontFamilies An array of available font families
17318 // "á" , ?? a acute?
17323 "°" // , // degrees
17325 // "é" , // e ecute
17326 // "ú" , // u ecute?
17329 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
17330 "input:submit", "input:button", "select", "textarea", "label" ],
17333 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
17335 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
17338 * @cfg {String} defaultFont default font to use.
17340 defaultFont: 'tahoma',
17342 fontSelect : false,
17345 formatCombo : false,
17347 init : function(editor)
17349 this.editor = editor;
17352 var fid = editor.frameId;
17354 function btn(id, toggle, handler){
17355 var xid = fid + '-'+ id ;
17359 cls : 'x-btn-icon x-edit-'+id,
17360 enableToggle:toggle !== false,
17361 scope: editor, // was editor...
17362 handler:handler||editor.relayBtnCmd,
17363 clickEvent:'mousedown',
17364 tooltip: etb.buttonTips[id] || undefined, ///tips ???
17371 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
17373 // stop form submits
17374 tb.el.on('click', function(e){
17375 e.preventDefault(); // what does this do?
17378 if(!this.disable.font && !Roo.isSafari){
17379 /* why no safari for fonts
17380 editor.fontSelect = tb.el.createChild({
17383 cls:'x-font-select',
17384 html: editor.createFontOptions()
17386 editor.fontSelect.on('change', function(){
17387 var font = editor.fontSelect.dom.value;
17388 editor.relayCmd('fontname', font);
17389 editor.deferFocus();
17392 editor.fontSelect.dom,
17397 if(!this.disable.formats){
17398 this.formatCombo = new Roo.form.ComboBox({
17399 store: new Roo.data.SimpleStore({
17402 data : this.formats // from states.js
17405 //autoCreate : {tag: "div", size: "20"},
17406 displayField:'tag',
17410 triggerAction: 'all',
17411 emptyText:'Add tag',
17412 selectOnFocus:true,
17415 'select': function(c, r, i) {
17416 editor.insertTag(r.get('tag'));
17422 tb.addField(this.formatCombo);
17426 if(!this.disable.format){
17433 if(!this.disable.fontSize){
17438 btn('increasefontsize', false, editor.adjustFont),
17439 btn('decreasefontsize', false, editor.adjustFont)
17444 if(this.disable.colors){
17447 id:editor.frameId +'-forecolor',
17448 cls:'x-btn-icon x-edit-forecolor',
17449 clickEvent:'mousedown',
17450 tooltip: this.buttonTips['forecolor'] || undefined,
17452 menu : new Roo.menu.ColorMenu({
17453 allowReselect: true,
17454 focus: Roo.emptyFn,
17457 selectHandler: function(cp, color){
17458 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
17459 editor.deferFocus();
17462 clickEvent:'mousedown'
17465 id:editor.frameId +'backcolor',
17466 cls:'x-btn-icon x-edit-backcolor',
17467 clickEvent:'mousedown',
17468 tooltip: this.buttonTips['backcolor'] || undefined,
17470 menu : new Roo.menu.ColorMenu({
17471 focus: Roo.emptyFn,
17474 allowReselect: true,
17475 selectHandler: function(cp, color){
17477 editor.execCmd('useCSS', false);
17478 editor.execCmd('hilitecolor', color);
17479 editor.execCmd('useCSS', true);
17480 editor.deferFocus();
17482 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
17483 Roo.isSafari || Roo.isIE ? '#'+color : color);
17484 editor.deferFocus();
17488 clickEvent:'mousedown'
17493 // now add all the items...
17496 if(!this.disable.alignments){
17499 btn('justifyleft'),
17500 btn('justifycenter'),
17501 btn('justifyright')
17505 //if(!Roo.isSafari){
17506 if(!this.disable.links){
17509 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
17513 if(!this.disable.lists){
17516 btn('insertorderedlist'),
17517 btn('insertunorderedlist')
17520 if(!this.disable.sourceEdit){
17523 btn('sourceedit', true, function(btn){
17524 this.toggleSourceEdit(btn.pressed);
17531 // special menu.. - needs to be tidied up..
17532 if (!this.disable.special) {
17535 cls: 'x-edit-none',
17540 for (var i =0; i < this.specialChars.length; i++) {
17541 smenu.menu.items.push({
17543 text: this.specialChars[i],
17544 handler: function(a,b) {
17545 editor.insertAtCursor(String.fromCharCode(a.text.replace('&#','').replace(';', '')));
17557 for(var i =0; i< this.btns.length;i++) {
17558 var b = this.btns[i];
17559 b.cls = 'x-edit-none';
17568 // disable everything...
17570 this.tb.items.each(function(item){
17571 if(item.id != editor.frameId+ '-sourceedit'){
17575 this.rendered = true;
17577 // the all the btns;
17578 editor.on('editorevent', this.updateToolbar, this);
17579 // other toolbars need to implement this..
17580 //editor.on('editmodechange', this.updateToolbar, this);
17586 * Protected method that will not generally be called directly. It triggers
17587 * a toolbar update by reading the markup state of the current selection in the editor.
17589 updateToolbar: function(){
17591 if(!this.editor.activated){
17592 this.editor.onFirstFocus();
17596 var btns = this.tb.items.map,
17597 doc = this.editor.doc,
17598 frameId = this.editor.frameId;
17600 if(!this.disable.font && !Roo.isSafari){
17602 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
17603 if(name != this.fontSelect.dom.value){
17604 this.fontSelect.dom.value = name;
17608 if(!this.disable.format){
17609 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
17610 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
17611 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
17613 if(!this.disable.alignments){
17614 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
17615 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
17616 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
17618 if(!Roo.isSafari && !this.disable.lists){
17619 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
17620 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
17623 var ans = this.editor.getAllAncestors();
17624 if (this.formatCombo) {
17627 var store = this.formatCombo.store;
17628 this.formatCombo.setValue("");
17629 for (var i =0; i < ans.length;i++) {
17630 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), true).length) {
17632 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17640 // hides menus... - so this cant be on a menu...
17641 Roo.menu.MenuMgr.hideAll();
17643 //this.editorsyncValue();
17647 createFontOptions : function(){
17648 var buf = [], fs = this.fontFamilies, ff, lc;
17649 for(var i = 0, len = fs.length; i< len; i++){
17651 lc = ff.toLowerCase();
17653 '<option value="',lc,'" style="font-family:',ff,';"',
17654 (this.defaultFont == lc ? ' selected="true">' : '>'),
17659 return buf.join('');
17662 toggleSourceEdit : function(sourceEditMode){
17663 if(sourceEditMode === undefined){
17664 sourceEditMode = !this.sourceEditMode;
17666 this.sourceEditMode = sourceEditMode === true;
17667 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
17668 // just toggle the button?
17669 if(btn.pressed !== this.editor.sourceEditMode){
17670 btn.toggle(this.editor.sourceEditMode);
17674 if(this.sourceEditMode){
17675 this.tb.items.each(function(item){
17676 if(item.cmd != 'sourceedit'){
17682 if(this.initialized){
17683 this.tb.items.each(function(item){
17689 // tell the editor that it's been pressed..
17690 this.editor.toggleSourceEdit(sourceEditMode);
17694 * Object collection of toolbar tooltips for the buttons in the editor. The key
17695 * is the command id associated with that button and the value is a valid QuickTips object.
17700 title: 'Bold (Ctrl+B)',
17701 text: 'Make the selected text bold.',
17702 cls: 'x-html-editor-tip'
17705 title: 'Italic (Ctrl+I)',
17706 text: 'Make the selected text italic.',
17707 cls: 'x-html-editor-tip'
17715 title: 'Bold (Ctrl+B)',
17716 text: 'Make the selected text bold.',
17717 cls: 'x-html-editor-tip'
17720 title: 'Italic (Ctrl+I)',
17721 text: 'Make the selected text italic.',
17722 cls: 'x-html-editor-tip'
17725 title: 'Underline (Ctrl+U)',
17726 text: 'Underline the selected text.',
17727 cls: 'x-html-editor-tip'
17729 increasefontsize : {
17730 title: 'Grow Text',
17731 text: 'Increase the font size.',
17732 cls: 'x-html-editor-tip'
17734 decreasefontsize : {
17735 title: 'Shrink Text',
17736 text: 'Decrease the font size.',
17737 cls: 'x-html-editor-tip'
17740 title: 'Text Highlight Color',
17741 text: 'Change the background color of the selected text.',
17742 cls: 'x-html-editor-tip'
17745 title: 'Font Color',
17746 text: 'Change the color of the selected text.',
17747 cls: 'x-html-editor-tip'
17750 title: 'Align Text Left',
17751 text: 'Align text to the left.',
17752 cls: 'x-html-editor-tip'
17755 title: 'Center Text',
17756 text: 'Center text in the editor.',
17757 cls: 'x-html-editor-tip'
17760 title: 'Align Text Right',
17761 text: 'Align text to the right.',
17762 cls: 'x-html-editor-tip'
17764 insertunorderedlist : {
17765 title: 'Bullet List',
17766 text: 'Start a bulleted list.',
17767 cls: 'x-html-editor-tip'
17769 insertorderedlist : {
17770 title: 'Numbered List',
17771 text: 'Start a numbered list.',
17772 cls: 'x-html-editor-tip'
17775 title: 'Hyperlink',
17776 text: 'Make the selected text a hyperlink.',
17777 cls: 'x-html-editor-tip'
17780 title: 'Source Edit',
17781 text: 'Switch to source editing mode.',
17782 cls: 'x-html-editor-tip'
17786 onDestroy : function(){
17789 this.tb.items.each(function(item){
17791 item.menu.removeAll();
17793 item.menu.el.destroy();
17801 onFirstFocus: function() {
17802 this.tb.items.each(function(item){
17811 // <script type="text/javascript">
17814 * Ext JS Library 1.1.1
17815 * Copyright(c) 2006-2007, Ext JS, LLC.
17822 * @class Roo.form.HtmlEditor.ToolbarContext
17827 new Roo.form.HtmlEditor({
17830 new Roo.form.HtmlEditor.ToolbarStandard(),
17831 new Roo.form.HtmlEditor.ToolbarContext()
17836 * @config : {Object} disable List of elements to disable.. (not done yet.)
17841 Roo.form.HtmlEditor.ToolbarContext = function(config)
17844 Roo.apply(this, config);
17845 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17846 // dont call parent... till later.
17848 Roo.form.HtmlEditor.ToolbarContext.types = {
17860 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
17922 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
17927 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
17991 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
17999 * @cfg {Object} disable List of toolbar elements to disable
18008 init : function(editor)
18010 this.editor = editor;
18013 var fid = editor.frameId;
18015 function btn(id, toggle, handler){
18016 var xid = fid + '-'+ id ;
18020 cls : 'x-btn-icon x-edit-'+id,
18021 enableToggle:toggle !== false,
18022 scope: editor, // was editor...
18023 handler:handler||editor.relayBtnCmd,
18024 clickEvent:'mousedown',
18025 tooltip: etb.buttonTips[id] || undefined, ///tips ???
18029 // create a new element.
18030 var wdiv = editor.wrap.createChild({
18032 }, editor.wrap.dom.firstChild.nextSibling, true);
18034 // can we do this more than once??
18036 // stop form submits
18039 // disable everything...
18040 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
18041 this.toolbars = {};
18043 for (var i in ty) {
18044 this.toolbars[i] = this.buildToolbar(ty[i],i);
18046 this.tb = this.toolbars.BODY;
18050 this.rendered = true;
18052 // the all the btns;
18053 editor.on('editorevent', this.updateToolbar, this);
18054 // other toolbars need to implement this..
18055 //editor.on('editmodechange', this.updateToolbar, this);
18061 * Protected method that will not generally be called directly. It triggers
18062 * a toolbar update by reading the markup state of the current selection in the editor.
18064 updateToolbar: function(){
18066 if(!this.editor.activated){
18067 this.editor.onFirstFocus();
18072 var ans = this.editor.getAllAncestors();
18075 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
18076 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
18077 sel = sel ? sel : this.editor.doc.body;
18078 sel = sel.tagName.length ? sel : this.editor.doc.body;
18079 var tn = sel.tagName.toUpperCase();
18080 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
18081 tn = sel.tagName.toUpperCase();
18082 if (this.tb.name == tn) {
18083 return; // no change
18086 ///console.log("show: " + tn);
18087 this.tb = this.toolbars[tn];
18089 this.tb.fields.each(function(e) {
18090 e.setValue(sel.getAttribute(e.name));
18092 this.tb.selectedNode = sel;
18095 Roo.menu.MenuMgr.hideAll();
18097 //this.editorsyncValue();
18102 onDestroy : function(){
18105 this.tb.items.each(function(item){
18107 item.menu.removeAll();
18109 item.menu.el.destroy();
18117 onFirstFocus: function() {
18118 // need to do this for all the toolbars..
18119 this.tb.items.each(function(item){
18123 buildToolbar: function(tlist, nm)
18125 var editor = this.editor;
18126 // create a new element.
18127 var wdiv = editor.wrap.createChild({
18129 }, editor.wrap.dom.firstChild.nextSibling, true);
18132 var tb = new Roo.Toolbar(wdiv);
18133 tb.add(nm+ ": ");
18134 for (var i in tlist) {
18135 var item = tlist[i];
18136 tb.add(item.title + ": ");
18141 tb.addField( new Roo.form.ComboBox({
18142 store: new Roo.data.SimpleStore({
18145 data : item.opts // from states.js
18148 displayField:'val',
18152 triggerAction: 'all',
18153 emptyText:'Select',
18154 selectOnFocus:true,
18155 width: item.width ? item.width : 130,
18157 'select': function(c, r, i) {
18158 tb.selectedNode.setAttribute(c.name, r.get('val'));
18169 tb.addField( new Roo.form.TextField({
18172 //allowBlank:false,
18177 tb.addField( new Roo.form.TextField({
18183 'change' : function(f, nv, ov) {
18184 tb.selectedNode.setAttribute(f.name, nv);
18190 tb.el.on('click', function(e){
18191 e.preventDefault(); // what does this do?
18193 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
18196 // dont need to disable them... as they will get hidden
18213 * Ext JS Library 1.1.1
18214 * Copyright(c) 2006-2007, Ext JS, LLC.
18216 * Originally Released Under LGPL - original licence link has changed is not relivant.
18219 * <script type="text/javascript">
18223 * @class Roo.form.BasicForm
18224 * @extends Roo.util.Observable
18225 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
18227 * @param {String/HTMLElement/Roo.Element} el The form element or its id
18228 * @param {Object} config Configuration options
18230 Roo.form.BasicForm = function(el, config){
18231 Roo.apply(this, config);
18233 * The Roo.form.Field items in this form.
18234 * @type MixedCollection
18236 this.items = new Roo.util.MixedCollection(false, function(o){
18237 return o.id || (o.id = Roo.id());
18241 * @event beforeaction
18242 * Fires before any action is performed. Return false to cancel the action.
18243 * @param {Form} this
18244 * @param {Action} action The action to be performed
18246 beforeaction: true,
18248 * @event actionfailed
18249 * Fires when an action fails.
18250 * @param {Form} this
18251 * @param {Action} action The action that failed
18253 actionfailed : true,
18255 * @event actioncomplete
18256 * Fires when an action is completed.
18257 * @param {Form} this
18258 * @param {Action} action The action that completed
18260 actioncomplete : true
18265 Roo.form.BasicForm.superclass.constructor.call(this);
18268 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
18270 * @cfg {String} method
18271 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
18274 * @cfg {DataReader} reader
18275 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
18276 * This is optional as there is built-in support for processing JSON.
18279 * @cfg {DataReader} errorReader
18280 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
18281 * This is completely optional as there is built-in support for processing JSON.
18284 * @cfg {String} url
18285 * The URL to use for form actions if one isn't supplied in the action options.
18288 * @cfg {Boolean} fileUpload
18289 * Set to true if this form is a file upload.
18292 * @cfg {Object} baseParams
18293 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
18296 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
18301 activeAction : null,
18304 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
18305 * or setValues() data instead of when the form was first created.
18307 trackResetOnLoad : false,
18310 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
18311 * element by passing it or its id or mask the form itself by passing in true.
18314 waitMsgTarget : undefined,
18317 initEl : function(el){
18318 this.el = Roo.get(el);
18319 this.id = this.el.id || Roo.id();
18320 this.el.on('submit', this.onSubmit, this);
18321 this.el.addClass('x-form');
18325 onSubmit : function(e){
18330 * Returns true if client-side validation on the form is successful.
18333 isValid : function(){
18335 this.items.each(function(f){
18344 * Returns true if any fields in this form have changed since their original load.
18347 isDirty : function(){
18349 this.items.each(function(f){
18359 * Performs a predefined action (submit or load) or custom actions you define on this form.
18360 * @param {String} actionName The name of the action type
18361 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
18362 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
18363 * accept other config options):
18365 Property Type Description
18366 ---------------- --------------- ----------------------------------------------------------------------------------
18367 url String The url for the action (defaults to the form's url)
18368 method String The form method to use (defaults to the form's method, or POST if not defined)
18369 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
18370 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
18371 validate the form on the client (defaults to false)
18373 * @return {BasicForm} this
18375 doAction : function(action, options){
18376 if(typeof action == 'string'){
18377 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
18379 if(this.fireEvent('beforeaction', this, action) !== false){
18380 this.beforeAction(action);
18381 action.run.defer(100, action);
18387 * Shortcut to do a submit action.
18388 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
18389 * @return {BasicForm} this
18391 submit : function(options){
18392 this.doAction('submit', options);
18397 * Shortcut to do a load action.
18398 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
18399 * @return {BasicForm} this
18401 load : function(options){
18402 this.doAction('load', options);
18407 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
18408 * @param {Record} record The record to edit
18409 * @return {BasicForm} this
18411 updateRecord : function(record){
18412 record.beginEdit();
18413 var fs = record.fields;
18414 fs.each(function(f){
18415 var field = this.findField(f.name);
18417 record.set(f.name, field.getValue());
18425 * Loads an Roo.data.Record into this form.
18426 * @param {Record} record The record to load
18427 * @return {BasicForm} this
18429 loadRecord : function(record){
18430 this.setValues(record.data);
18435 beforeAction : function(action){
18436 var o = action.options;
18438 if(this.waitMsgTarget === true){
18439 this.el.mask(o.waitMsg, 'x-mask-loading');
18440 }else if(this.waitMsgTarget){
18441 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
18442 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
18444 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
18450 afterAction : function(action, success){
18451 this.activeAction = null;
18452 var o = action.options;
18454 if(this.waitMsgTarget === true){
18456 }else if(this.waitMsgTarget){
18457 this.waitMsgTarget.unmask();
18459 Roo.MessageBox.updateProgress(1);
18460 Roo.MessageBox.hide();
18467 Roo.callback(o.success, o.scope, [this, action]);
18468 this.fireEvent('actioncomplete', this, action);
18470 Roo.callback(o.failure, o.scope, [this, action]);
18471 this.fireEvent('actionfailed', this, action);
18476 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
18477 * @param {String} id The value to search for
18480 findField : function(id){
18481 var field = this.items.get(id);
18483 this.items.each(function(f){
18484 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
18490 return field || null;
18495 * Mark fields in this form invalid in bulk.
18496 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
18497 * @return {BasicForm} this
18499 markInvalid : function(errors){
18500 if(errors instanceof Array){
18501 for(var i = 0, len = errors.length; i < len; i++){
18502 var fieldError = errors[i];
18503 var f = this.findField(fieldError.id);
18505 f.markInvalid(fieldError.msg);
18511 if(typeof errors[id] != 'function' && (field = this.findField(id))){
18512 field.markInvalid(errors[id]);
18520 * Set values for fields in this form in bulk.
18521 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
18522 * @return {BasicForm} this
18524 setValues : function(values){
18525 if(values instanceof Array){ // array of objects
18526 for(var i = 0, len = values.length; i < len; i++){
18528 var f = this.findField(v.id);
18530 f.setValue(v.value);
18531 if(this.trackResetOnLoad){
18532 f.originalValue = f.getValue();
18536 }else{ // object hash
18539 if(typeof values[id] != 'function' && (field = this.findField(id))){
18541 if (field.setFromData &&
18542 field.valueField &&
18543 field.displayField &&
18544 // combos' with local stores can
18545 // be queried via setValue()
18546 // to set their value..
18547 (field.store && !field.store.isLocal)
18551 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
18552 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
18553 field.setFromData(sd);
18556 field.setValue(values[id]);
18560 if(this.trackResetOnLoad){
18561 field.originalValue = field.getValue();
18570 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
18571 * they are returned as an array.
18572 * @param {Boolean} asString
18575 getValues : function(asString){
18576 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
18577 if(asString === true){
18580 return Roo.urlDecode(fs);
18584 * Clears all invalid messages in this form.
18585 * @return {BasicForm} this
18587 clearInvalid : function(){
18588 this.items.each(function(f){
18595 * Resets this form.
18596 * @return {BasicForm} this
18598 reset : function(){
18599 this.items.each(function(f){
18606 * Add Roo.form components to this form.
18607 * @param {Field} field1
18608 * @param {Field} field2 (optional)
18609 * @param {Field} etc (optional)
18610 * @return {BasicForm} this
18613 this.items.addAll(Array.prototype.slice.call(arguments, 0));
18619 * Removes a field from the items collection (does NOT remove its markup).
18620 * @param {Field} field
18621 * @return {BasicForm} this
18623 remove : function(field){
18624 this.items.remove(field);
18629 * Looks at the fields in this form, checks them for an id attribute,
18630 * and calls applyTo on the existing dom element with that id.
18631 * @return {BasicForm} this
18633 render : function(){
18634 this.items.each(function(f){
18635 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
18643 * Calls {@link Ext#apply} for all fields in this form with the passed object.
18644 * @param {Object} values
18645 * @return {BasicForm} this
18647 applyToFields : function(o){
18648 this.items.each(function(f){
18655 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
18656 * @param {Object} values
18657 * @return {BasicForm} this
18659 applyIfToFields : function(o){
18660 this.items.each(function(f){
18668 Roo.BasicForm = Roo.form.BasicForm;/*
18670 * Ext JS Library 1.1.1
18671 * Copyright(c) 2006-2007, Ext JS, LLC.
18673 * Originally Released Under LGPL - original licence link has changed is not relivant.
18676 * <script type="text/javascript">
18680 * @class Roo.form.Form
18681 * @extends Roo.form.BasicForm
18682 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
18684 * @param {Object} config Configuration options
18686 Roo.form.Form = function(config){
18688 if (config.items) {
18689 xitems = config.items;
18690 delete config.items;
18694 Roo.form.Form.superclass.constructor.call(this, null, config);
18695 this.url = this.url || this.action;
18697 this.root = new Roo.form.Layout(Roo.applyIf({
18701 this.active = this.root;
18703 * Array of all the buttons that have been added to this form via {@link addButton}
18707 this.allItems = [];
18710 * @event clientvalidation
18711 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
18712 * @param {Form} this
18713 * @param {Boolean} valid true if the form has passed client-side validation
18715 clientvalidation: true,
18718 * Fires when the form is rendered
18719 * @param {Roo.form.Form} form
18724 Roo.each(xitems, this.addxtype, this);
18730 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
18732 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
18735 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
18738 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
18740 buttonAlign:'center',
18743 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
18748 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
18749 * This property cascades to child containers if not set.
18754 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
18755 * fires a looping event with that state. This is required to bind buttons to the valid
18756 * state using the config value formBind:true on the button.
18758 monitorValid : false,
18761 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
18766 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
18767 * fields are added and the column is closed. If no fields are passed the column remains open
18768 * until end() is called.
18769 * @param {Object} config The config to pass to the column
18770 * @param {Field} field1 (optional)
18771 * @param {Field} field2 (optional)
18772 * @param {Field} etc (optional)
18773 * @return Column The column container object
18775 column : function(c){
18776 var col = new Roo.form.Column(c);
18778 if(arguments.length > 1){ // duplicate code required because of Opera
18779 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
18786 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
18787 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
18788 * until end() is called.
18789 * @param {Object} config The config to pass to the fieldset
18790 * @param {Field} field1 (optional)
18791 * @param {Field} field2 (optional)
18792 * @param {Field} etc (optional)
18793 * @return FieldSet The fieldset container object
18795 fieldset : function(c){
18796 var fs = new Roo.form.FieldSet(c);
18798 if(arguments.length > 1){ // duplicate code required because of Opera
18799 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
18806 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
18807 * fields are added and the container is closed. If no fields are passed the container remains open
18808 * until end() is called.
18809 * @param {Object} config The config to pass to the Layout
18810 * @param {Field} field1 (optional)
18811 * @param {Field} field2 (optional)
18812 * @param {Field} etc (optional)
18813 * @return Layout The container object
18815 container : function(c){
18816 var l = new Roo.form.Layout(c);
18818 if(arguments.length > 1){ // duplicate code required because of Opera
18819 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
18826 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
18827 * @param {Object} container A Roo.form.Layout or subclass of Layout
18828 * @return {Form} this
18830 start : function(c){
18831 // cascade label info
18832 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
18833 this.active.stack.push(c);
18834 c.ownerCt = this.active;
18840 * Closes the current open container
18841 * @return {Form} this
18844 if(this.active == this.root){
18847 this.active = this.active.ownerCt;
18852 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
18853 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
18854 * as the label of the field.
18855 * @param {Field} field1
18856 * @param {Field} field2 (optional)
18857 * @param {Field} etc. (optional)
18858 * @return {Form} this
18861 this.active.stack.push.apply(this.active.stack, arguments);
18862 this.allItems.push.apply(this.allItems,arguments);
18864 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
18865 if(a[i].isFormField){
18870 Roo.form.Form.superclass.add.apply(this, r);
18875 * Find any element that has been added to a form, using it's ID or name
18876 * This can include framesets, columns etc. along with regular fields..
18877 * @param {String} id - id or name to find.
18879 * @return {Element} e - or false if nothing found.
18881 findbyId : function(id)
18887 Ext.each(this.allItems, function(f){
18888 if (f.id == id || f.name == id ){
18899 * Render this form into the passed container. This should only be called once!
18900 * @param {String/HTMLElement/Element} container The element this component should be rendered into
18901 * @return {Form} this
18903 render : function(ct){
18905 var o = this.autoCreate || {
18907 method : this.method || 'POST',
18908 id : this.id || Roo.id()
18910 this.initEl(ct.createChild(o));
18912 this.root.render(this.el);
18914 this.items.each(function(f){
18915 f.render('x-form-el-'+f.id);
18918 if(this.buttons.length > 0){
18919 // tables are required to maintain order and for correct IE layout
18920 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
18921 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
18922 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
18924 var tr = tb.getElementsByTagName('tr')[0];
18925 for(var i = 0, len = this.buttons.length; i < len; i++) {
18926 var b = this.buttons[i];
18927 var td = document.createElement('td');
18928 td.className = 'x-form-btn-td';
18929 b.render(tr.appendChild(td));
18932 if(this.monitorValid){ // initialize after render
18933 this.startMonitoring();
18935 this.fireEvent('rendered', this);
18940 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
18941 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
18942 * object or a valid Roo.DomHelper element config
18943 * @param {Function} handler The function called when the button is clicked
18944 * @param {Object} scope (optional) The scope of the handler function
18945 * @return {Roo.Button}
18947 addButton : function(config, handler, scope){
18951 minWidth: this.minButtonWidth,
18954 if(typeof config == "string"){
18957 Roo.apply(bc, config);
18959 var btn = new Roo.Button(null, bc);
18960 this.buttons.push(btn);
18965 * Adds a series of form elements (using the xtype property as the factory method.
18966 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
18967 * @param {Object} config
18970 addxtype : function()
18972 var ar = Array.prototype.slice.call(arguments, 0);
18974 for(var i = 0; i < ar.length; i++) {
18976 continue; // skip -- if this happends something invalid got sent, we
18977 // should ignore it, as basically that interface element will not show up
18978 // and that should be pretty obvious!!
18981 if (Roo.form[ar[i].xtype]) {
18983 var fe = Roo.factory(ar[i], Roo.form);
18989 fe.store.form = this;
18994 this.allItems.push(fe);
18995 if (fe.items && fe.addxtype) {
18996 fe.addxtype.apply(fe, fe.items);
19006 // console.log('adding ' + ar[i].xtype);
19008 if (ar[i].xtype == 'Button') {
19009 //console.log('adding button');
19010 //console.log(ar[i]);
19011 this.addButton(ar[i]);
19012 this.allItems.push(fe);
19016 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
19017 alert('end is not supported on xtype any more, use items');
19019 // //console.log('adding end');
19027 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
19028 * option "monitorValid"
19030 startMonitoring : function(){
19033 Roo.TaskMgr.start({
19034 run : this.bindHandler,
19035 interval : this.monitorPoll || 200,
19042 * Stops monitoring of the valid state of this form
19044 stopMonitoring : function(){
19045 this.bound = false;
19049 bindHandler : function(){
19051 return false; // stops binding
19054 this.items.each(function(f){
19055 if(!f.isValid(true)){
19060 for(var i = 0, len = this.buttons.length; i < len; i++){
19061 var btn = this.buttons[i];
19062 if(btn.formBind === true && btn.disabled === valid){
19063 btn.setDisabled(!valid);
19066 this.fireEvent('clientvalidation', this, valid);
19080 Roo.Form = Roo.form.Form;
19083 * Ext JS Library 1.1.1
19084 * Copyright(c) 2006-2007, Ext JS, LLC.
19086 * Originally Released Under LGPL - original licence link has changed is not relivant.
19089 * <script type="text/javascript">
19093 * @class Roo.form.Action
19094 * Internal Class used to handle form actions
19096 * @param {Roo.form.BasicForm} el The form element or its id
19097 * @param {Object} config Configuration options
19101 // define the action interface
19102 Roo.form.Action = function(form, options){
19104 this.options = options || {};
19107 * Client Validation Failed
19110 Roo.form.Action.CLIENT_INVALID = 'client';
19112 * Server Validation Failed
19115 Roo.form.Action.SERVER_INVALID = 'server';
19117 * Connect to Server Failed
19120 Roo.form.Action.CONNECT_FAILURE = 'connect';
19122 * Reading Data from Server Failed
19125 Roo.form.Action.LOAD_FAILURE = 'load';
19127 Roo.form.Action.prototype = {
19129 failureType : undefined,
19130 response : undefined,
19131 result : undefined,
19133 // interface method
19134 run : function(options){
19138 // interface method
19139 success : function(response){
19143 // interface method
19144 handleResponse : function(response){
19148 // default connection failure
19149 failure : function(response){
19150 this.response = response;
19151 this.failureType = Roo.form.Action.CONNECT_FAILURE;
19152 this.form.afterAction(this, false);
19155 processResponse : function(response){
19156 this.response = response;
19157 if(!response.responseText){
19160 this.result = this.handleResponse(response);
19161 return this.result;
19164 // utility functions used internally
19165 getUrl : function(appendParams){
19166 var url = this.options.url || this.form.url || this.form.el.dom.action;
19168 var p = this.getParams();
19170 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
19176 getMethod : function(){
19177 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
19180 getParams : function(){
19181 var bp = this.form.baseParams;
19182 var p = this.options.params;
19184 if(typeof p == "object"){
19185 p = Roo.urlEncode(Roo.applyIf(p, bp));
19186 }else if(typeof p == 'string' && bp){
19187 p += '&' + Roo.urlEncode(bp);
19190 p = Roo.urlEncode(bp);
19195 createCallback : function(){
19197 success: this.success,
19198 failure: this.failure,
19200 timeout: (this.form.timeout*1000),
19201 upload: this.form.fileUpload ? this.success : undefined
19206 Roo.form.Action.Submit = function(form, options){
19207 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
19210 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
19214 var o = this.options;
19215 var method = this.getMethod();
19216 var isPost = method == 'POST';
19217 if(o.clientValidation === false || this.form.isValid()){
19218 Roo.Ajax.request(Roo.apply(this.createCallback(), {
19219 form:this.form.el.dom,
19220 url:this.getUrl(!isPost),
19222 params:isPost ? this.getParams() : null,
19223 isUpload: this.form.fileUpload
19226 }else if (o.clientValidation !== false){ // client validation failed
19227 this.failureType = Roo.form.Action.CLIENT_INVALID;
19228 this.form.afterAction(this, false);
19232 success : function(response){
19233 var result = this.processResponse(response);
19234 if(result === true || result.success){
19235 this.form.afterAction(this, true);
19239 this.form.markInvalid(result.errors);
19240 this.failureType = Roo.form.Action.SERVER_INVALID;
19242 this.form.afterAction(this, false);
19245 handleResponse : function(response){
19246 if(this.form.errorReader){
19247 var rs = this.form.errorReader.read(response);
19250 for(var i = 0, len = rs.records.length; i < len; i++) {
19251 var r = rs.records[i];
19252 errors[i] = r.data;
19255 if(errors.length < 1){
19259 success : rs.success,
19265 ret = Roo.decode(response.responseText);
19269 errorMsg: "Failed to read server message: " + response.responseText,
19279 Roo.form.Action.Load = function(form, options){
19280 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
19281 this.reader = this.form.reader;
19284 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
19288 Roo.Ajax.request(Roo.apply(
19289 this.createCallback(), {
19290 method:this.getMethod(),
19291 url:this.getUrl(false),
19292 params:this.getParams()
19296 success : function(response){
19297 var result = this.processResponse(response);
19298 if(result === true || !result.success || !result.data){
19299 this.failureType = Roo.form.Action.LOAD_FAILURE;
19300 this.form.afterAction(this, false);
19303 this.form.clearInvalid();
19304 this.form.setValues(result.data);
19305 this.form.afterAction(this, true);
19308 handleResponse : function(response){
19309 if(this.form.reader){
19310 var rs = this.form.reader.read(response);
19311 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
19313 success : rs.success,
19317 return Roo.decode(response.responseText);
19321 Roo.form.Action.ACTION_TYPES = {
19322 'load' : Roo.form.Action.Load,
19323 'submit' : Roo.form.Action.Submit
19326 * Ext JS Library 1.1.1
19327 * Copyright(c) 2006-2007, Ext JS, LLC.
19329 * Originally Released Under LGPL - original licence link has changed is not relivant.
19332 * <script type="text/javascript">
19336 * @class Roo.form.Layout
19337 * @extends Roo.Component
19338 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
19340 * @param {Object} config Configuration options
19342 Roo.form.Layout = function(config){
19344 if (config.items) {
19345 xitems = config.items;
19346 delete config.items;
19348 Roo.form.Layout.superclass.constructor.call(this, config);
19350 Roo.each(xitems, this.addxtype, this);
19354 Roo.extend(Roo.form.Layout, Roo.Component, {
19356 * @cfg {String/Object} autoCreate
19357 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
19360 * @cfg {String/Object/Function} style
19361 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
19362 * a function which returns such a specification.
19365 * @cfg {String} labelAlign
19366 * Valid values are "left," "top" and "right" (defaults to "left")
19369 * @cfg {Number} labelWidth
19370 * Fixed width in pixels of all field labels (defaults to undefined)
19373 * @cfg {Boolean} clear
19374 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
19378 * @cfg {String} labelSeparator
19379 * The separator to use after field labels (defaults to ':')
19381 labelSeparator : ':',
19383 * @cfg {Boolean} hideLabels
19384 * True to suppress the display of field labels in this layout (defaults to false)
19386 hideLabels : false,
19389 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
19394 onRender : function(ct, position){
19395 if(this.el){ // from markup
19396 this.el = Roo.get(this.el);
19397 }else { // generate
19398 var cfg = this.getAutoCreate();
19399 this.el = ct.createChild(cfg, position);
19402 this.el.applyStyles(this.style);
19404 if(this.labelAlign){
19405 this.el.addClass('x-form-label-'+this.labelAlign);
19407 if(this.hideLabels){
19408 this.labelStyle = "display:none";
19409 this.elementStyle = "padding-left:0;";
19411 if(typeof this.labelWidth == 'number'){
19412 this.labelStyle = "width:"+this.labelWidth+"px;";
19413 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
19415 if(this.labelAlign == 'top'){
19416 this.labelStyle = "width:auto;";
19417 this.elementStyle = "padding-left:0;";
19420 var stack = this.stack;
19421 var slen = stack.length;
19423 if(!this.fieldTpl){
19424 var t = new Roo.Template(
19425 '<div class="x-form-item {5}">',
19426 '<label for="{0}" style="{2}">{1}{4}</label>',
19427 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
19429 '</div><div class="x-form-clear-left"></div>'
19431 t.disableFormats = true;
19433 Roo.form.Layout.prototype.fieldTpl = t;
19435 for(var i = 0; i < slen; i++) {
19436 if(stack[i].isFormField){
19437 this.renderField(stack[i]);
19439 this.renderComponent(stack[i]);
19444 this.el.createChild({cls:'x-form-clear'});
19449 renderField : function(f){
19450 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
19453 f.labelStyle||this.labelStyle||'', //2
19454 this.elementStyle||'', //3
19455 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
19456 f.itemCls||this.itemCls||'' //5
19457 ], true).getPrevSibling());
19461 renderComponent : function(c){
19462 c.render(c.isLayout ? this.el : this.el.createChild());
19465 * Adds a object form elements (using the xtype property as the factory method.)
19466 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
19467 * @param {Object} config
19469 addxtype : function(o)
19471 // create the lement.
19472 o.form = this.form;
19473 var fe = Roo.factory(o, Roo.form);
19474 this.form.allItems.push(fe);
19475 this.stack.push(fe);
19477 if (fe.isFormField) {
19478 this.form.items.add(fe);
19486 * @class Roo.form.Column
19487 * @extends Roo.form.Layout
19488 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
19490 * @param {Object} config Configuration options
19492 Roo.form.Column = function(config){
19493 Roo.form.Column.superclass.constructor.call(this, config);
19496 Roo.extend(Roo.form.Column, Roo.form.Layout, {
19498 * @cfg {Number/String} width
19499 * The fixed width of the column in pixels or CSS value (defaults to "auto")
19502 * @cfg {String/Object} autoCreate
19503 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
19507 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
19510 onRender : function(ct, position){
19511 Roo.form.Column.superclass.onRender.call(this, ct, position);
19513 this.el.setWidth(this.width);
19520 * @class Roo.form.Row
19521 * @extends Roo.form.Layout
19522 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
19524 * @param {Object} config Configuration options
19528 Roo.form.Row = function(config){
19529 Roo.form.Row.superclass.constructor.call(this, config);
19532 Roo.extend(Roo.form.Row, Roo.form.Layout, {
19534 * @cfg {Number/String} width
19535 * The fixed width of the column in pixels or CSS value (defaults to "auto")
19538 * @cfg {Number/String} height
19539 * The fixed height of the column in pixels or CSS value (defaults to "auto")
19541 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
19545 onRender : function(ct, position){
19546 //console.log('row render');
19548 var t = new Roo.Template(
19549 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
19550 '<label for="{0}" style="{2}">{1}{4}</label>',
19551 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
19555 t.disableFormats = true;
19557 Roo.form.Layout.prototype.rowTpl = t;
19559 this.fieldTpl = this.rowTpl;
19561 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
19562 var labelWidth = 100;
19564 if ((this.labelAlign != 'top')) {
19565 if (typeof this.labelWidth == 'number') {
19566 labelWidth = this.labelWidth
19568 this.padWidth = 20 + labelWidth;
19572 Roo.form.Column.superclass.onRender.call(this, ct, position);
19574 this.el.setWidth(this.width);
19577 this.el.setHeight(this.height);
19582 renderField : function(f){
19583 f.fieldEl = this.fieldTpl.append(this.el, [
19584 f.id, f.fieldLabel,
19585 f.labelStyle||this.labelStyle||'',
19586 this.elementStyle||'',
19587 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
19588 f.itemCls||this.itemCls||'',
19589 f.width ? f.width + this.padWidth : 160 + this.padWidth
19596 * @class Roo.form.FieldSet
19597 * @extends Roo.form.Layout
19598 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
19600 * @param {Object} config Configuration options
19602 Roo.form.FieldSet = function(config){
19603 Roo.form.FieldSet.superclass.constructor.call(this, config);
19606 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
19608 * @cfg {String} legend
19609 * The text to display as the legend for the FieldSet (defaults to '')
19612 * @cfg {String/Object} autoCreate
19613 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
19617 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
19620 onRender : function(ct, position){
19621 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
19623 this.setLegend(this.legend);
19628 setLegend : function(text){
19630 this.el.child('legend').update(text);
19635 * Ext JS Library 1.1.1
19636 * Copyright(c) 2006-2007, Ext JS, LLC.
19638 * Originally Released Under LGPL - original licence link has changed is not relivant.
19641 * <script type="text/javascript">
19644 * @class Roo.form.VTypes
19645 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
19648 Roo.form.VTypes = function(){
19649 // closure these in so they are only created once.
19650 var alpha = /^[a-zA-Z_]+$/;
19651 var alphanum = /^[a-zA-Z0-9_]+$/;
19652 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
19653 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
19655 // All these messages and functions are configurable
19658 * The function used to validate email addresses
19659 * @param {String} value The email address
19661 'email' : function(v){
19662 return email.test(v);
19665 * The error text to display when the email validation function returns false
19668 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
19670 * The keystroke filter mask to be applied on email input
19673 'emailMask' : /[a-z0-9_\.\-@]/i,
19676 * The function used to validate URLs
19677 * @param {String} value The URL
19679 'url' : function(v){
19680 return url.test(v);
19683 * The error text to display when the url validation function returns false
19686 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
19689 * The function used to validate alpha values
19690 * @param {String} value The value
19692 'alpha' : function(v){
19693 return alpha.test(v);
19696 * The error text to display when the alpha validation function returns false
19699 'alphaText' : 'This field should only contain letters and _',
19701 * The keystroke filter mask to be applied on alpha input
19704 'alphaMask' : /[a-z_]/i,
19707 * The function used to validate alphanumeric values
19708 * @param {String} value The value
19710 'alphanum' : function(v){
19711 return alphanum.test(v);
19714 * The error text to display when the alphanumeric validation function returns false
19717 'alphanumText' : 'This field should only contain letters, numbers and _',
19719 * The keystroke filter mask to be applied on alphanumeric input
19722 'alphanumMask' : /[a-z0-9_]/i
19724 }();//<script type="text/javascript">
19727 * @class Roo.form.FCKeditor
19728 * @extends Roo.form.TextArea
19729 * Wrapper around the FCKEditor http://www.fckeditor.net
19731 * Creates a new FCKeditor
19732 * @param {Object} config Configuration options
19734 Roo.form.FCKeditor = function(config){
19735 Roo.form.FCKeditor.superclass.constructor.call(this, config);
19738 * @event editorinit
19739 * Fired when the editor is initialized - you can add extra handlers here..
19740 * @param {FCKeditor} this
19741 * @param {Object} the FCK object.
19748 Roo.form.FCKeditor.editors = { };
19749 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
19751 //defaultAutoCreate : {
19752 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
19756 * @cfg {Object} fck options - see fck manual for details.
19761 * @cfg {Object} fck toolbar set (Basic or Default)
19763 toolbarSet : 'Basic',
19765 * @cfg {Object} fck BasePath
19767 basePath : '/fckeditor/',
19775 onRender : function(ct, position)
19778 this.defaultAutoCreate = {
19780 style:"width:300px;height:60px;",
19781 autocomplete: "off"
19784 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
19787 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
19788 if(this.preventScrollbars){
19789 this.el.setStyle("overflow", "hidden");
19791 this.el.setHeight(this.growMin);
19794 //console.log('onrender' + this.getId() );
19795 Roo.form.FCKeditor.editors[this.getId()] = this;
19798 this.replaceTextarea() ;
19802 getEditor : function() {
19803 return this.fckEditor;
19806 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
19807 * @param {Mixed} value The value to set
19811 setValue : function(value)
19813 //console.log('setValue: ' + value);
19815 if(typeof(value) == 'undefined') { // not sure why this is happending...
19818 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
19820 //if(!this.el || !this.getEditor()) {
19821 // this.value = value;
19822 //this.setValue.defer(100,this,[value]);
19826 if(!this.getEditor()) {
19830 this.getEditor().SetData(value);
19837 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
19838 * @return {Mixed} value The field value
19840 getValue : function()
19843 if (this.frame && this.frame.dom.style.display == 'none') {
19844 return Roo.form.FCKeditor.superclass.getValue.call(this);
19847 if(!this.el || !this.getEditor()) {
19849 // this.getValue.defer(100,this);
19854 var value=this.getEditor().GetData();
19855 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
19856 return Roo.form.FCKeditor.superclass.getValue.call(this);
19862 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
19863 * @return {Mixed} value The field value
19865 getRawValue : function()
19867 if (this.frame && this.frame.dom.style.display == 'none') {
19868 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
19871 if(!this.el || !this.getEditor()) {
19872 //this.getRawValue.defer(100,this);
19879 var value=this.getEditor().GetData();
19880 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
19881 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
19885 setSize : function(w,h) {
19889 //if (this.frame && this.frame.dom.style.display == 'none') {
19890 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
19893 //if(!this.el || !this.getEditor()) {
19894 // this.setSize.defer(100,this, [w,h]);
19900 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
19902 this.frame.dom.setAttribute('width', w);
19903 this.frame.dom.setAttribute('height', h);
19904 this.frame.setSize(w,h);
19908 toggleSourceEdit : function(value) {
19912 this.el.dom.style.display = value ? '' : 'none';
19913 this.frame.dom.style.display = value ? 'none' : '';
19918 focus: function(tag)
19920 if (this.frame.dom.style.display == 'none') {
19921 return Roo.form.FCKeditor.superclass.focus.call(this);
19923 if(!this.el || !this.getEditor()) {
19924 this.focus.defer(100,this, [tag]);
19931 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
19932 this.getEditor().Focus();
19934 if (!this.getEditor().Selection.GetSelection()) {
19935 this.focus.defer(100,this, [tag]);
19940 var r = this.getEditor().EditorDocument.createRange();
19941 r.setStart(tgs[0],0);
19942 r.setEnd(tgs[0],0);
19943 this.getEditor().Selection.GetSelection().removeAllRanges();
19944 this.getEditor().Selection.GetSelection().addRange(r);
19945 this.getEditor().Focus();
19952 replaceTextarea : function()
19954 if ( document.getElementById( this.getId() + '___Frame' ) )
19956 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
19958 // We must check the elements firstly using the Id and then the name.
19959 var oTextarea = document.getElementById( this.getId() );
19961 var colElementsByName = document.getElementsByName( this.getId() ) ;
19963 oTextarea.style.display = 'none' ;
19965 if ( oTextarea.tabIndex ) {
19966 this.TabIndex = oTextarea.tabIndex ;
19969 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
19970 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
19971 this.frame = Roo.get(this.getId() + '___Frame')
19974 _getConfigHtml : function()
19978 for ( var o in this.fckconfig ) {
19979 sConfig += sConfig.length > 0 ? '&' : '';
19980 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
19983 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
19987 _getIFrameHtml : function()
19989 var sFile = 'fckeditor.html' ;
19990 /* no idea what this is about..
19993 if ( (/fcksource=true/i).test( window.top.location.search ) )
19994 sFile = 'fckeditor.original.html' ;
19999 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
20000 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
20003 var html = '<iframe id="' + this.getId() +
20004 '___Frame" src="' + sLink +
20005 '" width="' + this.width +
20006 '" height="' + this.height + '"' +
20007 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
20008 ' frameborder="0" scrolling="no"></iframe>' ;
20013 _insertHtmlBefore : function( html, element )
20015 if ( element.insertAdjacentHTML ) {
20017 element.insertAdjacentHTML( 'beforeBegin', html ) ;
20019 var oRange = document.createRange() ;
20020 oRange.setStartBefore( element ) ;
20021 var oFragment = oRange.createContextualFragment( html );
20022 element.parentNode.insertBefore( oFragment, element ) ;
20035 //Roo.reg('fckeditor', Roo.form.FCKeditor);
20037 function FCKeditor_OnComplete(editorInstance){
20038 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
20039 f.fckEditor = editorInstance;
20040 //console.log("loaded");
20041 f.fireEvent('editorinit', f, editorInstance);
20061 //<script type="text/javascript">
20063 * @class Roo.form.GridField
20064 * @extends Roo.form.Field
20065 * Embed a grid (or editable grid into a form)
20068 * Creates a new GridField
20069 * @param {Object} config Configuration options
20071 Roo.form.GridField = function(config){
20072 Roo.form.GridField.superclass.constructor.call(this, config);
20076 Roo.extend(Roo.form.GridField, Roo.form.Field, {
20078 * @cfg {Number} width - used to restrict width of grid..
20082 * @cfg {Number} height - used to restrict height of grid..
20086 * @cfg {Object} xgrid (xtype'd description of grid) Grid or EditorGrid
20090 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20091 * {tag: "input", type: "checkbox", autocomplete: "off"})
20093 // defaultAutoCreate : { tag: 'div' },
20094 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
20096 * @cfg {String} addTitle Text to include for adding a title.
20100 onResize : function(){
20101 Roo.form.Field.superclass.onResize.apply(this, arguments);
20104 initEvents : function(){
20105 // Roo.form.Checkbox.superclass.initEvents.call(this);
20106 // has no events...
20111 getResizeEl : function(){
20115 getPositionEl : function(){
20120 onRender : function(ct, position){
20122 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
20123 var style = this.style;
20126 Roo.form.DisplayImage.superclass.onRender.call(this, ct, position);
20127 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
20128 this.viewEl = this.wrap.createChild({ tag: 'div' });
20130 this.viewEl.applyStyles(style);
20133 this.viewEl.setWidth(this.width);
20136 this.viewEl.setHeight(this.height);
20138 //if(this.inputValue !== undefined){
20139 //this.setValue(this.value);
20142 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
20145 this.grid.render();
20146 this.grid.getDataSource().on('remove', this.refreshValue, this);
20147 this.grid.getDataSource().on('update', this.refreshValue, this);
20148 this.grid.on('afteredit', this.refreshValue, this);
20154 * Sets the value of the item.
20155 * @param {String} either an object or a string..
20157 setValue : function(v){
20159 v = v || []; // empty set..
20160 // this does not seem smart - it really only affects memoryproxy grids..
20161 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
20162 var ds = this.grid.getDataSource();
20163 // assumes a json reader..
20165 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
20166 ds.loadData( data);
20168 Roo.form.GridField.superclass.setValue.call(this, v);
20169 this.refreshValue();
20170 // should load data in the grid really....
20174 refreshValue: function() {
20176 this.grid.getDataSource().each(function(r) {
20179 this.el.dom.value = Roo.encode(val);
20185 });//<script type="text/javasscript">
20189 * @class Roo.DDView
20190 * A DnD enabled version of Roo.View.
20191 * @param {Element/String} container The Element in which to create the View.
20192 * @param {String} tpl The template string used to create the markup for each element of the View
20193 * @param {Object} config The configuration properties. These include all the config options of
20194 * {@link Roo.View} plus some specific to this class.<br>
20196 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
20197 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
20199 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
20200 .x-view-drag-insert-above {
20201 border-top:1px dotted #3366cc;
20203 .x-view-drag-insert-below {
20204 border-bottom:1px dotted #3366cc;
20210 Roo.DDView = function(container, tpl, config) {
20211 Roo.DDView.superclass.constructor.apply(this, arguments);
20212 this.getEl().setStyle("outline", "0px none");
20213 this.getEl().unselectable();
20214 if (this.dragGroup) {
20215 this.setDraggable(this.dragGroup.split(","));
20217 if (this.dropGroup) {
20218 this.setDroppable(this.dropGroup.split(","));
20220 if (this.deletable) {
20221 this.setDeletable();
20223 this.isDirtyFlag = false;
20229 Roo.extend(Roo.DDView, Roo.View, {
20230 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
20231 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
20232 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
20233 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
20237 reset: Roo.emptyFn,
20239 clearInvalid: Roo.form.Field.prototype.clearInvalid,
20241 validate: function() {
20245 destroy: function() {
20246 this.purgeListeners();
20247 this.getEl.removeAllListeners();
20248 this.getEl().remove();
20249 if (this.dragZone) {
20250 if (this.dragZone.destroy) {
20251 this.dragZone.destroy();
20254 if (this.dropZone) {
20255 if (this.dropZone.destroy) {
20256 this.dropZone.destroy();
20261 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
20262 getName: function() {
20266 /** Loads the View from a JSON string representing the Records to put into the Store. */
20267 setValue: function(v) {
20269 throw "DDView.setValue(). DDView must be constructed with a valid Store";
20272 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
20273 this.store.proxy = new Roo.data.MemoryProxy(data);
20277 /** @return {String} a parenthesised list of the ids of the Records in the View. */
20278 getValue: function() {
20280 this.store.each(function(rec) {
20281 result += rec.id + ',';
20283 return result.substr(0, result.length - 1) + ')';
20286 getIds: function() {
20287 var i = 0, result = new Array(this.store.getCount());
20288 this.store.each(function(rec) {
20289 result[i++] = rec.id;
20294 isDirty: function() {
20295 return this.isDirtyFlag;
20299 * Part of the Roo.dd.DropZone interface. If no target node is found, the
20300 * whole Element becomes the target, and this causes the drop gesture to append.
20302 getTargetFromEvent : function(e) {
20303 var target = e.getTarget();
20304 while ((target !== null) && (target.parentNode != this.el.dom)) {
20305 target = target.parentNode;
20308 target = this.el.dom.lastChild || this.el.dom;
20314 * Create the drag data which consists of an object which has the property "ddel" as
20315 * the drag proxy element.
20317 getDragData : function(e) {
20318 var target = this.findItemFromChild(e.getTarget());
20320 this.handleSelection(e);
20321 var selNodes = this.getSelectedNodes();
20324 copy: this.copy || (this.allowCopy && e.ctrlKey),
20328 var selectedIndices = this.getSelectedIndexes();
20329 for (var i = 0; i < selectedIndices.length; i++) {
20330 dragData.records.push(this.store.getAt(selectedIndices[i]));
20332 if (selNodes.length == 1) {
20333 dragData.ddel = target.cloneNode(true); // the div element
20335 var div = document.createElement('div'); // create the multi element drag "ghost"
20336 div.className = 'multi-proxy';
20337 for (var i = 0, len = selNodes.length; i < len; i++) {
20338 div.appendChild(selNodes[i].cloneNode(true));
20340 dragData.ddel = div;
20342 //console.log(dragData)
20343 //console.log(dragData.ddel.innerHTML)
20346 //console.log('nodragData')
20350 /** Specify to which ddGroup items in this DDView may be dragged. */
20351 setDraggable: function(ddGroup) {
20352 if (ddGroup instanceof Array) {
20353 Roo.each(ddGroup, this.setDraggable, this);
20356 if (this.dragZone) {
20357 this.dragZone.addToGroup(ddGroup);
20359 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
20360 containerScroll: true,
20364 // Draggability implies selection. DragZone's mousedown selects the element.
20365 if (!this.multiSelect) { this.singleSelect = true; }
20367 // Wire the DragZone's handlers up to methods in *this*
20368 this.dragZone.getDragData = this.getDragData.createDelegate(this);
20372 /** Specify from which ddGroup this DDView accepts drops. */
20373 setDroppable: function(ddGroup) {
20374 if (ddGroup instanceof Array) {
20375 Roo.each(ddGroup, this.setDroppable, this);
20378 if (this.dropZone) {
20379 this.dropZone.addToGroup(ddGroup);
20381 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
20382 containerScroll: true,
20386 // Wire the DropZone's handlers up to methods in *this*
20387 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
20388 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
20389 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
20390 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
20391 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
20395 /** Decide whether to drop above or below a View node. */
20396 getDropPoint : function(e, n, dd){
20397 if (n == this.el.dom) { return "above"; }
20398 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
20399 var c = t + (b - t) / 2;
20400 var y = Roo.lib.Event.getPageY(e);
20408 onNodeEnter : function(n, dd, e, data){
20412 onNodeOver : function(n, dd, e, data){
20413 var pt = this.getDropPoint(e, n, dd);
20414 // set the insert point style on the target node
20415 var dragElClass = this.dropNotAllowed;
20418 if (pt == "above"){
20419 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
20420 targetElClass = "x-view-drag-insert-above";
20422 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
20423 targetElClass = "x-view-drag-insert-below";
20425 if (this.lastInsertClass != targetElClass){
20426 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
20427 this.lastInsertClass = targetElClass;
20430 return dragElClass;
20433 onNodeOut : function(n, dd, e, data){
20434 this.removeDropIndicators(n);
20437 onNodeDrop : function(n, dd, e, data){
20438 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
20441 var pt = this.getDropPoint(e, n, dd);
20442 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
20443 if (pt == "below") { insertAt++; }
20444 for (var i = 0; i < data.records.length; i++) {
20445 var r = data.records[i];
20446 var dup = this.store.getById(r.id);
20447 if (dup && (dd != this.dragZone)) {
20448 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
20451 this.store.insert(insertAt++, r.copy());
20453 data.source.isDirtyFlag = true;
20455 this.store.insert(insertAt++, r);
20457 this.isDirtyFlag = true;
20460 this.dragZone.cachedTarget = null;
20464 removeDropIndicators : function(n){
20466 Roo.fly(n).removeClass([
20467 "x-view-drag-insert-above",
20468 "x-view-drag-insert-below"]);
20469 this.lastInsertClass = "_noclass";
20474 * Utility method. Add a delete option to the DDView's context menu.
20475 * @param {String} imageUrl The URL of the "delete" icon image.
20477 setDeletable: function(imageUrl) {
20478 if (!this.singleSelect && !this.multiSelect) {
20479 this.singleSelect = true;
20481 var c = this.getContextMenu();
20482 this.contextMenu.on("itemclick", function(item) {
20485 this.remove(this.getSelectedIndexes());
20489 this.contextMenu.add({
20496 /** Return the context menu for this DDView. */
20497 getContextMenu: function() {
20498 if (!this.contextMenu) {
20499 // Create the View's context menu
20500 this.contextMenu = new Roo.menu.Menu({
20501 id: this.id + "-contextmenu"
20503 this.el.on("contextmenu", this.showContextMenu, this);
20505 return this.contextMenu;
20508 disableContextMenu: function() {
20509 if (this.contextMenu) {
20510 this.el.un("contextmenu", this.showContextMenu, this);
20514 showContextMenu: function(e, item) {
20515 item = this.findItemFromChild(e.getTarget());
20518 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
20519 this.contextMenu.showAt(e.getXY());
20524 * Remove {@link Roo.data.Record}s at the specified indices.
20525 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
20527 remove: function(selectedIndices) {
20528 selectedIndices = [].concat(selectedIndices);
20529 for (var i = 0; i < selectedIndices.length; i++) {
20530 var rec = this.store.getAt(selectedIndices[i]);
20531 this.store.remove(rec);
20536 * Double click fires the event, but also, if this is draggable, and there is only one other
20537 * related DropZone, it transfers the selected node.
20539 onDblClick : function(e){
20540 var item = this.findItemFromChild(e.getTarget());
20542 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
20545 if (this.dragGroup) {
20546 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
20547 while (targets.indexOf(this.dropZone) > -1) {
20548 targets.remove(this.dropZone);
20550 if (targets.length == 1) {
20551 this.dragZone.cachedTarget = null;
20552 var el = Roo.get(targets[0].getEl());
20553 var box = el.getBox(true);
20554 targets[0].onNodeDrop(el.dom, {
20556 xy: [box.x, box.y + box.height - 1]
20557 }, null, this.getDragData(e));
20563 handleSelection: function(e) {
20564 this.dragZone.cachedTarget = null;
20565 var item = this.findItemFromChild(e.getTarget());
20567 this.clearSelections(true);
20570 if (item && (this.multiSelect || this.singleSelect)){
20571 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
20572 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
20573 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
20574 this.unselect(item);
20576 this.select(item, this.multiSelect && e.ctrlKey);
20577 this.lastSelection = item;
20582 onItemClick : function(item, index, e){
20583 if(this.fireEvent("beforeclick", this, index, item, e) === false){
20589 unselect : function(nodeInfo, suppressEvent){
20590 var node = this.getNode(nodeInfo);
20591 if(node && this.isSelected(node)){
20592 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
20593 Roo.fly(node).removeClass(this.selectedClass);
20594 this.selections.remove(node);
20595 if(!suppressEvent){
20596 this.fireEvent("selectionchange", this, this.selections);
20604 * Ext JS Library 1.1.1
20605 * Copyright(c) 2006-2007, Ext JS, LLC.
20607 * Originally Released Under LGPL - original licence link has changed is not relivant.
20610 * <script type="text/javascript">
20614 * @class Roo.LayoutManager
20615 * @extends Roo.util.Observable
20616 * Base class for layout managers.
20618 Roo.LayoutManager = function(container, config){
20619 Roo.LayoutManager.superclass.constructor.call(this);
20620 this.el = Roo.get(container);
20621 // ie scrollbar fix
20622 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
20623 document.body.scroll = "no";
20624 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
20625 this.el.position('relative');
20627 this.id = this.el.id;
20628 this.el.addClass("x-layout-container");
20629 /** false to disable window resize monitoring @type Boolean */
20630 this.monitorWindowResize = true;
20635 * Fires when a layout is performed.
20636 * @param {Roo.LayoutManager} this
20640 * @event regionresized
20641 * Fires when the user resizes a region.
20642 * @param {Roo.LayoutRegion} region The resized region
20643 * @param {Number} newSize The new size (width for east/west, height for north/south)
20645 "regionresized" : true,
20647 * @event regioncollapsed
20648 * Fires when a region is collapsed.
20649 * @param {Roo.LayoutRegion} region The collapsed region
20651 "regioncollapsed" : true,
20653 * @event regionexpanded
20654 * Fires when a region is expanded.
20655 * @param {Roo.LayoutRegion} region The expanded region
20657 "regionexpanded" : true
20659 this.updating = false;
20660 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
20663 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
20665 * Returns true if this layout is currently being updated
20666 * @return {Boolean}
20668 isUpdating : function(){
20669 return this.updating;
20673 * Suspend the LayoutManager from doing auto-layouts while
20674 * making multiple add or remove calls
20676 beginUpdate : function(){
20677 this.updating = true;
20681 * Restore auto-layouts and optionally disable the manager from performing a layout
20682 * @param {Boolean} noLayout true to disable a layout update
20684 endUpdate : function(noLayout){
20685 this.updating = false;
20691 layout: function(){
20695 onRegionResized : function(region, newSize){
20696 this.fireEvent("regionresized", region, newSize);
20700 onRegionCollapsed : function(region){
20701 this.fireEvent("regioncollapsed", region);
20704 onRegionExpanded : function(region){
20705 this.fireEvent("regionexpanded", region);
20709 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
20710 * performs box-model adjustments.
20711 * @return {Object} The size as an object {width: (the width), height: (the height)}
20713 getViewSize : function(){
20715 if(this.el.dom != document.body){
20716 size = this.el.getSize();
20718 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20720 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
20721 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
20726 * Returns the Element this layout is bound to.
20727 * @return {Roo.Element}
20729 getEl : function(){
20734 * Returns the specified region.
20735 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
20736 * @return {Roo.LayoutRegion}
20738 getRegion : function(target){
20739 return this.regions[target.toLowerCase()];
20742 onWindowResize : function(){
20743 if(this.monitorWindowResize){
20749 * Ext JS Library 1.1.1
20750 * Copyright(c) 2006-2007, Ext JS, LLC.
20752 * Originally Released Under LGPL - original licence link has changed is not relivant.
20755 * <script type="text/javascript">
20758 * @class Roo.BorderLayout
20759 * @extends Roo.LayoutManager
20760 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
20761 * please see: <br><br>
20762 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
20763 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
20766 var layout = new Roo.BorderLayout(document.body, {
20800 preferredTabWidth: 150
20805 var CP = Roo.ContentPanel;
20807 layout.beginUpdate();
20808 layout.add("north", new CP("north", "North"));
20809 layout.add("south", new CP("south", {title: "South", closable: true}));
20810 layout.add("west", new CP("west", {title: "West"}));
20811 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
20812 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
20813 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
20814 layout.getRegion("center").showPanel("center1");
20815 layout.endUpdate();
20818 <b>The container the layout is rendered into can be either the body element or any other element.
20819 If it is not the body element, the container needs to either be an absolute positioned element,
20820 or you will need to add "position:relative" to the css of the container. You will also need to specify
20821 the container size if it is not the body element.</b>
20824 * Create a new BorderLayout
20825 * @param {String/HTMLElement/Element} container The container this layout is bound to
20826 * @param {Object} config Configuration options
20828 Roo.BorderLayout = function(container, config){
20829 config = config || {};
20830 Roo.BorderLayout.superclass.constructor.call(this, container, config);
20831 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
20832 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
20833 var target = this.factory.validRegions[i];
20834 if(config[target]){
20835 this.addRegion(target, config[target]);
20840 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
20842 * Creates and adds a new region if it doesn't already exist.
20843 * @param {String} target The target region key (north, south, east, west or center).
20844 * @param {Object} config The regions config object
20845 * @return {BorderLayoutRegion} The new region
20847 addRegion : function(target, config){
20848 if(!this.regions[target]){
20849 var r = this.factory.create(target, this, config);
20850 this.bindRegion(target, r);
20852 return this.regions[target];
20856 bindRegion : function(name, r){
20857 this.regions[name] = r;
20858 r.on("visibilitychange", this.layout, this);
20859 r.on("paneladded", this.layout, this);
20860 r.on("panelremoved", this.layout, this);
20861 r.on("invalidated", this.layout, this);
20862 r.on("resized", this.onRegionResized, this);
20863 r.on("collapsed", this.onRegionCollapsed, this);
20864 r.on("expanded", this.onRegionExpanded, this);
20868 * Performs a layout update.
20870 layout : function(){
20871 if(this.updating) return;
20872 var size = this.getViewSize();
20873 var w = size.width;
20874 var h = size.height;
20879 //var x = 0, y = 0;
20881 var rs = this.regions;
20882 var north = rs["north"];
20883 var south = rs["south"];
20884 var west = rs["west"];
20885 var east = rs["east"];
20886 var center = rs["center"];
20887 //if(this.hideOnLayout){ // not supported anymore
20888 //c.el.setStyle("display", "none");
20890 if(north && north.isVisible()){
20891 var b = north.getBox();
20892 var m = north.getMargins();
20893 b.width = w - (m.left+m.right);
20896 centerY = b.height + b.y + m.bottom;
20897 centerH -= centerY;
20898 north.updateBox(this.safeBox(b));
20900 if(south && south.isVisible()){
20901 var b = south.getBox();
20902 var m = south.getMargins();
20903 b.width = w - (m.left+m.right);
20905 var totalHeight = (b.height + m.top + m.bottom);
20906 b.y = h - totalHeight + m.top;
20907 centerH -= totalHeight;
20908 south.updateBox(this.safeBox(b));
20910 if(west && west.isVisible()){
20911 var b = west.getBox();
20912 var m = west.getMargins();
20913 b.height = centerH - (m.top+m.bottom);
20915 b.y = centerY + m.top;
20916 var totalWidth = (b.width + m.left + m.right);
20917 centerX += totalWidth;
20918 centerW -= totalWidth;
20919 west.updateBox(this.safeBox(b));
20921 if(east && east.isVisible()){
20922 var b = east.getBox();
20923 var m = east.getMargins();
20924 b.height = centerH - (m.top+m.bottom);
20925 var totalWidth = (b.width + m.left + m.right);
20926 b.x = w - totalWidth + m.left;
20927 b.y = centerY + m.top;
20928 centerW -= totalWidth;
20929 east.updateBox(this.safeBox(b));
20932 var m = center.getMargins();
20934 x: centerX + m.left,
20935 y: centerY + m.top,
20936 width: centerW - (m.left+m.right),
20937 height: centerH - (m.top+m.bottom)
20939 //if(this.hideOnLayout){
20940 //center.el.setStyle("display", "block");
20942 center.updateBox(this.safeBox(centerBox));
20945 this.fireEvent("layout", this);
20949 safeBox : function(box){
20950 box.width = Math.max(0, box.width);
20951 box.height = Math.max(0, box.height);
20956 * Adds a ContentPanel (or subclass) to this layout.
20957 * @param {String} target The target region key (north, south, east, west or center).
20958 * @param {Roo.ContentPanel} panel The panel to add
20959 * @return {Roo.ContentPanel} The added panel
20961 add : function(target, panel){
20963 target = target.toLowerCase();
20964 return this.regions[target].add(panel);
20968 * Remove a ContentPanel (or subclass) to this layout.
20969 * @param {String} target The target region key (north, south, east, west or center).
20970 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
20971 * @return {Roo.ContentPanel} The removed panel
20973 remove : function(target, panel){
20974 target = target.toLowerCase();
20975 return this.regions[target].remove(panel);
20979 * Searches all regions for a panel with the specified id
20980 * @param {String} panelId
20981 * @return {Roo.ContentPanel} The panel or null if it wasn't found
20983 findPanel : function(panelId){
20984 var rs = this.regions;
20985 for(var target in rs){
20986 if(typeof rs[target] != "function"){
20987 var p = rs[target].getPanel(panelId);
20997 * Searches all regions for a panel with the specified id and activates (shows) it.
20998 * @param {String/ContentPanel} panelId The panels id or the panel itself
20999 * @return {Roo.ContentPanel} The shown panel or null
21001 showPanel : function(panelId) {
21002 var rs = this.regions;
21003 for(var target in rs){
21004 var r = rs[target];
21005 if(typeof r != "function"){
21006 if(r.hasPanel(panelId)){
21007 return r.showPanel(panelId);
21015 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
21016 * @param {Roo.state.Provider} provider (optional) An alternate state provider
21018 restoreState : function(provider){
21020 provider = Roo.state.Manager;
21022 var sm = new Roo.LayoutStateManager();
21023 sm.init(this, provider);
21027 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
21028 * object should contain properties for each region to add ContentPanels to, and each property's value should be
21029 * a valid ContentPanel config object. Example:
21031 // Create the main layout
21032 var layout = new Roo.BorderLayout('main-ct', {
21043 // Create and add multiple ContentPanels at once via configs
21046 id: 'source-files',
21048 title:'Ext Source Files',
21061 * @param {Object} regions An object containing ContentPanel configs by region name
21063 batchAdd : function(regions){
21064 this.beginUpdate();
21065 for(var rname in regions){
21066 var lr = this.regions[rname];
21068 this.addTypedPanels(lr, regions[rname]);
21075 addTypedPanels : function(lr, ps){
21076 if(typeof ps == 'string'){
21077 lr.add(new Roo.ContentPanel(ps));
21079 else if(ps instanceof Array){
21080 for(var i =0, len = ps.length; i < len; i++){
21081 this.addTypedPanels(lr, ps[i]);
21084 else if(!ps.events){ // raw config?
21086 delete ps.el; // prevent conflict
21087 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
21089 else { // panel object assumed!
21094 * Adds a xtype elements to the layout.
21098 xtype : 'ContentPanel',
21105 xtype : 'NestedLayoutPanel',
21111 items : [ ... list of content panels or nested layout panels.. ]
21115 * @param {Object} cfg Xtype definition of item to add.
21117 addxtype : function(cfg)
21119 // basically accepts a pannel...
21120 // can accept a layout region..!?!?
21121 // console.log('BorderLayout add ' + cfg.xtype)
21123 if (!cfg.xtype.match(/Panel$/)) {
21127 var region = cfg.region;
21133 xitems = cfg.items;
21140 case 'ContentPanel': // ContentPanel (el, cfg)
21141 if(cfg.autoCreate) {
21142 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
21144 var el = this.el.createChild();
21145 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
21148 this.add(region, ret);
21152 case 'TreePanel': // our new panel!
21153 cfg.el = this.el.createChild();
21154 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
21155 this.add(region, ret);
21158 case 'NestedLayoutPanel':
21159 // create a new Layout (which is a Border Layout...
21160 var el = this.el.createChild();
21161 var clayout = cfg.layout;
21163 clayout.items = clayout.items || [];
21164 // replace this exitems with the clayout ones..
21165 xitems = clayout.items;
21168 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
21169 cfg.background = false;
21171 var layout = new Roo.BorderLayout(el, clayout);
21173 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
21174 //console.log('adding nested layout panel ' + cfg.toSource());
21175 this.add(region, ret);
21181 // needs grid and region
21183 //var el = this.getRegion(region).el.createChild();
21184 var el = this.el.createChild();
21185 // create the grid first...
21187 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
21189 if (region == 'center' && this.active ) {
21190 cfg.background = false;
21192 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
21194 this.add(region, ret);
21195 if (cfg.background) {
21196 ret.on('activate', function(gp) {
21197 if (!gp.grid.rendered) {
21210 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
21212 // GridPanel (grid, cfg)
21215 this.beginUpdate();
21217 Roo.each(xitems, function(i) {
21227 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
21228 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
21229 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
21230 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
21233 var CP = Roo.ContentPanel;
21235 var layout = Roo.BorderLayout.create({
21239 panels: [new CP("north", "North")]
21248 panels: [new CP("west", {title: "West"})]
21257 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
21266 panels: [new CP("south", {title: "South", closable: true})]
21273 preferredTabWidth: 150,
21275 new CP("center1", {title: "Close Me", closable: true}),
21276 new CP("center2", {title: "Center Panel", closable: false})
21281 layout.getRegion("center").showPanel("center1");
21286 Roo.BorderLayout.create = function(config, targetEl){
21287 var layout = new Roo.BorderLayout(targetEl || document.body, config);
21288 layout.beginUpdate();
21289 var regions = Roo.BorderLayout.RegionFactory.validRegions;
21290 for(var j = 0, jlen = regions.length; j < jlen; j++){
21291 var lr = regions[j];
21292 if(layout.regions[lr] && config[lr].panels){
21293 var r = layout.regions[lr];
21294 var ps = config[lr].panels;
21295 layout.addTypedPanels(r, ps);
21298 layout.endUpdate();
21303 Roo.BorderLayout.RegionFactory = {
21305 validRegions : ["north","south","east","west","center"],
21308 create : function(target, mgr, config){
21309 target = target.toLowerCase();
21310 if(config.lightweight || config.basic){
21311 return new Roo.BasicLayoutRegion(mgr, config, target);
21315 return new Roo.NorthLayoutRegion(mgr, config);
21317 return new Roo.SouthLayoutRegion(mgr, config);
21319 return new Roo.EastLayoutRegion(mgr, config);
21321 return new Roo.WestLayoutRegion(mgr, config);
21323 return new Roo.CenterLayoutRegion(mgr, config);
21325 throw 'Layout region "'+target+'" not supported.';
21329 * Ext JS Library 1.1.1
21330 * Copyright(c) 2006-2007, Ext JS, LLC.
21332 * Originally Released Under LGPL - original licence link has changed is not relivant.
21335 * <script type="text/javascript">
21339 * @class Roo.BasicLayoutRegion
21340 * @extends Roo.util.Observable
21341 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
21342 * and does not have a titlebar, tabs or any other features. All it does is size and position
21343 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
21345 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
21347 this.position = pos;
21350 * @scope Roo.BasicLayoutRegion
21354 * @event beforeremove
21355 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
21356 * @param {Roo.LayoutRegion} this
21357 * @param {Roo.ContentPanel} panel The panel
21358 * @param {Object} e The cancel event object
21360 "beforeremove" : true,
21362 * @event invalidated
21363 * Fires when the layout for this region is changed.
21364 * @param {Roo.LayoutRegion} this
21366 "invalidated" : true,
21368 * @event visibilitychange
21369 * Fires when this region is shown or hidden
21370 * @param {Roo.LayoutRegion} this
21371 * @param {Boolean} visibility true or false
21373 "visibilitychange" : true,
21375 * @event paneladded
21376 * Fires when a panel is added.
21377 * @param {Roo.LayoutRegion} this
21378 * @param {Roo.ContentPanel} panel The panel
21380 "paneladded" : true,
21382 * @event panelremoved
21383 * Fires when a panel is removed.
21384 * @param {Roo.LayoutRegion} this
21385 * @param {Roo.ContentPanel} panel The panel
21387 "panelremoved" : true,
21390 * Fires when this region is collapsed.
21391 * @param {Roo.LayoutRegion} this
21393 "collapsed" : true,
21396 * Fires when this region is expanded.
21397 * @param {Roo.LayoutRegion} this
21402 * Fires when this region is slid into view.
21403 * @param {Roo.LayoutRegion} this
21405 "slideshow" : true,
21408 * Fires when this region slides out of view.
21409 * @param {Roo.LayoutRegion} this
21411 "slidehide" : true,
21413 * @event panelactivated
21414 * Fires when a panel is activated.
21415 * @param {Roo.LayoutRegion} this
21416 * @param {Roo.ContentPanel} panel The activated panel
21418 "panelactivated" : true,
21421 * Fires when the user resizes this region.
21422 * @param {Roo.LayoutRegion} this
21423 * @param {Number} newSize The new size (width for east/west, height for north/south)
21427 /** A collection of panels in this region. @type Roo.util.MixedCollection */
21428 this.panels = new Roo.util.MixedCollection();
21429 this.panels.getKey = this.getPanelId.createDelegate(this);
21431 this.activePanel = null;
21432 // ensure listeners are added...
21434 if (config.listeners || config.events) {
21435 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
21436 listeners : config.listeners || {},
21437 events : config.events || {}
21441 if(skipConfig !== true){
21442 this.applyConfig(config);
21446 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
21447 getPanelId : function(p){
21451 applyConfig : function(config){
21452 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
21453 this.config = config;
21458 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
21459 * the width, for horizontal (north, south) the height.
21460 * @param {Number} newSize The new width or height
21462 resizeTo : function(newSize){
21463 var el = this.el ? this.el :
21464 (this.activePanel ? this.activePanel.getEl() : null);
21466 switch(this.position){
21469 el.setWidth(newSize);
21470 this.fireEvent("resized", this, newSize);
21474 el.setHeight(newSize);
21475 this.fireEvent("resized", this, newSize);
21481 getBox : function(){
21482 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
21485 getMargins : function(){
21486 return this.margins;
21489 updateBox : function(box){
21491 var el = this.activePanel.getEl();
21492 el.dom.style.left = box.x + "px";
21493 el.dom.style.top = box.y + "px";
21494 this.activePanel.setSize(box.width, box.height);
21498 * Returns the container element for this region.
21499 * @return {Roo.Element}
21501 getEl : function(){
21502 return this.activePanel;
21506 * Returns true if this region is currently visible.
21507 * @return {Boolean}
21509 isVisible : function(){
21510 return this.activePanel ? true : false;
21513 setActivePanel : function(panel){
21514 panel = this.getPanel(panel);
21515 if(this.activePanel && this.activePanel != panel){
21516 this.activePanel.setActiveState(false);
21517 this.activePanel.getEl().setLeftTop(-10000,-10000);
21519 this.activePanel = panel;
21520 panel.setActiveState(true);
21522 panel.setSize(this.box.width, this.box.height);
21524 this.fireEvent("panelactivated", this, panel);
21525 this.fireEvent("invalidated");
21529 * Show the specified panel.
21530 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
21531 * @return {Roo.ContentPanel} The shown panel or null
21533 showPanel : function(panel){
21534 if(panel = this.getPanel(panel)){
21535 this.setActivePanel(panel);
21541 * Get the active panel for this region.
21542 * @return {Roo.ContentPanel} The active panel or null
21544 getActivePanel : function(){
21545 return this.activePanel;
21549 * Add the passed ContentPanel(s)
21550 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
21551 * @return {Roo.ContentPanel} The panel added (if only one was added)
21553 add : function(panel){
21554 if(arguments.length > 1){
21555 for(var i = 0, len = arguments.length; i < len; i++) {
21556 this.add(arguments[i]);
21560 if(this.hasPanel(panel)){
21561 this.showPanel(panel);
21564 var el = panel.getEl();
21565 if(el.dom.parentNode != this.mgr.el.dom){
21566 this.mgr.el.dom.appendChild(el.dom);
21568 if(panel.setRegion){
21569 panel.setRegion(this);
21571 this.panels.add(panel);
21572 el.setStyle("position", "absolute");
21573 if(!panel.background){
21574 this.setActivePanel(panel);
21575 if(this.config.initialSize && this.panels.getCount()==1){
21576 this.resizeTo(this.config.initialSize);
21579 this.fireEvent("paneladded", this, panel);
21584 * Returns true if the panel is in this region.
21585 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
21586 * @return {Boolean}
21588 hasPanel : function(panel){
21589 if(typeof panel == "object"){ // must be panel obj
21590 panel = panel.getId();
21592 return this.getPanel(panel) ? true : false;
21596 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
21597 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
21598 * @param {Boolean} preservePanel Overrides the config preservePanel option
21599 * @return {Roo.ContentPanel} The panel that was removed
21601 remove : function(panel, preservePanel){
21602 panel = this.getPanel(panel);
21607 this.fireEvent("beforeremove", this, panel, e);
21608 if(e.cancel === true){
21611 var panelId = panel.getId();
21612 this.panels.removeKey(panelId);
21617 * Returns the panel specified or null if it's not in this region.
21618 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
21619 * @return {Roo.ContentPanel}
21621 getPanel : function(id){
21622 if(typeof id == "object"){ // must be panel obj
21625 return this.panels.get(id);
21629 * Returns this regions position (north/south/east/west/center).
21632 getPosition: function(){
21633 return this.position;
21637 * Ext JS Library 1.1.1
21638 * Copyright(c) 2006-2007, Ext JS, LLC.
21640 * Originally Released Under LGPL - original licence link has changed is not relivant.
21643 * <script type="text/javascript">
21647 * @class Roo.LayoutRegion
21648 * @extends Roo.BasicLayoutRegion
21649 * This class represents a region in a layout manager.
21650 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
21651 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
21652 * @cfg {Boolean} floatable False to disable floating (defaults to true)
21653 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
21654 * @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})
21655 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
21656 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
21657 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
21658 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
21659 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
21660 * @cfg {String} title The title for the region (overrides panel titles)
21661 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
21662 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
21663 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
21664 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
21665 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
21666 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
21667 * the space available, similar to FireFox 1.5 tabs (defaults to false)
21668 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
21669 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
21670 * @cfg {Boolean} showPin True to show a pin button
21671 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
21672 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
21673 * @cfg {Boolean} disableTabTips True to disable tab tooltips
21674 * @cfg {Number} width For East/West panels
21675 * @cfg {Number} height For North/South panels
21676 * @cfg {Boolean} split To show the splitter
21678 Roo.LayoutRegion = function(mgr, config, pos){
21679 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
21680 var dh = Roo.DomHelper;
21681 /** This region's container element
21682 * @type Roo.Element */
21683 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
21684 /** This region's title element
21685 * @type Roo.Element */
21687 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
21688 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
21689 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
21691 this.titleEl.enableDisplayMode();
21692 /** This region's title text element
21693 * @type HTMLElement */
21694 this.titleTextEl = this.titleEl.dom.firstChild;
21695 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
21696 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
21697 this.closeBtn.enableDisplayMode();
21698 this.closeBtn.on("click", this.closeClicked, this);
21699 this.closeBtn.hide();
21701 this.createBody(config);
21702 this.visible = true;
21703 this.collapsed = false;
21705 if(config.hideWhenEmpty){
21707 this.on("paneladded", this.validateVisibility, this);
21708 this.on("panelremoved", this.validateVisibility, this);
21710 this.applyConfig(config);
21713 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
21715 createBody : function(){
21716 /** This region's body element
21717 * @type Roo.Element */
21718 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
21721 applyConfig : function(c){
21722 if(c.collapsible && this.position != "center" && !this.collapsedEl){
21723 var dh = Roo.DomHelper;
21724 if(c.titlebar !== false){
21725 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
21726 this.collapseBtn.on("click", this.collapse, this);
21727 this.collapseBtn.enableDisplayMode();
21729 if(c.showPin === true || this.showPin){
21730 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
21731 this.stickBtn.enableDisplayMode();
21732 this.stickBtn.on("click", this.expand, this);
21733 this.stickBtn.hide();
21736 /** This region's collapsed element
21737 * @type Roo.Element */
21738 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
21739 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
21741 if(c.floatable !== false){
21742 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
21743 this.collapsedEl.on("click", this.collapseClick, this);
21746 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
21747 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
21748 id: "message", unselectable: "on", style:{"float":"left"}});
21749 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
21751 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
21752 this.expandBtn.on("click", this.expand, this);
21754 if(this.collapseBtn){
21755 this.collapseBtn.setVisible(c.collapsible == true);
21757 this.cmargins = c.cmargins || this.cmargins ||
21758 (this.position == "west" || this.position == "east" ?
21759 {top: 0, left: 2, right:2, bottom: 0} :
21760 {top: 2, left: 0, right:0, bottom: 2});
21761 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
21762 this.bottomTabs = c.tabPosition != "top";
21763 this.autoScroll = c.autoScroll || false;
21764 if(this.autoScroll){
21765 this.bodyEl.setStyle("overflow", "auto");
21767 this.bodyEl.setStyle("overflow", "hidden");
21769 //if(c.titlebar !== false){
21770 if((!c.titlebar && !c.title) || c.titlebar === false){
21771 this.titleEl.hide();
21773 this.titleEl.show();
21775 this.titleTextEl.innerHTML = c.title;
21779 this.duration = c.duration || .30;
21780 this.slideDuration = c.slideDuration || .45;
21783 this.collapse(true);
21790 * Returns true if this region is currently visible.
21791 * @return {Boolean}
21793 isVisible : function(){
21794 return this.visible;
21798 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
21799 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
21801 setCollapsedTitle : function(title){
21802 title = title || " ";
21803 if(this.collapsedTitleTextEl){
21804 this.collapsedTitleTextEl.innerHTML = title;
21808 getBox : function(){
21810 if(!this.collapsed){
21811 b = this.el.getBox(false, true);
21813 b = this.collapsedEl.getBox(false, true);
21818 getMargins : function(){
21819 return this.collapsed ? this.cmargins : this.margins;
21822 highlight : function(){
21823 this.el.addClass("x-layout-panel-dragover");
21826 unhighlight : function(){
21827 this.el.removeClass("x-layout-panel-dragover");
21830 updateBox : function(box){
21832 if(!this.collapsed){
21833 this.el.dom.style.left = box.x + "px";
21834 this.el.dom.style.top = box.y + "px";
21835 this.updateBody(box.width, box.height);
21837 this.collapsedEl.dom.style.left = box.x + "px";
21838 this.collapsedEl.dom.style.top = box.y + "px";
21839 this.collapsedEl.setSize(box.width, box.height);
21842 this.tabs.autoSizeTabs();
21846 updateBody : function(w, h){
21848 this.el.setWidth(w);
21849 w -= this.el.getBorderWidth("rl");
21850 if(this.config.adjustments){
21851 w += this.config.adjustments[0];
21855 this.el.setHeight(h);
21856 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
21857 h -= this.el.getBorderWidth("tb");
21858 if(this.config.adjustments){
21859 h += this.config.adjustments[1];
21861 this.bodyEl.setHeight(h);
21863 h = this.tabs.syncHeight(h);
21866 if(this.panelSize){
21867 w = w !== null ? w : this.panelSize.width;
21868 h = h !== null ? h : this.panelSize.height;
21870 if(this.activePanel){
21871 var el = this.activePanel.getEl();
21872 w = w !== null ? w : el.getWidth();
21873 h = h !== null ? h : el.getHeight();
21874 this.panelSize = {width: w, height: h};
21875 this.activePanel.setSize(w, h);
21877 if(Roo.isIE && this.tabs){
21878 this.tabs.el.repaint();
21883 * Returns the container element for this region.
21884 * @return {Roo.Element}
21886 getEl : function(){
21891 * Hides this region.
21894 if(!this.collapsed){
21895 this.el.dom.style.left = "-2000px";
21898 this.collapsedEl.dom.style.left = "-2000px";
21899 this.collapsedEl.hide();
21901 this.visible = false;
21902 this.fireEvent("visibilitychange", this, false);
21906 * Shows this region if it was previously hidden.
21909 if(!this.collapsed){
21912 this.collapsedEl.show();
21914 this.visible = true;
21915 this.fireEvent("visibilitychange", this, true);
21918 closeClicked : function(){
21919 if(this.activePanel){
21920 this.remove(this.activePanel);
21924 collapseClick : function(e){
21926 e.stopPropagation();
21929 e.stopPropagation();
21935 * Collapses this region.
21936 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
21938 collapse : function(skipAnim){
21939 if(this.collapsed) return;
21940 this.collapsed = true;
21942 this.split.el.hide();
21944 if(this.config.animate && skipAnim !== true){
21945 this.fireEvent("invalidated", this);
21946 this.animateCollapse();
21948 this.el.setLocation(-20000,-20000);
21950 this.collapsedEl.show();
21951 this.fireEvent("collapsed", this);
21952 this.fireEvent("invalidated", this);
21956 animateCollapse : function(){
21961 * Expands this region if it was previously collapsed.
21962 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
21963 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
21965 expand : function(e, skipAnim){
21966 if(e) e.stopPropagation();
21967 if(!this.collapsed || this.el.hasActiveFx()) return;
21969 this.afterSlideIn();
21972 this.collapsed = false;
21973 if(this.config.animate && skipAnim !== true){
21974 this.animateExpand();
21978 this.split.el.show();
21980 this.collapsedEl.setLocation(-2000,-2000);
21981 this.collapsedEl.hide();
21982 this.fireEvent("invalidated", this);
21983 this.fireEvent("expanded", this);
21987 animateExpand : function(){
21991 initTabs : function(){
21992 this.bodyEl.setStyle("overflow", "hidden");
21993 var ts = new Roo.TabPanel(this.bodyEl.dom, {
21994 tabPosition: this.bottomTabs ? 'bottom' : 'top',
21995 disableTooltips: this.config.disableTabTips
21997 if(this.config.hideTabs){
21998 ts.stripWrap.setDisplayed(false);
22001 ts.resizeTabs = this.config.resizeTabs === true;
22002 ts.minTabWidth = this.config.minTabWidth || 40;
22003 ts.maxTabWidth = this.config.maxTabWidth || 250;
22004 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
22005 ts.monitorResize = false;
22006 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
22007 ts.bodyEl.addClass('x-layout-tabs-body');
22008 this.panels.each(this.initPanelAsTab, this);
22011 initPanelAsTab : function(panel){
22012 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
22013 this.config.closeOnTab && panel.isClosable());
22014 if(panel.tabTip !== undefined){
22015 ti.setTooltip(panel.tabTip);
22017 ti.on("activate", function(){
22018 this.setActivePanel(panel);
22020 if(this.config.closeOnTab){
22021 ti.on("beforeclose", function(t, e){
22023 this.remove(panel);
22029 updatePanelTitle : function(panel, title){
22030 if(this.activePanel == panel){
22031 this.updateTitle(title);
22034 var ti = this.tabs.getTab(panel.getEl().id);
22036 if(panel.tabTip !== undefined){
22037 ti.setTooltip(panel.tabTip);
22042 updateTitle : function(title){
22043 if(this.titleTextEl && !this.config.title){
22044 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
22048 setActivePanel : function(panel){
22049 panel = this.getPanel(panel);
22050 if(this.activePanel && this.activePanel != panel){
22051 this.activePanel.setActiveState(false);
22053 this.activePanel = panel;
22054 panel.setActiveState(true);
22055 if(this.panelSize){
22056 panel.setSize(this.panelSize.width, this.panelSize.height);
22059 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
22061 this.updateTitle(panel.getTitle());
22063 this.fireEvent("invalidated", this);
22065 this.fireEvent("panelactivated", this, panel);
22069 * Shows the specified panel.
22070 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
22071 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
22073 showPanel : function(panel){
22074 if(panel = this.getPanel(panel)){
22076 var tab = this.tabs.getTab(panel.getEl().id);
22077 if(tab.isHidden()){
22078 this.tabs.unhideTab(tab.id);
22082 this.setActivePanel(panel);
22089 * Get the active panel for this region.
22090 * @return {Roo.ContentPanel} The active panel or null
22092 getActivePanel : function(){
22093 return this.activePanel;
22096 validateVisibility : function(){
22097 if(this.panels.getCount() < 1){
22098 this.updateTitle(" ");
22099 this.closeBtn.hide();
22102 if(!this.isVisible()){
22109 * Adds the passed ContentPanel(s) to this region.
22110 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
22111 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
22113 add : function(panel){
22114 if(arguments.length > 1){
22115 for(var i = 0, len = arguments.length; i < len; i++) {
22116 this.add(arguments[i]);
22120 if(this.hasPanel(panel)){
22121 this.showPanel(panel);
22124 panel.setRegion(this);
22125 this.panels.add(panel);
22126 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
22127 this.bodyEl.dom.appendChild(panel.getEl().dom);
22128 if(panel.background !== true){
22129 this.setActivePanel(panel);
22131 this.fireEvent("paneladded", this, panel);
22137 this.initPanelAsTab(panel);
22139 if(panel.background !== true){
22140 this.tabs.activate(panel.getEl().id);
22142 this.fireEvent("paneladded", this, panel);
22147 * Hides the tab for the specified panel.
22148 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
22150 hidePanel : function(panel){
22151 if(this.tabs && (panel = this.getPanel(panel))){
22152 this.tabs.hideTab(panel.getEl().id);
22157 * Unhides the tab for a previously hidden panel.
22158 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
22160 unhidePanel : function(panel){
22161 if(this.tabs && (panel = this.getPanel(panel))){
22162 this.tabs.unhideTab(panel.getEl().id);
22166 clearPanels : function(){
22167 while(this.panels.getCount() > 0){
22168 this.remove(this.panels.first());
22173 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
22174 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
22175 * @param {Boolean} preservePanel Overrides the config preservePanel option
22176 * @return {Roo.ContentPanel} The panel that was removed
22178 remove : function(panel, preservePanel){
22179 panel = this.getPanel(panel);
22184 this.fireEvent("beforeremove", this, panel, e);
22185 if(e.cancel === true){
22188 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
22189 var panelId = panel.getId();
22190 this.panels.removeKey(panelId);
22192 document.body.appendChild(panel.getEl().dom);
22195 this.tabs.removeTab(panel.getEl().id);
22196 }else if (!preservePanel){
22197 this.bodyEl.dom.removeChild(panel.getEl().dom);
22199 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
22200 var p = this.panels.first();
22201 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
22202 tempEl.appendChild(p.getEl().dom);
22203 this.bodyEl.update("");
22204 this.bodyEl.dom.appendChild(p.getEl().dom);
22206 this.updateTitle(p.getTitle());
22208 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
22209 this.setActivePanel(p);
22211 panel.setRegion(null);
22212 if(this.activePanel == panel){
22213 this.activePanel = null;
22215 if(this.config.autoDestroy !== false && preservePanel !== true){
22216 try{panel.destroy();}catch(e){}
22218 this.fireEvent("panelremoved", this, panel);
22223 * Returns the TabPanel component used by this region
22224 * @return {Roo.TabPanel}
22226 getTabs : function(){
22230 createTool : function(parentEl, className){
22231 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
22232 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
22233 btn.addClassOnOver("x-layout-tools-button-over");
22238 * Ext JS Library 1.1.1
22239 * Copyright(c) 2006-2007, Ext JS, LLC.
22241 * Originally Released Under LGPL - original licence link has changed is not relivant.
22244 * <script type="text/javascript">
22250 * @class Roo.SplitLayoutRegion
22251 * @extends Roo.LayoutRegion
22252 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
22254 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
22255 this.cursor = cursor;
22256 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
22259 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
22260 splitTip : "Drag to resize.",
22261 collapsibleSplitTip : "Drag to resize. Double click to hide.",
22262 useSplitTips : false,
22264 applyConfig : function(config){
22265 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
22268 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
22269 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
22270 /** The SplitBar for this region
22271 * @type Roo.SplitBar */
22272 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
22273 this.split.on("moved", this.onSplitMove, this);
22274 this.split.useShim = config.useShim === true;
22275 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
22276 if(this.useSplitTips){
22277 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
22279 if(config.collapsible){
22280 this.split.el.on("dblclick", this.collapse, this);
22283 if(typeof config.minSize != "undefined"){
22284 this.split.minSize = config.minSize;
22286 if(typeof config.maxSize != "undefined"){
22287 this.split.maxSize = config.maxSize;
22289 if(config.hideWhenEmpty || config.hidden || config.collapsed){
22290 this.hideSplitter();
22295 getHMaxSize : function(){
22296 var cmax = this.config.maxSize || 10000;
22297 var center = this.mgr.getRegion("center");
22298 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
22301 getVMaxSize : function(){
22302 var cmax = this.config.maxSize || 10000;
22303 var center = this.mgr.getRegion("center");
22304 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
22307 onSplitMove : function(split, newSize){
22308 this.fireEvent("resized", this, newSize);
22312 * Returns the {@link Roo.SplitBar} for this region.
22313 * @return {Roo.SplitBar}
22315 getSplitBar : function(){
22320 this.hideSplitter();
22321 Roo.SplitLayoutRegion.superclass.hide.call(this);
22324 hideSplitter : function(){
22326 this.split.el.setLocation(-2000,-2000);
22327 this.split.el.hide();
22333 this.split.el.show();
22335 Roo.SplitLayoutRegion.superclass.show.call(this);
22338 beforeSlide: function(){
22339 if(Roo.isGecko){// firefox overflow auto bug workaround
22340 this.bodyEl.clip();
22341 if(this.tabs) this.tabs.bodyEl.clip();
22342 if(this.activePanel){
22343 this.activePanel.getEl().clip();
22345 if(this.activePanel.beforeSlide){
22346 this.activePanel.beforeSlide();
22352 afterSlide : function(){
22353 if(Roo.isGecko){// firefox overflow auto bug workaround
22354 this.bodyEl.unclip();
22355 if(this.tabs) this.tabs.bodyEl.unclip();
22356 if(this.activePanel){
22357 this.activePanel.getEl().unclip();
22358 if(this.activePanel.afterSlide){
22359 this.activePanel.afterSlide();
22365 initAutoHide : function(){
22366 if(this.autoHide !== false){
22367 if(!this.autoHideHd){
22368 var st = new Roo.util.DelayedTask(this.slideIn, this);
22369 this.autoHideHd = {
22370 "mouseout": function(e){
22371 if(!e.within(this.el, true)){
22375 "mouseover" : function(e){
22381 this.el.on(this.autoHideHd);
22385 clearAutoHide : function(){
22386 if(this.autoHide !== false){
22387 this.el.un("mouseout", this.autoHideHd.mouseout);
22388 this.el.un("mouseover", this.autoHideHd.mouseover);
22392 clearMonitor : function(){
22393 Roo.get(document).un("click", this.slideInIf, this);
22396 // these names are backwards but not changed for compat
22397 slideOut : function(){
22398 if(this.isSlid || this.el.hasActiveFx()){
22401 this.isSlid = true;
22402 if(this.collapseBtn){
22403 this.collapseBtn.hide();
22405 this.closeBtnState = this.closeBtn.getStyle('display');
22406 this.closeBtn.hide();
22408 this.stickBtn.show();
22411 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
22412 this.beforeSlide();
22413 this.el.setStyle("z-index", 10001);
22414 this.el.slideIn(this.getSlideAnchor(), {
22415 callback: function(){
22417 this.initAutoHide();
22418 Roo.get(document).on("click", this.slideInIf, this);
22419 this.fireEvent("slideshow", this);
22426 afterSlideIn : function(){
22427 this.clearAutoHide();
22428 this.isSlid = false;
22429 this.clearMonitor();
22430 this.el.setStyle("z-index", "");
22431 if(this.collapseBtn){
22432 this.collapseBtn.show();
22434 this.closeBtn.setStyle('display', this.closeBtnState);
22436 this.stickBtn.hide();
22438 this.fireEvent("slidehide", this);
22441 slideIn : function(cb){
22442 if(!this.isSlid || this.el.hasActiveFx()){
22446 this.isSlid = false;
22447 this.beforeSlide();
22448 this.el.slideOut(this.getSlideAnchor(), {
22449 callback: function(){
22450 this.el.setLeftTop(-10000, -10000);
22452 this.afterSlideIn();
22460 slideInIf : function(e){
22461 if(!e.within(this.el)){
22466 animateCollapse : function(){
22467 this.beforeSlide();
22468 this.el.setStyle("z-index", 20000);
22469 var anchor = this.getSlideAnchor();
22470 this.el.slideOut(anchor, {
22471 callback : function(){
22472 this.el.setStyle("z-index", "");
22473 this.collapsedEl.slideIn(anchor, {duration:.3});
22475 this.el.setLocation(-10000,-10000);
22477 this.fireEvent("collapsed", this);
22484 animateExpand : function(){
22485 this.beforeSlide();
22486 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
22487 this.el.setStyle("z-index", 20000);
22488 this.collapsedEl.hide({
22491 this.el.slideIn(this.getSlideAnchor(), {
22492 callback : function(){
22493 this.el.setStyle("z-index", "");
22496 this.split.el.show();
22498 this.fireEvent("invalidated", this);
22499 this.fireEvent("expanded", this);
22527 getAnchor : function(){
22528 return this.anchors[this.position];
22531 getCollapseAnchor : function(){
22532 return this.canchors[this.position];
22535 getSlideAnchor : function(){
22536 return this.sanchors[this.position];
22539 getAlignAdj : function(){
22540 var cm = this.cmargins;
22541 switch(this.position){
22557 getExpandAdj : function(){
22558 var c = this.collapsedEl, cm = this.cmargins;
22559 switch(this.position){
22561 return [-(cm.right+c.getWidth()+cm.left), 0];
22564 return [cm.right+c.getWidth()+cm.left, 0];
22567 return [0, -(cm.top+cm.bottom+c.getHeight())];
22570 return [0, cm.top+cm.bottom+c.getHeight()];
22576 * Ext JS Library 1.1.1
22577 * Copyright(c) 2006-2007, Ext JS, LLC.
22579 * Originally Released Under LGPL - original licence link has changed is not relivant.
22582 * <script type="text/javascript">
22585 * These classes are private internal classes
22587 Roo.CenterLayoutRegion = function(mgr, config){
22588 Roo.LayoutRegion.call(this, mgr, config, "center");
22589 this.visible = true;
22590 this.minWidth = config.minWidth || 20;
22591 this.minHeight = config.minHeight || 20;
22594 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
22596 // center panel can't be hidden
22600 // center panel can't be hidden
22603 getMinWidth: function(){
22604 return this.minWidth;
22607 getMinHeight: function(){
22608 return this.minHeight;
22613 Roo.NorthLayoutRegion = function(mgr, config){
22614 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
22616 this.split.placement = Roo.SplitBar.TOP;
22617 this.split.orientation = Roo.SplitBar.VERTICAL;
22618 this.split.el.addClass("x-layout-split-v");
22620 var size = config.initialSize || config.height;
22621 if(typeof size != "undefined"){
22622 this.el.setHeight(size);
22625 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
22626 orientation: Roo.SplitBar.VERTICAL,
22627 getBox : function(){
22628 if(this.collapsed){
22629 return this.collapsedEl.getBox();
22631 var box = this.el.getBox();
22633 box.height += this.split.el.getHeight();
22638 updateBox : function(box){
22639 if(this.split && !this.collapsed){
22640 box.height -= this.split.el.getHeight();
22641 this.split.el.setLeft(box.x);
22642 this.split.el.setTop(box.y+box.height);
22643 this.split.el.setWidth(box.width);
22645 if(this.collapsed){
22646 this.updateBody(box.width, null);
22648 Roo.LayoutRegion.prototype.updateBox.call(this, box);
22652 Roo.SouthLayoutRegion = function(mgr, config){
22653 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
22655 this.split.placement = Roo.SplitBar.BOTTOM;
22656 this.split.orientation = Roo.SplitBar.VERTICAL;
22657 this.split.el.addClass("x-layout-split-v");
22659 var size = config.initialSize || config.height;
22660 if(typeof size != "undefined"){
22661 this.el.setHeight(size);
22664 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
22665 orientation: Roo.SplitBar.VERTICAL,
22666 getBox : function(){
22667 if(this.collapsed){
22668 return this.collapsedEl.getBox();
22670 var box = this.el.getBox();
22672 var sh = this.split.el.getHeight();
22679 updateBox : function(box){
22680 if(this.split && !this.collapsed){
22681 var sh = this.split.el.getHeight();
22684 this.split.el.setLeft(box.x);
22685 this.split.el.setTop(box.y-sh);
22686 this.split.el.setWidth(box.width);
22688 if(this.collapsed){
22689 this.updateBody(box.width, null);
22691 Roo.LayoutRegion.prototype.updateBox.call(this, box);
22695 Roo.EastLayoutRegion = function(mgr, config){
22696 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
22698 this.split.placement = Roo.SplitBar.RIGHT;
22699 this.split.orientation = Roo.SplitBar.HORIZONTAL;
22700 this.split.el.addClass("x-layout-split-h");
22702 var size = config.initialSize || config.width;
22703 if(typeof size != "undefined"){
22704 this.el.setWidth(size);
22707 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
22708 orientation: Roo.SplitBar.HORIZONTAL,
22709 getBox : function(){
22710 if(this.collapsed){
22711 return this.collapsedEl.getBox();
22713 var box = this.el.getBox();
22715 var sw = this.split.el.getWidth();
22722 updateBox : function(box){
22723 if(this.split && !this.collapsed){
22724 var sw = this.split.el.getWidth();
22726 this.split.el.setLeft(box.x);
22727 this.split.el.setTop(box.y);
22728 this.split.el.setHeight(box.height);
22731 if(this.collapsed){
22732 this.updateBody(null, box.height);
22734 Roo.LayoutRegion.prototype.updateBox.call(this, box);
22738 Roo.WestLayoutRegion = function(mgr, config){
22739 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
22741 this.split.placement = Roo.SplitBar.LEFT;
22742 this.split.orientation = Roo.SplitBar.HORIZONTAL;
22743 this.split.el.addClass("x-layout-split-h");
22745 var size = config.initialSize || config.width;
22746 if(typeof size != "undefined"){
22747 this.el.setWidth(size);
22750 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
22751 orientation: Roo.SplitBar.HORIZONTAL,
22752 getBox : function(){
22753 if(this.collapsed){
22754 return this.collapsedEl.getBox();
22756 var box = this.el.getBox();
22758 box.width += this.split.el.getWidth();
22763 updateBox : function(box){
22764 if(this.split && !this.collapsed){
22765 var sw = this.split.el.getWidth();
22767 this.split.el.setLeft(box.x+box.width);
22768 this.split.el.setTop(box.y);
22769 this.split.el.setHeight(box.height);
22771 if(this.collapsed){
22772 this.updateBody(null, box.height);
22774 Roo.LayoutRegion.prototype.updateBox.call(this, box);
22779 * Ext JS Library 1.1.1
22780 * Copyright(c) 2006-2007, Ext JS, LLC.
22782 * Originally Released Under LGPL - original licence link has changed is not relivant.
22785 * <script type="text/javascript">
22790 * Private internal class for reading and applying state
22792 Roo.LayoutStateManager = function(layout){
22793 // default empty state
22802 Roo.LayoutStateManager.prototype = {
22803 init : function(layout, provider){
22804 this.provider = provider;
22805 var state = provider.get(layout.id+"-layout-state");
22807 var wasUpdating = layout.isUpdating();
22809 layout.beginUpdate();
22811 for(var key in state){
22812 if(typeof state[key] != "function"){
22813 var rstate = state[key];
22814 var r = layout.getRegion(key);
22817 r.resizeTo(rstate.size);
22819 if(rstate.collapsed == true){
22822 r.expand(null, true);
22828 layout.endUpdate();
22830 this.state = state;
22832 this.layout = layout;
22833 layout.on("regionresized", this.onRegionResized, this);
22834 layout.on("regioncollapsed", this.onRegionCollapsed, this);
22835 layout.on("regionexpanded", this.onRegionExpanded, this);
22838 storeState : function(){
22839 this.provider.set(this.layout.id+"-layout-state", this.state);
22842 onRegionResized : function(region, newSize){
22843 this.state[region.getPosition()].size = newSize;
22847 onRegionCollapsed : function(region){
22848 this.state[region.getPosition()].collapsed = true;
22852 onRegionExpanded : function(region){
22853 this.state[region.getPosition()].collapsed = false;
22858 * Ext JS Library 1.1.1
22859 * Copyright(c) 2006-2007, Ext JS, LLC.
22861 * Originally Released Under LGPL - original licence link has changed is not relivant.
22864 * <script type="text/javascript">
22867 * @class Roo.ContentPanel
22868 * @extends Roo.util.Observable
22869 * A basic ContentPanel element.
22870 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
22871 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
22872 * @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
22873 * @cfg {Boolean} closable True if the panel can be closed/removed
22874 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
22875 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
22876 * @cfg {Toolbar} toolbar A toolbar for this panel
22877 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
22878 * @cfg {String} title The title for this panel
22879 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
22880 * @cfg {String} url Calls {@link #setUrl} with this value
22881 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
22882 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
22884 * Create a new ContentPanel.
22885 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
22886 * @param {String/Object} config A string to set only the title or a config object
22887 * @param {String} content (optional) Set the HTML content for this panel
22888 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
22890 Roo.ContentPanel = function(el, config, content){
22894 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
22898 if (config && config.parentLayout) {
22899 el = config.parentLayout.el.createChild();
22902 if(el.autoCreate){ // xtype is available if this is called from factory
22906 this.el = Roo.get(el);
22907 if(!this.el && config && config.autoCreate){
22908 if(typeof config.autoCreate == "object"){
22909 if(!config.autoCreate.id){
22910 config.autoCreate.id = config.id||el;
22912 this.el = Roo.DomHelper.append(document.body,
22913 config.autoCreate, true);
22915 this.el = Roo.DomHelper.append(document.body,
22916 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
22919 this.closable = false;
22920 this.loaded = false;
22921 this.active = false;
22922 if(typeof config == "string"){
22923 this.title = config;
22925 Roo.apply(this, config);
22928 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
22929 this.wrapEl = this.el.wrap();
22930 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
22937 this.resizeEl = Roo.get(this.resizeEl, true);
22939 this.resizeEl = this.el;
22944 * Fires when this panel is activated.
22945 * @param {Roo.ContentPanel} this
22949 * @event deactivate
22950 * Fires when this panel is activated.
22951 * @param {Roo.ContentPanel} this
22953 "deactivate" : true,
22957 * Fires when this panel is resized if fitToFrame is true.
22958 * @param {Roo.ContentPanel} this
22959 * @param {Number} width The width after any component adjustments
22960 * @param {Number} height The height after any component adjustments
22964 if(this.autoScroll){
22965 this.resizeEl.setStyle("overflow", "auto");
22967 content = content || this.content;
22969 this.setContent(content);
22971 if(config && config.url){
22972 this.setUrl(this.url, this.params, this.loadOnce);
22977 Roo.ContentPanel.superclass.constructor.call(this);
22980 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
22982 setRegion : function(region){
22983 this.region = region;
22985 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
22987 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
22992 * Returns the toolbar for this Panel if one was configured.
22993 * @return {Roo.Toolbar}
22995 getToolbar : function(){
22996 return this.toolbar;
22999 setActiveState : function(active){
23000 this.active = active;
23002 this.fireEvent("deactivate", this);
23004 this.fireEvent("activate", this);
23008 * Updates this panel's element
23009 * @param {String} content The new content
23010 * @param {Boolean} loadScripts (optional) true to look for and process scripts
23012 setContent : function(content, loadScripts){
23013 this.el.update(content, loadScripts);
23016 ignoreResize : function(w, h){
23017 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23020 this.lastSize = {width: w, height: h};
23025 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
23026 * @return {Roo.UpdateManager} The UpdateManager
23028 getUpdateManager : function(){
23029 return this.el.getUpdateManager();
23032 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
23033 * @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:
23036 url: "your-url.php",
23037 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
23038 callback: yourFunction,
23039 scope: yourObject, //(optional scope)
23042 text: "Loading...",
23047 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
23048 * 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.
23049 * @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}
23050 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
23051 * @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.
23052 * @return {Roo.ContentPanel} this
23055 var um = this.el.getUpdateManager();
23056 um.update.apply(um, arguments);
23062 * 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.
23063 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
23064 * @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)
23065 * @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)
23066 * @return {Roo.UpdateManager} The UpdateManager
23068 setUrl : function(url, params, loadOnce){
23069 if(this.refreshDelegate){
23070 this.removeListener("activate", this.refreshDelegate);
23072 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
23073 this.on("activate", this.refreshDelegate);
23074 return this.el.getUpdateManager();
23077 _handleRefresh : function(url, params, loadOnce){
23078 if(!loadOnce || !this.loaded){
23079 var updater = this.el.getUpdateManager();
23080 updater.update(url, params, this._setLoaded.createDelegate(this));
23084 _setLoaded : function(){
23085 this.loaded = true;
23089 * Returns this panel's id
23092 getId : function(){
23097 * Returns this panel's element - used by regiosn to add.
23098 * @return {Roo.Element}
23100 getEl : function(){
23101 return this.wrapEl || this.el;
23104 adjustForComponents : function(width, height){
23105 if(this.resizeEl != this.el){
23106 width -= this.el.getFrameWidth('lr');
23107 height -= this.el.getFrameWidth('tb');
23110 var te = this.toolbar.getEl();
23111 height -= te.getHeight();
23112 te.setWidth(width);
23114 if(this.adjustments){
23115 width += this.adjustments[0];
23116 height += this.adjustments[1];
23118 return {"width": width, "height": height};
23121 setSize : function(width, height){
23122 if(this.fitToFrame && !this.ignoreResize(width, height)){
23123 if(this.fitContainer && this.resizeEl != this.el){
23124 this.el.setSize(width, height);
23126 var size = this.adjustForComponents(width, height);
23127 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
23128 this.fireEvent('resize', this, size.width, size.height);
23133 * Returns this panel's title
23136 getTitle : function(){
23141 * Set this panel's title
23142 * @param {String} title
23144 setTitle : function(title){
23145 this.title = title;
23147 this.region.updatePanelTitle(this, title);
23152 * Returns true is this panel was configured to be closable
23153 * @return {Boolean}
23155 isClosable : function(){
23156 return this.closable;
23159 beforeSlide : function(){
23161 this.resizeEl.clip();
23164 afterSlide : function(){
23166 this.resizeEl.unclip();
23170 * Force a content refresh from the URL specified in the {@link #setUrl} method.
23171 * Will fail silently if the {@link #setUrl} method has not been called.
23172 * This does not activate the panel, just updates its content.
23174 refresh : function(){
23175 if(this.refreshDelegate){
23176 this.loaded = false;
23177 this.refreshDelegate();
23182 * Destroys this panel
23184 destroy : function(){
23185 this.el.removeAllListeners();
23186 var tempEl = document.createElement("span");
23187 tempEl.appendChild(this.el.dom);
23188 tempEl.innerHTML = "";
23194 * Adds a xtype elements to the panel - currently only supports Forms.
23204 * @param {Object} cfg Xtype definition of item to add.
23207 addxtype : function(cfg) {
23209 if (!cfg.xtype.match(/^Form$/)) {
23212 var el = this.el.createChild();
23214 this.form = new Roo.form.Form(cfg);
23217 if ( this.form.allItems.length) this.form.render(el.dom);
23224 * @class Roo.GridPanel
23225 * @extends Roo.ContentPanel
23227 * Create a new GridPanel.
23228 * @param {Roo.grid.Grid} grid The grid for this panel
23229 * @param {String/Object} config A string to set only the panel's title, or a config object
23231 Roo.GridPanel = function(grid, config){
23234 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
23235 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
23237 this.wrapper.dom.appendChild(grid.getGridEl().dom);
23239 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
23242 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
23244 // xtype created footer. - not sure if will work as we normally have to render first..
23245 if (this.footer && !this.footer.el && this.footer.xtype) {
23247 this.footer.container = this.grid.getView().getFooterPanel(true);
23248 this.footer.dataSource = this.grid.dataSource;
23249 this.footer = Roo.factory(this.footer, Roo);
23253 grid.monitorWindowResize = false; // turn off autosizing
23254 grid.autoHeight = false;
23255 grid.autoWidth = false;
23257 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
23260 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
23261 getId : function(){
23262 return this.grid.id;
23266 * Returns the grid for this panel
23267 * @return {Roo.grid.Grid}
23269 getGrid : function(){
23273 setSize : function(width, height){
23274 if(!this.ignoreResize(width, height)){
23275 var grid = this.grid;
23276 var size = this.adjustForComponents(width, height);
23277 grid.getGridEl().setSize(size.width, size.height);
23282 beforeSlide : function(){
23283 this.grid.getView().scroller.clip();
23286 afterSlide : function(){
23287 this.grid.getView().scroller.unclip();
23290 destroy : function(){
23291 this.grid.destroy();
23293 Roo.GridPanel.superclass.destroy.call(this);
23299 * @class Roo.NestedLayoutPanel
23300 * @extends Roo.ContentPanel
23302 * Create a new NestedLayoutPanel.
23305 * @param {Roo.BorderLayout} layout The layout for this panel
23306 * @param {String/Object} config A string to set only the title or a config object
23308 Roo.NestedLayoutPanel = function(layout, config)
23310 // construct with only one argument..
23311 /* FIXME - implement nicer consturctors
23312 if (layout.layout) {
23314 layout = config.layout;
23315 delete config.layout;
23317 if (layout.xtype && !layout.getEl) {
23318 // then layout needs constructing..
23319 layout = Roo.factory(layout, Roo);
23323 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
23325 layout.monitorWindowResize = false; // turn off autosizing
23326 this.layout = layout;
23327 this.layout.getEl().addClass("x-layout-nested-layout");
23333 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
23335 setSize : function(width, height){
23336 if(!this.ignoreResize(width, height)){
23337 var size = this.adjustForComponents(width, height);
23338 var el = this.layout.getEl();
23339 el.setSize(size.width, size.height);
23340 var touch = el.dom.offsetWidth;
23341 this.layout.layout();
23342 // ie requires a double layout on the first pass
23343 if(Roo.isIE && !this.initialized){
23344 this.initialized = true;
23345 this.layout.layout();
23350 // activate all subpanels if not currently active..
23352 setActiveState : function(active){
23353 this.active = active;
23355 this.fireEvent("deactivate", this);
23359 this.fireEvent("activate", this);
23360 // not sure if this should happen before or after..
23361 if (!this.layout) {
23362 return; // should not happen..
23365 for (var r in this.layout.regions) {
23366 reg = this.layout.getRegion(r);
23367 if (reg.getActivePanel()) {
23368 //reg.showPanel(reg.getActivePanel()); // force it to activate..
23369 reg.setActivePanel(reg.getActivePanel());
23372 if (!reg.panels.length) {
23375 reg.showPanel(reg.getPanel(0));
23384 * Returns the nested BorderLayout for this panel
23385 * @return {Roo.BorderLayout}
23387 getLayout : function(){
23388 return this.layout;
23392 * Adds a xtype elements to the layout of the nested panel
23396 xtype : 'ContentPanel',
23403 xtype : 'NestedLayoutPanel',
23409 items : [ ... list of content panels or nested layout panels.. ]
23413 * @param {Object} cfg Xtype definition of item to add.
23415 addxtype : function(cfg) {
23416 return this.layout.addxtype(cfg);
23421 Roo.ScrollPanel = function(el, config, content){
23422 config = config || {};
23423 config.fitToFrame = true;
23424 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
23426 this.el.dom.style.overflow = "hidden";
23427 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
23428 this.el.removeClass("x-layout-inactive-content");
23429 this.el.on("mousewheel", this.onWheel, this);
23431 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
23432 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
23433 up.unselectable(); down.unselectable();
23434 up.on("click", this.scrollUp, this);
23435 down.on("click", this.scrollDown, this);
23436 up.addClassOnOver("x-scroller-btn-over");
23437 down.addClassOnOver("x-scroller-btn-over");
23438 up.addClassOnClick("x-scroller-btn-click");
23439 down.addClassOnClick("x-scroller-btn-click");
23440 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
23442 this.resizeEl = this.el;
23443 this.el = wrap; this.up = up; this.down = down;
23446 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
23448 wheelIncrement : 5,
23449 scrollUp : function(){
23450 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
23453 scrollDown : function(){
23454 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
23457 afterScroll : function(){
23458 var el = this.resizeEl;
23459 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
23460 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
23461 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
23464 setSize : function(){
23465 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
23466 this.afterScroll();
23469 onWheel : function(e){
23470 var d = e.getWheelDelta();
23471 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
23472 this.afterScroll();
23476 setContent : function(content, loadScripts){
23477 this.resizeEl.update(content, loadScripts);
23491 * @class Roo.TreePanel
23492 * @extends Roo.ContentPanel
23494 * Create a new TreePanel.
23495 * @param {String/Object} config A string to set only the panel's title, or a config object
23496 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
23498 Roo.TreePanel = function(config){
23499 var el = config.el;
23500 var tree = config.tree;
23501 delete config.tree;
23502 delete config.el; // hopefull!
23503 Roo.TreePanel.superclass.constructor.call(this, el, config);
23504 var treeEl = el.createChild();
23505 this.tree = new Roo.tree.TreePanel(treeEl , tree);
23506 //console.log(tree);
23507 this.on('activate', function()
23509 if (this.tree.rendered) {
23512 //console.log('render tree');
23513 this.tree.render();
23516 this.on('resize', function (cp, w, h) {
23517 this.tree.innerCt.setWidth(w);
23518 this.tree.innerCt.setHeight(h);
23519 this.tree.innerCt.setStyle('overflow-y', 'auto');
23526 Roo.extend(Roo.TreePanel, Roo.ContentPanel);
23540 * Ext JS Library 1.1.1
23541 * Copyright(c) 2006-2007, Ext JS, LLC.
23543 * Originally Released Under LGPL - original licence link has changed is not relivant.
23546 * <script type="text/javascript">
23551 * @class Roo.ReaderLayout
23552 * @extends Roo.BorderLayout
23553 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
23554 * center region containing two nested regions (a top one for a list view and one for item preview below),
23555 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
23556 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
23557 * expedites the setup of the overall layout and regions for this common application style.
23560 var reader = new Roo.ReaderLayout();
23561 var CP = Roo.ContentPanel; // shortcut for adding
23563 reader.beginUpdate();
23564 reader.add("north", new CP("north", "North"));
23565 reader.add("west", new CP("west", {title: "West"}));
23566 reader.add("east", new CP("east", {title: "East"}));
23568 reader.regions.listView.add(new CP("listView", "List"));
23569 reader.regions.preview.add(new CP("preview", "Preview"));
23570 reader.endUpdate();
23573 * Create a new ReaderLayout
23574 * @param {Object} config Configuration options
23575 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
23576 * document.body if omitted)
23578 Roo.ReaderLayout = function(config, renderTo){
23579 var c = config || {size:{}};
23580 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
23581 north: c.north !== false ? Roo.apply({
23585 }, c.north) : false,
23586 west: c.west !== false ? Roo.apply({
23594 margins:{left:5,right:0,bottom:5,top:5},
23595 cmargins:{left:5,right:5,bottom:5,top:5}
23596 }, c.west) : false,
23597 east: c.east !== false ? Roo.apply({
23605 margins:{left:0,right:5,bottom:5,top:5},
23606 cmargins:{left:5,right:5,bottom:5,top:5}
23607 }, c.east) : false,
23608 center: Roo.apply({
23609 tabPosition: 'top',
23613 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
23617 this.el.addClass('x-reader');
23619 this.beginUpdate();
23621 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
23622 south: c.preview !== false ? Roo.apply({
23629 cmargins:{top:5,left:0, right:0, bottom:0}
23630 }, c.preview) : false,
23631 center: Roo.apply({
23637 this.add('center', new Roo.NestedLayoutPanel(inner,
23638 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
23642 this.regions.preview = inner.getRegion('south');
23643 this.regions.listView = inner.getRegion('center');
23646 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
23648 * Ext JS Library 1.1.1
23649 * Copyright(c) 2006-2007, Ext JS, LLC.
23651 * Originally Released Under LGPL - original licence link has changed is not relivant.
23654 * <script type="text/javascript">
23658 * @class Roo.grid.Grid
23659 * @extends Roo.util.Observable
23660 * This class represents the primary interface of a component based grid control.
23661 * <br><br>Usage:<pre><code>
23662 var grid = new Roo.grid.Grid("my-container-id", {
23665 selModel: mySelectionModel,
23666 autoSizeColumns: true,
23667 monitorWindowResize: false,
23668 trackMouseOver: true
23673 * <b>Common Problems:</b><br/>
23674 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
23675 * element will correct this<br/>
23676 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
23677 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
23678 * are unpredictable.<br/>
23679 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
23680 * grid to calculate dimensions/offsets.<br/>
23682 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
23683 * The container MUST have some type of size defined for the grid to fill. The container will be
23684 * automatically set to position relative if it isn't already.
23685 * @param {Object} config A config object that sets properties on this grid.
23687 Roo.grid.Grid = function(container, config){
23688 // initialize the container
23689 this.container = Roo.get(container);
23690 this.container.update("");
23691 this.container.setStyle("overflow", "hidden");
23692 this.container.addClass('x-grid-container');
23694 this.id = this.container.id;
23696 Roo.apply(this, config);
23697 // check and correct shorthanded configs
23699 this.dataSource = this.ds;
23703 this.colModel = this.cm;
23707 this.selModel = this.sm;
23711 if (this.selModel) {
23712 this.selModel = Roo.factory(this.selModel, Roo.grid);
23713 this.sm = this.selModel;
23714 this.sm.xmodule = this.xmodule || false;
23716 if (typeof(this.colModel.config) == 'undefined') {
23717 this.colModel = new Roo.grid.ColumnModel(this.colModel);
23718 this.cm = this.colModel;
23719 this.cm.xmodule = this.xmodule || false;
23721 if (this.dataSource) {
23722 this.dataSource= Roo.factory(this.dataSource, Roo.data);
23723 this.ds = this.dataSource;
23724 this.ds.xmodule = this.xmodule || false;
23731 this.container.setWidth(this.width);
23735 this.container.setHeight(this.height);
23742 * The raw click event for the entire grid.
23743 * @param {Roo.EventObject} e
23748 * The raw dblclick event for the entire grid.
23749 * @param {Roo.EventObject} e
23753 * @event contextmenu
23754 * The raw contextmenu event for the entire grid.
23755 * @param {Roo.EventObject} e
23757 "contextmenu" : true,
23760 * The raw mousedown event for the entire grid.
23761 * @param {Roo.EventObject} e
23763 "mousedown" : true,
23766 * The raw mouseup event for the entire grid.
23767 * @param {Roo.EventObject} e
23772 * The raw mouseover event for the entire grid.
23773 * @param {Roo.EventObject} e
23775 "mouseover" : true,
23778 * The raw mouseout event for the entire grid.
23779 * @param {Roo.EventObject} e
23784 * The raw keypress event for the entire grid.
23785 * @param {Roo.EventObject} e
23790 * The raw keydown event for the entire grid.
23791 * @param {Roo.EventObject} e
23799 * Fires when a cell is clicked
23800 * @param {Grid} this
23801 * @param {Number} rowIndex
23802 * @param {Number} columnIndex
23803 * @param {Roo.EventObject} e
23805 "cellclick" : true,
23807 * @event celldblclick
23808 * Fires when a cell is double clicked
23809 * @param {Grid} this
23810 * @param {Number} rowIndex
23811 * @param {Number} columnIndex
23812 * @param {Roo.EventObject} e
23814 "celldblclick" : true,
23817 * Fires when a row is clicked
23818 * @param {Grid} this
23819 * @param {Number} rowIndex
23820 * @param {Roo.EventObject} e
23824 * @event rowdblclick
23825 * Fires when a row is double clicked
23826 * @param {Grid} this
23827 * @param {Number} rowIndex
23828 * @param {Roo.EventObject} e
23830 "rowdblclick" : true,
23832 * @event headerclick
23833 * Fires when a header is clicked
23834 * @param {Grid} this
23835 * @param {Number} columnIndex
23836 * @param {Roo.EventObject} e
23838 "headerclick" : true,
23840 * @event headerdblclick
23841 * Fires when a header cell is double clicked
23842 * @param {Grid} this
23843 * @param {Number} columnIndex
23844 * @param {Roo.EventObject} e
23846 "headerdblclick" : true,
23848 * @event rowcontextmenu
23849 * Fires when a row is right clicked
23850 * @param {Grid} this
23851 * @param {Number} rowIndex
23852 * @param {Roo.EventObject} e
23854 "rowcontextmenu" : true,
23856 * @event cellcontextmenu
23857 * Fires when a cell is right clicked
23858 * @param {Grid} this
23859 * @param {Number} rowIndex
23860 * @param {Number} cellIndex
23861 * @param {Roo.EventObject} e
23863 "cellcontextmenu" : true,
23865 * @event headercontextmenu
23866 * Fires when a header is right clicked
23867 * @param {Grid} this
23868 * @param {Number} columnIndex
23869 * @param {Roo.EventObject} e
23871 "headercontextmenu" : true,
23873 * @event bodyscroll
23874 * Fires when the body element is scrolled
23875 * @param {Number} scrollLeft
23876 * @param {Number} scrollTop
23878 "bodyscroll" : true,
23880 * @event columnresize
23881 * Fires when the user resizes a column
23882 * @param {Number} columnIndex
23883 * @param {Number} newSize
23885 "columnresize" : true,
23887 * @event columnmove
23888 * Fires when the user moves a column
23889 * @param {Number} oldIndex
23890 * @param {Number} newIndex
23892 "columnmove" : true,
23895 * Fires when row(s) start being dragged
23896 * @param {Grid} this
23897 * @param {Roo.GridDD} dd The drag drop object
23898 * @param {event} e The raw browser event
23900 "startdrag" : true,
23903 * Fires when a drag operation is complete
23904 * @param {Grid} this
23905 * @param {Roo.GridDD} dd The drag drop object
23906 * @param {event} e The raw browser event
23911 * Fires when dragged row(s) are dropped on a valid DD target
23912 * @param {Grid} this
23913 * @param {Roo.GridDD} dd The drag drop object
23914 * @param {String} targetId The target drag drop object
23915 * @param {event} e The raw browser event
23920 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
23921 * @param {Grid} this
23922 * @param {Roo.GridDD} dd The drag drop object
23923 * @param {String} targetId The target drag drop object
23924 * @param {event} e The raw browser event
23929 * Fires when the dragged row(s) first cross another DD target while being dragged
23930 * @param {Grid} this
23931 * @param {Roo.GridDD} dd The drag drop object
23932 * @param {String} targetId The target drag drop object
23933 * @param {event} e The raw browser event
23935 "dragenter" : true,
23938 * Fires when the dragged row(s) leave another DD target while being dragged
23939 * @param {Grid} this
23940 * @param {Roo.GridDD} dd The drag drop object
23941 * @param {String} targetId The target drag drop object
23942 * @param {event} e The raw browser event
23947 * Fires when the grid is rendered
23948 * @param {Grid} grid
23953 Roo.grid.Grid.superclass.constructor.call(this);
23955 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
23957 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
23959 minColumnWidth : 25,
23962 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
23963 * <b>on initial render.</b> It is more efficient to explicitly size the columns
23964 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
23966 autoSizeColumns : false,
23969 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
23971 autoSizeHeaders : true,
23974 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
23976 monitorWindowResize : true,
23979 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
23980 * rows measured to get a columns size. Default is 0 (all rows).
23982 maxRowsToMeasure : 0,
23985 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
23987 trackMouseOver : true,
23990 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
23992 enableDragDrop : false,
23995 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
23997 enableColumnMove : true,
24000 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
24002 enableColumnHide : true,
24005 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
24007 enableRowHeightSync : false,
24010 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
24015 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
24017 autoHeight : false,
24020 * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
24022 autoExpandColumn : false,
24025 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
24028 autoExpandMin : 50,
24031 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
24033 autoExpandMax : 1000,
24036 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
24041 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
24049 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
24050 * of a fixed width. Default is false.
24053 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
24056 * Called once after all setup has been completed and the grid is ready to be rendered.
24057 * @return {Roo.grid.Grid} this
24059 render : function(){
24060 var c = this.container;
24061 // try to detect autoHeight/width mode
24062 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
24063 this.autoHeight = true;
24065 var view = this.getView();
24068 c.on("click", this.onClick, this);
24069 c.on("dblclick", this.onDblClick, this);
24070 c.on("contextmenu", this.onContextMenu, this);
24071 c.on("keydown", this.onKeyDown, this);
24073 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
24075 this.getSelectionModel().init(this);
24080 this.loadMask = new Roo.LoadMask(this.container,
24081 Roo.apply({store:this.dataSource}, this.loadMask));
24085 if (this.toolbar && this.toolbar.xtype) {
24086 this.toolbar.container = this.getView().getHeaderPanel(true);
24087 this.toolbar = new Ext.Toolbar(this.toolbar);
24089 if (this.footer && this.footer.xtype) {
24090 this.footer.dataSource = this.getDataSource();
24091 this.footer.container = this.getView().getFooterPanel(true);
24092 this.footer = Roo.factory(this.footer, Roo);
24094 this.rendered = true;
24095 this.fireEvent('render', this);
24100 * Reconfigures the grid to use a different Store and Column Model.
24101 * The View will be bound to the new objects and refreshed.
24102 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
24103 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
24105 reconfigure : function(dataSource, colModel){
24107 this.loadMask.destroy();
24108 this.loadMask = new Roo.LoadMask(this.container,
24109 Roo.apply({store:dataSource}, this.loadMask));
24111 this.view.bind(dataSource, colModel);
24112 this.dataSource = dataSource;
24113 this.colModel = colModel;
24114 this.view.refresh(true);
24118 onKeyDown : function(e){
24119 this.fireEvent("keydown", e);
24123 * Destroy this grid.
24124 * @param {Boolean} removeEl True to remove the element
24126 destroy : function(removeEl, keepListeners){
24128 this.loadMask.destroy();
24130 var c = this.container;
24131 c.removeAllListeners();
24132 this.view.destroy();
24133 this.colModel.purgeListeners();
24134 if(!keepListeners){
24135 this.purgeListeners();
24138 if(removeEl === true){
24144 processEvent : function(name, e){
24145 this.fireEvent(name, e);
24146 var t = e.getTarget();
24148 var header = v.findHeaderIndex(t);
24149 if(header !== false){
24150 this.fireEvent("header" + name, this, header, e);
24152 var row = v.findRowIndex(t);
24153 var cell = v.findCellIndex(t);
24155 this.fireEvent("row" + name, this, row, e);
24156 if(cell !== false){
24157 this.fireEvent("cell" + name, this, row, cell, e);
24164 onClick : function(e){
24165 this.processEvent("click", e);
24169 onContextMenu : function(e, t){
24170 this.processEvent("contextmenu", e);
24174 onDblClick : function(e){
24175 this.processEvent("dblclick", e);
24179 walkCells : function(row, col, step, fn, scope){
24180 var cm = this.colModel, clen = cm.getColumnCount();
24181 var ds = this.dataSource, rlen = ds.getCount(), first = true;
24193 if(fn.call(scope || this, row, col, cm) === true){
24211 if(fn.call(scope || this, row, col, cm) === true){
24223 getSelections : function(){
24224 return this.selModel.getSelections();
24228 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
24229 * but if manual update is required this method will initiate it.
24231 autoSize : function(){
24233 this.view.layout();
24234 if(this.view.adjustForScroll){
24235 this.view.adjustForScroll();
24241 * Returns the grid's underlying element.
24242 * @return {Element} The element
24244 getGridEl : function(){
24245 return this.container;
24248 // private for compatibility, overridden by editor grid
24249 stopEditing : function(){},
24252 * Returns the grid's SelectionModel.
24253 * @return {SelectionModel}
24255 getSelectionModel : function(){
24256 if(!this.selModel){
24257 this.selModel = new Roo.grid.RowSelectionModel();
24259 return this.selModel;
24263 * Returns the grid's DataSource.
24264 * @return {DataSource}
24266 getDataSource : function(){
24267 return this.dataSource;
24271 * Returns the grid's ColumnModel.
24272 * @return {ColumnModel}
24274 getColumnModel : function(){
24275 return this.colModel;
24279 * Returns the grid's GridView object.
24280 * @return {GridView}
24282 getView : function(){
24284 this.view = new Roo.grid.GridView(this.viewConfig);
24289 * Called to get grid's drag proxy text, by default returns this.ddText.
24292 getDragDropText : function(){
24293 var count = this.selModel.getCount();
24294 return String.format(this.ddText, count, count == 1 ? '' : 's');
24298 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
24299 * %0 is replaced with the number of selected rows.
24302 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
24304 * Ext JS Library 1.1.1
24305 * Copyright(c) 2006-2007, Ext JS, LLC.
24307 * Originally Released Under LGPL - original licence link has changed is not relivant.
24310 * <script type="text/javascript">
24313 Roo.grid.AbstractGridView = function(){
24317 "beforerowremoved" : true,
24318 "beforerowsinserted" : true,
24319 "beforerefresh" : true,
24320 "rowremoved" : true,
24321 "rowsinserted" : true,
24322 "rowupdated" : true,
24325 Roo.grid.AbstractGridView.superclass.constructor.call(this);
24328 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
24329 rowClass : "x-grid-row",
24330 cellClass : "x-grid-cell",
24331 tdClass : "x-grid-td",
24332 hdClass : "x-grid-hd",
24333 splitClass : "x-grid-hd-split",
24335 init: function(grid){
24337 var cid = this.grid.getGridEl().id;
24338 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
24339 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
24340 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
24341 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
24344 getColumnRenderers : function(){
24345 var renderers = [];
24346 var cm = this.grid.colModel;
24347 var colCount = cm.getColumnCount();
24348 for(var i = 0; i < colCount; i++){
24349 renderers[i] = cm.getRenderer(i);
24354 getColumnIds : function(){
24356 var cm = this.grid.colModel;
24357 var colCount = cm.getColumnCount();
24358 for(var i = 0; i < colCount; i++){
24359 ids[i] = cm.getColumnId(i);
24364 getDataIndexes : function(){
24365 if(!this.indexMap){
24366 this.indexMap = this.buildIndexMap();
24368 return this.indexMap.colToData;
24371 getColumnIndexByDataIndex : function(dataIndex){
24372 if(!this.indexMap){
24373 this.indexMap = this.buildIndexMap();
24375 return this.indexMap.dataToCol[dataIndex];
24379 * Set a css style for a column dynamically.
24380 * @param {Number} colIndex The index of the column
24381 * @param {String} name The css property name
24382 * @param {String} value The css value
24384 setCSSStyle : function(colIndex, name, value){
24385 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
24386 Roo.util.CSS.updateRule(selector, name, value);
24389 generateRules : function(cm){
24390 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
24391 Roo.util.CSS.removeStyleSheet(rulesId);
24392 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
24393 var cid = cm.getColumnId(i);
24394 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
24395 this.tdSelector, cid, " {\n}\n",
24396 this.hdSelector, cid, " {\n}\n",
24397 this.splitSelector, cid, " {\n}\n");
24399 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
24403 * Ext JS Library 1.1.1
24404 * Copyright(c) 2006-2007, Ext JS, LLC.
24406 * Originally Released Under LGPL - original licence link has changed is not relivant.
24409 * <script type="text/javascript">
24413 // This is a support class used internally by the Grid components
24414 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
24416 this.view = grid.getView();
24417 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
24418 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
24420 this.setHandleElId(Roo.id(hd));
24421 this.setOuterHandleElId(Roo.id(hd2));
24423 this.scroll = false;
24425 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
24427 getDragData : function(e){
24428 var t = Roo.lib.Event.getTarget(e);
24429 var h = this.view.findHeaderCell(t);
24431 return {ddel: h.firstChild, header:h};
24436 onInitDrag : function(e){
24437 this.view.headersDisabled = true;
24438 var clone = this.dragData.ddel.cloneNode(true);
24439 clone.id = Roo.id();
24440 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
24441 this.proxy.update(clone);
24445 afterValidDrop : function(){
24447 setTimeout(function(){
24448 v.headersDisabled = false;
24452 afterInvalidDrop : function(){
24454 setTimeout(function(){
24455 v.headersDisabled = false;
24461 * Ext JS Library 1.1.1
24462 * Copyright(c) 2006-2007, Ext JS, LLC.
24464 * Originally Released Under LGPL - original licence link has changed is not relivant.
24467 * <script type="text/javascript">
24470 // This is a support class used internally by the Grid components
24471 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
24473 this.view = grid.getView();
24474 // split the proxies so they don't interfere with mouse events
24475 this.proxyTop = Roo.DomHelper.append(document.body, {
24476 cls:"col-move-top", html:" "
24478 this.proxyBottom = Roo.DomHelper.append(document.body, {
24479 cls:"col-move-bottom", html:" "
24481 this.proxyTop.hide = this.proxyBottom.hide = function(){
24482 this.setLeftTop(-100,-100);
24483 this.setStyle("visibility", "hidden");
24485 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
24486 // temporarily disabled
24487 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
24488 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
24490 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
24491 proxyOffsets : [-4, -9],
24492 fly: Roo.Element.fly,
24494 getTargetFromEvent : function(e){
24495 var t = Roo.lib.Event.getTarget(e);
24496 var cindex = this.view.findCellIndex(t);
24497 if(cindex !== false){
24498 return this.view.getHeaderCell(cindex);
24502 nextVisible : function(h){
24503 var v = this.view, cm = this.grid.colModel;
24506 if(!cm.isHidden(v.getCellIndex(h))){
24514 prevVisible : function(h){
24515 var v = this.view, cm = this.grid.colModel;
24518 if(!cm.isHidden(v.getCellIndex(h))){
24526 positionIndicator : function(h, n, e){
24527 var x = Roo.lib.Event.getPageX(e);
24528 var r = Roo.lib.Dom.getRegion(n.firstChild);
24529 var px, pt, py = r.top + this.proxyOffsets[1];
24530 if((r.right - x) <= (r.right-r.left)/2){
24531 px = r.right+this.view.borderWidth;
24537 var oldIndex = this.view.getCellIndex(h);
24538 var newIndex = this.view.getCellIndex(n);
24540 if(this.grid.colModel.isFixed(newIndex)){
24544 var locked = this.grid.colModel.isLocked(newIndex);
24549 if(oldIndex < newIndex){
24552 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
24555 px += this.proxyOffsets[0];
24556 this.proxyTop.setLeftTop(px, py);
24557 this.proxyTop.show();
24558 if(!this.bottomOffset){
24559 this.bottomOffset = this.view.mainHd.getHeight();
24561 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
24562 this.proxyBottom.show();
24566 onNodeEnter : function(n, dd, e, data){
24567 if(data.header != n){
24568 this.positionIndicator(data.header, n, e);
24572 onNodeOver : function(n, dd, e, data){
24573 var result = false;
24574 if(data.header != n){
24575 result = this.positionIndicator(data.header, n, e);
24578 this.proxyTop.hide();
24579 this.proxyBottom.hide();
24581 return result ? this.dropAllowed : this.dropNotAllowed;
24584 onNodeOut : function(n, dd, e, data){
24585 this.proxyTop.hide();
24586 this.proxyBottom.hide();
24589 onNodeDrop : function(n, dd, e, data){
24590 var h = data.header;
24592 var cm = this.grid.colModel;
24593 var x = Roo.lib.Event.getPageX(e);
24594 var r = Roo.lib.Dom.getRegion(n.firstChild);
24595 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
24596 var oldIndex = this.view.getCellIndex(h);
24597 var newIndex = this.view.getCellIndex(n);
24598 var locked = cm.isLocked(newIndex);
24602 if(oldIndex < newIndex){
24605 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
24608 cm.setLocked(oldIndex, locked, true);
24609 cm.moveColumn(oldIndex, newIndex);
24610 this.grid.fireEvent("columnmove", oldIndex, newIndex);
24618 * Ext JS Library 1.1.1
24619 * Copyright(c) 2006-2007, Ext JS, LLC.
24621 * Originally Released Under LGPL - original licence link has changed is not relivant.
24624 * <script type="text/javascript">
24628 * @class Roo.grid.GridView
24629 * @extends Roo.util.Observable
24632 * @param {Object} config
24634 Roo.grid.GridView = function(config){
24635 Roo.grid.GridView.superclass.constructor.call(this);
24638 Roo.apply(this, config);
24641 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
24644 * Override this function to apply custom css classes to rows during rendering
24645 * @param {Record} record The record
24646 * @param {Number} index
24647 * @method getRowClass
24649 rowClass : "x-grid-row",
24651 cellClass : "x-grid-col",
24653 tdClass : "x-grid-td",
24655 hdClass : "x-grid-hd",
24657 splitClass : "x-grid-split",
24659 sortClasses : ["sort-asc", "sort-desc"],
24661 enableMoveAnim : false,
24665 dh : Roo.DomHelper,
24667 fly : Roo.Element.fly,
24669 css : Roo.util.CSS,
24675 scrollIncrement : 22,
24677 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
24679 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
24681 bind : function(ds, cm){
24683 this.ds.un("load", this.onLoad, this);
24684 this.ds.un("datachanged", this.onDataChange, this);
24685 this.ds.un("add", this.onAdd, this);
24686 this.ds.un("remove", this.onRemove, this);
24687 this.ds.un("update", this.onUpdate, this);
24688 this.ds.un("clear", this.onClear, this);
24691 ds.on("load", this.onLoad, this);
24692 ds.on("datachanged", this.onDataChange, this);
24693 ds.on("add", this.onAdd, this);
24694 ds.on("remove", this.onRemove, this);
24695 ds.on("update", this.onUpdate, this);
24696 ds.on("clear", this.onClear, this);
24701 this.cm.un("widthchange", this.onColWidthChange, this);
24702 this.cm.un("headerchange", this.onHeaderChange, this);
24703 this.cm.un("hiddenchange", this.onHiddenChange, this);
24704 this.cm.un("columnmoved", this.onColumnMove, this);
24705 this.cm.un("columnlockchange", this.onColumnLock, this);
24708 this.generateRules(cm);
24709 cm.on("widthchange", this.onColWidthChange, this);
24710 cm.on("headerchange", this.onHeaderChange, this);
24711 cm.on("hiddenchange", this.onHiddenChange, this);
24712 cm.on("columnmoved", this.onColumnMove, this);
24713 cm.on("columnlockchange", this.onColumnLock, this);
24718 init: function(grid){
24719 Roo.grid.GridView.superclass.init.call(this, grid);
24721 this.bind(grid.dataSource, grid.colModel);
24723 grid.on("headerclick", this.handleHeaderClick, this);
24725 if(grid.trackMouseOver){
24726 grid.on("mouseover", this.onRowOver, this);
24727 grid.on("mouseout", this.onRowOut, this);
24729 grid.cancelTextSelection = function(){};
24730 this.gridId = grid.id;
24732 var tpls = this.templates || {};
24735 tpls.master = new Roo.Template(
24736 '<div class="x-grid" hidefocus="true">',
24737 '<div class="x-grid-topbar"></div>',
24738 '<div class="x-grid-scroller"><div></div></div>',
24739 '<div class="x-grid-locked">',
24740 '<div class="x-grid-header">{lockedHeader}</div>',
24741 '<div class="x-grid-body">{lockedBody}</div>',
24743 '<div class="x-grid-viewport">',
24744 '<div class="x-grid-header">{header}</div>',
24745 '<div class="x-grid-body">{body}</div>',
24747 '<div class="x-grid-bottombar"></div>',
24748 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
24749 '<div class="x-grid-resize-proxy"> </div>',
24752 tpls.master.disableformats = true;
24756 tpls.header = new Roo.Template(
24757 '<table border="0" cellspacing="0" cellpadding="0">',
24758 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
24761 tpls.header.disableformats = true;
24763 tpls.header.compile();
24766 tpls.hcell = new Roo.Template(
24767 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
24768 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
24771 tpls.hcell.disableFormats = true;
24773 tpls.hcell.compile();
24776 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
24777 tpls.hsplit.disableFormats = true;
24779 tpls.hsplit.compile();
24782 tpls.body = new Roo.Template(
24783 '<table border="0" cellspacing="0" cellpadding="0">',
24784 "<tbody>{rows}</tbody>",
24787 tpls.body.disableFormats = true;
24789 tpls.body.compile();
24792 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
24793 tpls.row.disableFormats = true;
24795 tpls.row.compile();
24798 tpls.cell = new Roo.Template(
24799 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
24800 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
24803 tpls.cell.disableFormats = true;
24805 tpls.cell.compile();
24807 this.templates = tpls;
24810 // remap these for backwards compat
24811 onColWidthChange : function(){
24812 this.updateColumns.apply(this, arguments);
24814 onHeaderChange : function(){
24815 this.updateHeaders.apply(this, arguments);
24817 onHiddenChange : function(){
24818 this.handleHiddenChange.apply(this, arguments);
24820 onColumnMove : function(){
24821 this.handleColumnMove.apply(this, arguments);
24823 onColumnLock : function(){
24824 this.handleLockChange.apply(this, arguments);
24827 onDataChange : function(){
24829 this.updateHeaderSortState();
24832 onClear : function(){
24836 onUpdate : function(ds, record){
24837 this.refreshRow(record);
24840 refreshRow : function(record){
24841 var ds = this.ds, index;
24842 if(typeof record == 'number'){
24844 record = ds.getAt(index);
24846 index = ds.indexOf(record);
24848 this.insertRows(ds, index, index, true);
24849 this.onRemove(ds, record, index+1, true);
24850 this.syncRowHeights(index, index);
24852 this.fireEvent("rowupdated", this, index, record);
24855 onAdd : function(ds, records, index){
24856 this.insertRows(ds, index, index + (records.length-1));
24859 onRemove : function(ds, record, index, isUpdate){
24860 if(isUpdate !== true){
24861 this.fireEvent("beforerowremoved", this, index, record);
24863 var bt = this.getBodyTable(), lt = this.getLockedTable();
24864 if(bt.rows[index]){
24865 bt.firstChild.removeChild(bt.rows[index]);
24867 if(lt.rows[index]){
24868 lt.firstChild.removeChild(lt.rows[index]);
24870 if(isUpdate !== true){
24871 this.stripeRows(index);
24872 this.syncRowHeights(index, index);
24874 this.fireEvent("rowremoved", this, index, record);
24878 onLoad : function(){
24879 this.scrollToTop();
24883 * Scrolls the grid to the top
24885 scrollToTop : function(){
24887 this.scroller.dom.scrollTop = 0;
24893 * Gets a panel in the header of the grid that can be used for toolbars etc.
24894 * After modifying the contents of this panel a call to grid.autoSize() may be
24895 * required to register any changes in size.
24896 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
24897 * @return Roo.Element
24899 getHeaderPanel : function(doShow){
24901 this.headerPanel.show();
24903 return this.headerPanel;
24907 * Gets a panel in the footer of the grid that can be used for toolbars etc.
24908 * After modifying the contents of this panel a call to grid.autoSize() may be
24909 * required to register any changes in size.
24910 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
24911 * @return Roo.Element
24913 getFooterPanel : function(doShow){
24915 this.footerPanel.show();
24917 return this.footerPanel;
24920 initElements : function(){
24921 var E = Roo.Element;
24922 var el = this.grid.getGridEl().dom.firstChild;
24923 var cs = el.childNodes;
24925 this.el = new E(el);
24926 this.headerPanel = new E(el.firstChild);
24927 this.headerPanel.enableDisplayMode("block");
24929 this.scroller = new E(cs[1]);
24930 this.scrollSizer = new E(this.scroller.dom.firstChild);
24932 this.lockedWrap = new E(cs[2]);
24933 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
24934 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
24936 this.mainWrap = new E(cs[3]);
24937 this.mainHd = new E(this.mainWrap.dom.firstChild);
24938 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
24940 this.footerPanel = new E(cs[4]);
24941 this.footerPanel.enableDisplayMode("block");
24943 this.focusEl = new E(cs[5]);
24944 this.focusEl.swallowEvent("click", true);
24945 this.resizeProxy = new E(cs[6]);
24947 this.headerSelector = String.format(
24948 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
24949 this.lockedHd.id, this.mainHd.id
24952 this.splitterSelector = String.format(
24953 '#{0} div.x-grid-split, #{1} div.x-grid-split',
24954 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
24957 idToCssName : function(s)
24959 return s.replace(/[^a-z0-9]+/ig, '-');
24962 getHeaderCell : function(index){
24963 return Roo.DomQuery.select(this.headerSelector)[index];
24966 getHeaderCellMeasure : function(index){
24967 return this.getHeaderCell(index).firstChild;
24970 getHeaderCellText : function(index){
24971 return this.getHeaderCell(index).firstChild.firstChild;
24974 getLockedTable : function(){
24975 return this.lockedBody.dom.firstChild;
24978 getBodyTable : function(){
24979 return this.mainBody.dom.firstChild;
24982 getLockedRow : function(index){
24983 return this.getLockedTable().rows[index];
24986 getRow : function(index){
24987 return this.getBodyTable().rows[index];
24990 getRowComposite : function(index){
24992 this.rowEl = new Roo.CompositeElementLite();
24994 var els = [], lrow, mrow;
24995 if(lrow = this.getLockedRow(index)){
24998 if(mrow = this.getRow(index)){
25001 this.rowEl.elements = els;
25005 getCell : function(rowIndex, colIndex){
25006 var locked = this.cm.getLockedCount();
25008 if(colIndex < locked){
25009 source = this.lockedBody.dom.firstChild;
25011 source = this.mainBody.dom.firstChild;
25012 colIndex -= locked;
25014 return source.rows[rowIndex].childNodes[colIndex];
25017 getCellText : function(rowIndex, colIndex){
25018 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
25021 getCellBox : function(cell){
25022 var b = this.fly(cell).getBox();
25023 if(Roo.isOpera){ // opera fails to report the Y
25024 b.y = cell.offsetTop + this.mainBody.getY();
25029 getCellIndex : function(cell){
25030 var id = String(cell.className).match(this.cellRE);
25032 return parseInt(id[1], 10);
25037 findHeaderIndex : function(n){
25038 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
25039 return r ? this.getCellIndex(r) : false;
25042 findHeaderCell : function(n){
25043 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
25044 return r ? r : false;
25047 findRowIndex : function(n){
25051 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
25052 return r ? r.rowIndex : false;
25055 findCellIndex : function(node){
25056 var stop = this.el.dom;
25057 while(node && node != stop){
25058 if(this.findRE.test(node.className)){
25059 return this.getCellIndex(node);
25061 node = node.parentNode;
25066 getColumnId : function(index){
25067 return this.cm.getColumnId(index);
25070 getSplitters : function(){
25071 if(this.splitterSelector){
25072 return Roo.DomQuery.select(this.splitterSelector);
25078 getSplitter : function(index){
25079 return this.getSplitters()[index];
25082 onRowOver : function(e, t){
25084 if((row = this.findRowIndex(t)) !== false){
25085 this.getRowComposite(row).addClass("x-grid-row-over");
25089 onRowOut : function(e, t){
25091 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
25092 this.getRowComposite(row).removeClass("x-grid-row-over");
25096 renderHeaders : function(){
25098 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
25099 var cb = [], lb = [], sb = [], lsb = [], p = {};
25100 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
25101 p.cellId = "x-grid-hd-0-" + i;
25102 p.splitId = "x-grid-csplit-0-" + i;
25103 p.id = cm.getColumnId(i);
25104 p.title = cm.getColumnTooltip(i) || "";
25105 p.value = cm.getColumnHeader(i) || "";
25106 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
25107 if(!cm.isLocked(i)){
25108 cb[cb.length] = ct.apply(p);
25109 sb[sb.length] = st.apply(p);
25111 lb[lb.length] = ct.apply(p);
25112 lsb[lsb.length] = st.apply(p);
25115 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
25116 ht.apply({cells: cb.join(""), splits:sb.join("")})];
25119 updateHeaders : function(){
25120 var html = this.renderHeaders();
25121 this.lockedHd.update(html[0]);
25122 this.mainHd.update(html[1]);
25126 * Focuses the specified row.
25127 * @param {Number} row The row index
25129 focusRow : function(row){
25130 var x = this.scroller.dom.scrollLeft;
25131 this.focusCell(row, 0, false);
25132 this.scroller.dom.scrollLeft = x;
25136 * Focuses the specified cell.
25137 * @param {Number} row The row index
25138 * @param {Number} col The column index
25139 * @param {Boolean} hscroll false to disable horizontal scrolling
25141 focusCell : function(row, col, hscroll){
25142 var el = this.ensureVisible(row, col, hscroll);
25143 this.focusEl.alignTo(el, "tl-tl");
25145 this.focusEl.focus();
25147 this.focusEl.focus.defer(1, this.focusEl);
25152 * Scrolls the specified cell into view
25153 * @param {Number} row The row index
25154 * @param {Number} col The column index
25155 * @param {Boolean} hscroll false to disable horizontal scrolling
25157 ensureVisible : function(row, col, hscroll){
25158 if(typeof row != "number"){
25159 row = row.rowIndex;
25161 if(row < 0 && row >= this.ds.getCount()){
25164 col = (col !== undefined ? col : 0);
25165 var cm = this.grid.colModel;
25166 while(cm.isHidden(col)){
25170 var el = this.getCell(row, col);
25174 var c = this.scroller.dom;
25176 var ctop = parseInt(el.offsetTop, 10);
25177 var cleft = parseInt(el.offsetLeft, 10);
25178 var cbot = ctop + el.offsetHeight;
25179 var cright = cleft + el.offsetWidth;
25181 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
25182 var stop = parseInt(c.scrollTop, 10);
25183 var sleft = parseInt(c.scrollLeft, 10);
25184 var sbot = stop + ch;
25185 var sright = sleft + c.clientWidth;
25188 c.scrollTop = ctop;
25189 }else if(cbot > sbot){
25190 c.scrollTop = cbot-ch;
25193 if(hscroll !== false){
25195 c.scrollLeft = cleft;
25196 }else if(cright > sright){
25197 c.scrollLeft = cright-c.clientWidth;
25203 updateColumns : function(){
25204 this.grid.stopEditing();
25205 var cm = this.grid.colModel, colIds = this.getColumnIds();
25206 //var totalWidth = cm.getTotalWidth();
25208 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
25209 //if(cm.isHidden(i)) continue;
25210 var w = cm.getColumnWidth(i);
25211 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
25212 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
25214 this.updateSplitters();
25217 generateRules : function(cm){
25218 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
25219 Roo.util.CSS.removeStyleSheet(rulesId);
25220 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
25221 var cid = cm.getColumnId(i);
25223 if(cm.config[i].align){
25224 align = 'text-align:'+cm.config[i].align+';';
25227 if(cm.isHidden(i)){
25228 hidden = 'display:none;';
25230 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
25232 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
25233 this.hdSelector, cid, " {\n", align, width, "}\n",
25234 this.tdSelector, cid, " {\n",hidden,"\n}\n",
25235 this.splitSelector, cid, " {\n", hidden , "\n}\n");
25237 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
25240 updateSplitters : function(){
25241 var cm = this.cm, s = this.getSplitters();
25242 if(s){ // splitters not created yet
25243 var pos = 0, locked = true;
25244 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
25245 if(cm.isHidden(i)) continue;
25246 var w = cm.getColumnWidth(i);
25247 if(!cm.isLocked(i) && locked){
25252 s[i].style.left = (pos-this.splitOffset) + "px";
25257 handleHiddenChange : function(colModel, colIndex, hidden){
25259 this.hideColumn(colIndex);
25261 this.unhideColumn(colIndex);
25265 hideColumn : function(colIndex){
25266 var cid = this.getColumnId(colIndex);
25267 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
25268 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
25270 this.updateHeaders();
25272 this.updateSplitters();
25276 unhideColumn : function(colIndex){
25277 var cid = this.getColumnId(colIndex);
25278 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
25279 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
25282 this.updateHeaders();
25284 this.updateSplitters();
25288 insertRows : function(dm, firstRow, lastRow, isUpdate){
25289 if(firstRow == 0 && lastRow == dm.getCount()-1){
25293 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
25295 var s = this.getScrollState();
25296 var markup = this.renderRows(firstRow, lastRow);
25297 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
25298 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
25299 this.restoreScroll(s);
25301 this.fireEvent("rowsinserted", this, firstRow, lastRow);
25302 this.syncRowHeights(firstRow, lastRow);
25303 this.stripeRows(firstRow);
25309 bufferRows : function(markup, target, index){
25310 var before = null, trows = target.rows, tbody = target.tBodies[0];
25311 if(index < trows.length){
25312 before = trows[index];
25314 var b = document.createElement("div");
25315 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
25316 var rows = b.firstChild.rows;
25317 for(var i = 0, len = rows.length; i < len; i++){
25319 tbody.insertBefore(rows[0], before);
25321 tbody.appendChild(rows[0]);
25328 deleteRows : function(dm, firstRow, lastRow){
25329 if(dm.getRowCount()<1){
25330 this.fireEvent("beforerefresh", this);
25331 this.mainBody.update("");
25332 this.lockedBody.update("");
25333 this.fireEvent("refresh", this);
25335 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
25336 var bt = this.getBodyTable();
25337 var tbody = bt.firstChild;
25338 var rows = bt.rows;
25339 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
25340 tbody.removeChild(rows[firstRow]);
25342 this.stripeRows(firstRow);
25343 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
25347 updateRows : function(dataSource, firstRow, lastRow){
25348 var s = this.getScrollState();
25350 this.restoreScroll(s);
25353 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
25357 this.updateHeaderSortState();
25360 getScrollState : function(){
25361 var sb = this.scroller.dom;
25362 return {left: sb.scrollLeft, top: sb.scrollTop};
25365 stripeRows : function(startRow){
25366 if(!this.grid.stripeRows || this.ds.getCount() < 1){
25369 startRow = startRow || 0;
25370 var rows = this.getBodyTable().rows;
25371 var lrows = this.getLockedTable().rows;
25372 var cls = ' x-grid-row-alt ';
25373 for(var i = startRow, len = rows.length; i < len; i++){
25374 var row = rows[i], lrow = lrows[i];
25375 var isAlt = ((i+1) % 2 == 0);
25376 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
25377 if(isAlt == hasAlt){
25381 row.className += " x-grid-row-alt";
25383 row.className = row.className.replace("x-grid-row-alt", "");
25386 lrow.className = row.className;
25391 restoreScroll : function(state){
25392 var sb = this.scroller.dom;
25393 sb.scrollLeft = state.left;
25394 sb.scrollTop = state.top;
25398 syncScroll : function(){
25399 var sb = this.scroller.dom;
25400 var sh = this.mainHd.dom;
25401 var bs = this.mainBody.dom;
25402 var lv = this.lockedBody.dom;
25403 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
25404 lv.scrollTop = bs.scrollTop = sb.scrollTop;
25407 handleScroll : function(e){
25409 var sb = this.scroller.dom;
25410 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
25414 handleWheel : function(e){
25415 var d = e.getWheelDelta();
25416 this.scroller.dom.scrollTop -= d*22;
25417 // set this here to prevent jumpy scrolling on large tables
25418 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
25422 renderRows : function(startRow, endRow){
25423 // pull in all the crap needed to render rows
25424 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
25425 var colCount = cm.getColumnCount();
25427 if(ds.getCount() < 1){
25431 // build a map for all the columns
25433 for(var i = 0; i < colCount; i++){
25434 var name = cm.getDataIndex(i);
25436 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
25437 renderer : cm.getRenderer(i),
25438 id : cm.getColumnId(i),
25439 locked : cm.isLocked(i)
25443 startRow = startRow || 0;
25444 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
25446 // records to render
25447 var rs = ds.getRange(startRow, endRow);
25449 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
25452 // As much as I hate to duplicate code, this was branched because FireFox really hates
25453 // [].join("") on strings. The performance difference was substantial enough to
25454 // branch this function
25455 doRender : Roo.isGecko ?
25456 function(cs, rs, ds, startRow, colCount, stripe){
25457 var ts = this.templates, ct = ts.cell, rt = ts.row;
25459 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
25460 for(var j = 0, len = rs.length; j < len; j++){
25461 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
25462 for(var i = 0; i < colCount; i++){
25464 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
25466 p.css = p.attr = "";
25467 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
25468 if(p.value == undefined || p.value === "") p.value = " ";
25469 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
25470 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
25472 var markup = ct.apply(p);
25480 if(stripe && ((rowIndex+1) % 2 == 0)){
25481 alt[0] = "x-grid-row-alt";
25484 alt[1] = " x-grid-dirty-row";
25487 if(this.getRowClass){
25488 alt[2] = this.getRowClass(r, rowIndex);
25490 rp.alt = alt.join(" ");
25491 lbuf+= rt.apply(rp);
25493 buf+= rt.apply(rp);
25495 return [lbuf, buf];
25497 function(cs, rs, ds, startRow, colCount, stripe){
25498 var ts = this.templates, ct = ts.cell, rt = ts.row;
25500 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
25501 for(var j = 0, len = rs.length; j < len; j++){
25502 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
25503 for(var i = 0; i < colCount; i++){
25505 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
25507 p.css = p.attr = "";
25508 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
25509 if(p.value == undefined || p.value === "") p.value = " ";
25510 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
25511 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
25513 var markup = ct.apply(p);
25515 cb[cb.length] = markup;
25517 lcb[lcb.length] = markup;
25521 if(stripe && ((rowIndex+1) % 2 == 0)){
25522 alt[0] = "x-grid-row-alt";
25525 alt[1] = " x-grid-dirty-row";
25528 if(this.getRowClass){
25529 alt[2] = this.getRowClass(r, rowIndex);
25531 rp.alt = alt.join(" ");
25532 rp.cells = lcb.join("");
25533 lbuf[lbuf.length] = rt.apply(rp);
25534 rp.cells = cb.join("");
25535 buf[buf.length] = rt.apply(rp);
25537 return [lbuf.join(""), buf.join("")];
25540 renderBody : function(){
25541 var markup = this.renderRows();
25542 var bt = this.templates.body;
25543 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
25547 * Refreshes the grid
25548 * @param {Boolean} headersToo
25550 refresh : function(headersToo){
25551 this.fireEvent("beforerefresh", this);
25552 this.grid.stopEditing();
25553 var result = this.renderBody();
25554 this.lockedBody.update(result[0]);
25555 this.mainBody.update(result[1]);
25556 if(headersToo === true){
25557 this.updateHeaders();
25558 this.updateColumns();
25559 this.updateSplitters();
25560 this.updateHeaderSortState();
25562 this.syncRowHeights();
25564 this.fireEvent("refresh", this);
25567 handleColumnMove : function(cm, oldIndex, newIndex){
25568 this.indexMap = null;
25569 var s = this.getScrollState();
25570 this.refresh(true);
25571 this.restoreScroll(s);
25572 this.afterMove(newIndex);
25575 afterMove : function(colIndex){
25576 if(this.enableMoveAnim && Roo.enableFx){
25577 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
25581 updateCell : function(dm, rowIndex, dataIndex){
25582 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
25583 if(typeof colIndex == "undefined"){ // not present in grid
25586 var cm = this.grid.colModel;
25587 var cell = this.getCell(rowIndex, colIndex);
25588 var cellText = this.getCellText(rowIndex, colIndex);
25591 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
25592 id : cm.getColumnId(colIndex),
25593 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
25595 var renderer = cm.getRenderer(colIndex);
25596 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
25597 if(typeof val == "undefined" || val === "") val = " ";
25598 cellText.innerHTML = val;
25599 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
25600 this.syncRowHeights(rowIndex, rowIndex);
25603 calcColumnWidth : function(colIndex, maxRowsToMeasure){
25605 if(this.grid.autoSizeHeaders){
25606 var h = this.getHeaderCellMeasure(colIndex);
25607 maxWidth = Math.max(maxWidth, h.scrollWidth);
25610 if(this.cm.isLocked(colIndex)){
25611 tb = this.getLockedTable();
25614 tb = this.getBodyTable();
25615 index = colIndex - this.cm.getLockedCount();
25618 var rows = tb.rows;
25619 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
25620 for(var i = 0; i < stopIndex; i++){
25621 var cell = rows[i].childNodes[index].firstChild;
25622 maxWidth = Math.max(maxWidth, cell.scrollWidth);
25625 return maxWidth + /*margin for error in IE*/ 5;
25628 * Autofit a column to its content.
25629 * @param {Number} colIndex
25630 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
25632 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
25633 if(this.cm.isHidden(colIndex)){
25634 return; // can't calc a hidden column
25637 var cid = this.cm.getColumnId(colIndex);
25638 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
25639 if(this.grid.autoSizeHeaders){
25640 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
25643 var newWidth = this.calcColumnWidth(colIndex);
25644 this.cm.setColumnWidth(colIndex,
25645 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
25646 if(!suppressEvent){
25647 this.grid.fireEvent("columnresize", colIndex, newWidth);
25652 * Autofits all columns to their content and then expands to fit any extra space in the grid
25654 autoSizeColumns : function(){
25655 var cm = this.grid.colModel;
25656 var colCount = cm.getColumnCount();
25657 for(var i = 0; i < colCount; i++){
25658 this.autoSizeColumn(i, true, true);
25660 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
25663 this.updateColumns();
25669 * Autofits all columns to the grid's width proportionate with their current size
25670 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
25672 fitColumns : function(reserveScrollSpace){
25673 var cm = this.grid.colModel;
25674 var colCount = cm.getColumnCount();
25678 for (i = 0; i < colCount; i++){
25679 if(!cm.isHidden(i) && !cm.isFixed(i)){
25680 w = cm.getColumnWidth(i);
25686 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
25687 if(reserveScrollSpace){
25690 var frac = (avail - cm.getTotalWidth())/width;
25691 while (cols.length){
25694 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
25696 this.updateColumns();
25700 onRowSelect : function(rowIndex){
25701 var row = this.getRowComposite(rowIndex);
25702 row.addClass("x-grid-row-selected");
25705 onRowDeselect : function(rowIndex){
25706 var row = this.getRowComposite(rowIndex);
25707 row.removeClass("x-grid-row-selected");
25710 onCellSelect : function(row, col){
25711 var cell = this.getCell(row, col);
25713 Roo.fly(cell).addClass("x-grid-cell-selected");
25717 onCellDeselect : function(row, col){
25718 var cell = this.getCell(row, col);
25720 Roo.fly(cell).removeClass("x-grid-cell-selected");
25724 updateHeaderSortState : function(){
25725 var state = this.ds.getSortState();
25729 this.sortState = state;
25730 var sortColumn = this.cm.findColumnIndex(state.field);
25731 if(sortColumn != -1){
25732 var sortDir = state.direction;
25733 var sc = this.sortClasses;
25734 var hds = this.el.select(this.headerSelector).removeClass(sc);
25735 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
25739 handleHeaderClick : function(g, index){
25740 if(this.headersDisabled){
25743 var dm = g.dataSource, cm = g.colModel;
25744 if(!cm.isSortable(index)){
25748 dm.sort(cm.getDataIndex(index));
25752 destroy : function(){
25754 this.colMenu.removeAll();
25755 Roo.menu.MenuMgr.unregister(this.colMenu);
25756 this.colMenu.getEl().remove();
25757 delete this.colMenu;
25760 this.hmenu.removeAll();
25761 Roo.menu.MenuMgr.unregister(this.hmenu);
25762 this.hmenu.getEl().remove();
25765 if(this.grid.enableColumnMove){
25766 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
25768 for(var dd in dds){
25769 if(!dds[dd].config.isTarget && dds[dd].dragElId){
25770 var elid = dds[dd].dragElId;
25772 Roo.get(elid).remove();
25773 } else if(dds[dd].config.isTarget){
25774 dds[dd].proxyTop.remove();
25775 dds[dd].proxyBottom.remove();
25778 if(Roo.dd.DDM.locationCache[dd]){
25779 delete Roo.dd.DDM.locationCache[dd];
25782 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
25785 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
25786 this.bind(null, null);
25787 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
25790 handleLockChange : function(){
25791 this.refresh(true);
25794 onDenyColumnLock : function(){
25798 onDenyColumnHide : function(){
25802 handleHdMenuClick : function(item){
25803 var index = this.hdCtxIndex;
25804 var cm = this.cm, ds = this.ds;
25807 ds.sort(cm.getDataIndex(index), "ASC");
25810 ds.sort(cm.getDataIndex(index), "DESC");
25813 var lc = cm.getLockedCount();
25814 if(cm.getColumnCount(true) <= lc+1){
25815 this.onDenyColumnLock();
25819 cm.setLocked(index, true, true);
25820 cm.moveColumn(index, lc);
25821 this.grid.fireEvent("columnmove", index, lc);
25823 cm.setLocked(index, true);
25827 var lc = cm.getLockedCount();
25828 if((lc-1) != index){
25829 cm.setLocked(index, false, true);
25830 cm.moveColumn(index, lc-1);
25831 this.grid.fireEvent("columnmove", index, lc-1);
25833 cm.setLocked(index, false);
25837 index = cm.getIndexById(item.id.substr(4));
25839 if(item.checked && cm.getColumnCount(true) <= 1){
25840 this.onDenyColumnHide();
25843 cm.setHidden(index, item.checked);
25849 beforeColMenuShow : function(){
25850 var cm = this.cm, colCount = cm.getColumnCount();
25851 this.colMenu.removeAll();
25852 for(var i = 0; i < colCount; i++){
25853 this.colMenu.add(new Roo.menu.CheckItem({
25854 id: "col-"+cm.getColumnId(i),
25855 text: cm.getColumnHeader(i),
25856 checked: !cm.isHidden(i),
25862 handleHdCtx : function(g, index, e){
25864 var hd = this.getHeaderCell(index);
25865 this.hdCtxIndex = index;
25866 var ms = this.hmenu.items, cm = this.cm;
25867 ms.get("asc").setDisabled(!cm.isSortable(index));
25868 ms.get("desc").setDisabled(!cm.isSortable(index));
25869 if(this.grid.enableColLock !== false){
25870 ms.get("lock").setDisabled(cm.isLocked(index));
25871 ms.get("unlock").setDisabled(!cm.isLocked(index));
25873 this.hmenu.show(hd, "tl-bl");
25876 handleHdOver : function(e){
25877 var hd = this.findHeaderCell(e.getTarget());
25878 if(hd && !this.headersDisabled){
25879 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
25880 this.fly(hd).addClass("x-grid-hd-over");
25885 handleHdOut : function(e){
25886 var hd = this.findHeaderCell(e.getTarget());
25888 this.fly(hd).removeClass("x-grid-hd-over");
25892 handleSplitDblClick : function(e, t){
25893 var i = this.getCellIndex(t);
25894 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
25895 this.autoSizeColumn(i, true);
25900 render : function(){
25903 var colCount = cm.getColumnCount();
25905 if(this.grid.monitorWindowResize === true){
25906 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
25908 var header = this.renderHeaders();
25909 var body = this.templates.body.apply({rows:""});
25910 var html = this.templates.master.apply({
25913 lockedHeader: header[0],
25917 //this.updateColumns();
25919 this.grid.getGridEl().dom.innerHTML = html;
25921 this.initElements();
25923 this.scroller.on("scroll", this.handleScroll, this);
25924 this.lockedBody.on("mousewheel", this.handleWheel, this);
25925 this.mainBody.on("mousewheel", this.handleWheel, this);
25927 this.mainHd.on("mouseover", this.handleHdOver, this);
25928 this.mainHd.on("mouseout", this.handleHdOut, this);
25929 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
25930 {delegate: "."+this.splitClass});
25932 this.lockedHd.on("mouseover", this.handleHdOver, this);
25933 this.lockedHd.on("mouseout", this.handleHdOut, this);
25934 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
25935 {delegate: "."+this.splitClass});
25937 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
25938 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
25941 this.updateSplitters();
25943 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
25944 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
25945 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
25948 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
25949 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
25951 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
25952 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
25954 if(this.grid.enableColLock !== false){
25955 this.hmenu.add('-',
25956 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
25957 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
25960 if(this.grid.enableColumnHide !== false){
25962 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
25963 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
25964 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
25966 this.hmenu.add('-',
25967 {id:"columns", text: this.columnsText, menu: this.colMenu}
25970 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
25972 this.grid.on("headercontextmenu", this.handleHdCtx, this);
25975 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
25976 this.dd = new Roo.grid.GridDragZone(this.grid, {
25977 ddGroup : this.grid.ddGroup || 'GridDD'
25982 for(var i = 0; i < colCount; i++){
25983 if(cm.isHidden(i)){
25984 this.hideColumn(i);
25986 if(cm.config[i].align){
25987 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
25988 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
25992 this.updateHeaderSortState();
25994 this.beforeInitialResize();
25997 // two part rendering gives faster view to the user
25998 this.renderPhase2.defer(1, this);
26001 renderPhase2 : function(){
26002 // render the rows now
26004 if(this.grid.autoSizeColumns){
26005 this.autoSizeColumns();
26009 beforeInitialResize : function(){
26013 onColumnSplitterMoved : function(i, w){
26014 this.userResized = true;
26015 var cm = this.grid.colModel;
26016 cm.setColumnWidth(i, w, true);
26017 var cid = cm.getColumnId(i);
26018 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
26019 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
26020 this.updateSplitters();
26022 this.grid.fireEvent("columnresize", i, w);
26025 syncRowHeights : function(startIndex, endIndex){
26026 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
26027 startIndex = startIndex || 0;
26028 var mrows = this.getBodyTable().rows;
26029 var lrows = this.getLockedTable().rows;
26030 var len = mrows.length-1;
26031 endIndex = Math.min(endIndex || len, len);
26032 for(var i = startIndex; i <= endIndex; i++){
26033 var m = mrows[i], l = lrows[i];
26034 var h = Math.max(m.offsetHeight, l.offsetHeight);
26035 m.style.height = l.style.height = h + "px";
26040 layout : function(initialRender, is2ndPass){
26042 var auto = g.autoHeight;
26043 var scrollOffset = 16;
26044 var c = g.getGridEl(), cm = this.cm,
26045 expandCol = g.autoExpandColumn,
26047 //c.beginMeasure();
26049 if(!c.dom.offsetWidth){ // display:none?
26051 this.lockedWrap.show();
26052 this.mainWrap.show();
26057 var hasLock = this.cm.isLocked(0);
26059 var tbh = this.headerPanel.getHeight();
26060 var bbh = this.footerPanel.getHeight();
26063 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
26064 var newHeight = ch + c.getBorderWidth("tb");
26066 newHeight = Math.min(g.maxHeight, newHeight);
26068 c.setHeight(newHeight);
26072 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
26075 var s = this.scroller;
26077 var csize = c.getSize(true);
26079 this.el.setSize(csize.width, csize.height);
26081 this.headerPanel.setWidth(csize.width);
26082 this.footerPanel.setWidth(csize.width);
26084 var hdHeight = this.mainHd.getHeight();
26085 var vw = csize.width;
26086 var vh = csize.height - (tbh + bbh);
26090 var bt = this.getBodyTable();
26091 var ltWidth = hasLock ?
26092 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
26094 var scrollHeight = bt.offsetHeight;
26095 var scrollWidth = ltWidth + bt.offsetWidth;
26096 var vscroll = false, hscroll = false;
26098 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
26100 var lw = this.lockedWrap, mw = this.mainWrap;
26101 var lb = this.lockedBody, mb = this.mainBody;
26103 setTimeout(function(){
26104 var t = s.dom.offsetTop;
26105 var w = s.dom.clientWidth,
26106 h = s.dom.clientHeight;
26109 lw.setSize(ltWidth, h);
26111 mw.setLeftTop(ltWidth, t);
26112 mw.setSize(w-ltWidth, h);
26114 lb.setHeight(h-hdHeight);
26115 mb.setHeight(h-hdHeight);
26117 if(is2ndPass !== true && !gv.userResized && expandCol){
26118 // high speed resize without full column calculation
26120 var ci = cm.getIndexById(expandCol);
26122 ci = cm.findColumnIndex(expandCol);
26124 ci = Math.max(0, ci); // make sure it's got at least the first col.
26125 var expandId = cm.getColumnId(ci);
26126 var tw = cm.getTotalWidth(false);
26127 var currentWidth = cm.getColumnWidth(ci);
26128 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
26129 if(currentWidth != cw){
26130 cm.setColumnWidth(ci, cw, true);
26131 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
26132 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
26133 gv.updateSplitters();
26134 gv.layout(false, true);
26146 onWindowResize : function(){
26147 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
26153 appendFooter : function(parentEl){
26157 sortAscText : "Sort Ascending",
26158 sortDescText : "Sort Descending",
26159 lockText : "Lock Column",
26160 unlockText : "Unlock Column",
26161 columnsText : "Columns"
26165 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
26166 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
26167 this.proxy.el.addClass('x-grid3-col-dd');
26170 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
26171 handleMouseDown : function(e){
26175 callHandleMouseDown : function(e){
26176 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
26181 * Ext JS Library 1.1.1
26182 * Copyright(c) 2006-2007, Ext JS, LLC.
26184 * Originally Released Under LGPL - original licence link has changed is not relivant.
26187 * <script type="text/javascript">
26191 // This is a support class used internally by the Grid components
26192 Roo.grid.SplitDragZone = function(grid, hd, hd2){
26194 this.view = grid.getView();
26195 this.proxy = this.view.resizeProxy;
26196 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
26197 "gridSplitters" + this.grid.getGridEl().id, {
26198 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
26200 this.setHandleElId(Roo.id(hd));
26201 this.setOuterHandleElId(Roo.id(hd2));
26202 this.scroll = false;
26204 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
26205 fly: Roo.Element.fly,
26207 b4StartDrag : function(x, y){
26208 this.view.headersDisabled = true;
26209 this.proxy.setHeight(this.view.mainWrap.getHeight());
26210 var w = this.cm.getColumnWidth(this.cellIndex);
26211 var minw = Math.max(w-this.grid.minColumnWidth, 0);
26212 this.resetConstraints();
26213 this.setXConstraint(minw, 1000);
26214 this.setYConstraint(0, 0);
26215 this.minX = x - minw;
26216 this.maxX = x + 1000;
26218 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
26222 handleMouseDown : function(e){
26223 ev = Roo.EventObject.setEvent(e);
26224 var t = this.fly(ev.getTarget());
26225 if(t.hasClass("x-grid-split")){
26226 this.cellIndex = this.view.getCellIndex(t.dom);
26227 this.split = t.dom;
26228 this.cm = this.grid.colModel;
26229 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
26230 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
26235 endDrag : function(e){
26236 this.view.headersDisabled = false;
26237 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
26238 var diff = endX - this.startPos;
26239 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
26242 autoOffset : function(){
26243 this.setDelta(0,0);
26247 * Ext JS Library 1.1.1
26248 * Copyright(c) 2006-2007, Ext JS, LLC.
26250 * Originally Released Under LGPL - original licence link has changed is not relivant.
26253 * <script type="text/javascript">
26257 // This is a support class used internally by the Grid components
26258 Roo.grid.GridDragZone = function(grid, config){
26259 this.view = grid.getView();
26260 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
26261 if(this.view.lockedBody){
26262 this.setHandleElId(Roo.id(this.view.mainBody.dom));
26263 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
26265 this.scroll = false;
26267 this.ddel = document.createElement('div');
26268 this.ddel.className = 'x-grid-dd-wrap';
26271 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
26272 ddGroup : "GridDD",
26274 getDragData : function(e){
26275 var t = Roo.lib.Event.getTarget(e);
26276 var rowIndex = this.view.findRowIndex(t);
26277 if(rowIndex !== false){
26278 var sm = this.grid.selModel;
26279 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
26280 // sm.mouseDown(e, t);
26282 if (e.hasModifier()){
26283 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
26285 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
26290 onInitDrag : function(e){
26291 var data = this.dragData;
26292 this.ddel.innerHTML = this.grid.getDragDropText();
26293 this.proxy.update(this.ddel);
26294 // fire start drag?
26297 afterRepair : function(){
26298 this.dragging = false;
26301 getRepairXY : function(e, data){
26305 onEndDrag : function(data, e){
26309 onValidDrop : function(dd, e, id){
26314 beforeInvalidDrop : function(e, id){
26319 * Ext JS Library 1.1.1
26320 * Copyright(c) 2006-2007, Ext JS, LLC.
26322 * Originally Released Under LGPL - original licence link has changed is not relivant.
26325 * <script type="text/javascript">
26330 * @class Roo.grid.ColumnModel
26331 * @extends Roo.util.Observable
26332 * This is the default implementation of a ColumnModel used by the Grid. It defines
26333 * the columns in the grid.
26336 var colModel = new Roo.grid.ColumnModel([
26337 {header: "Ticker", width: 60, sortable: true, locked: true},
26338 {header: "Company Name", width: 150, sortable: true},
26339 {header: "Market Cap.", width: 100, sortable: true},
26340 {header: "$ Sales", width: 100, sortable: true, renderer: money},
26341 {header: "Employees", width: 100, sortable: true, resizable: false}
26346 * The config options listed for this class are options which may appear in each
26347 * individual column definition.
26348 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
26350 * @param {Object} config An Array of column config objects. See this class's
26351 * config objects for details.
26353 Roo.grid.ColumnModel = function(config){
26355 * The config passed into the constructor
26357 this.config = config;
26360 // if no id, create one
26361 // if the column does not have a dataIndex mapping,
26362 // map it to the order it is in the config
26363 for(var i = 0, len = config.length; i < len; i++){
26365 if(typeof c.dataIndex == "undefined"){
26368 if(typeof c.renderer == "string"){
26369 c.renderer = Roo.util.Format[c.renderer];
26371 if(typeof c.id == "undefined"){
26374 if(c.editor && c.editor.xtype){
26375 c.editor = Roo.factory(c.editor, Roo.grid);
26377 if(c.editor && c.editor.isFormField){
26378 c.editor = new Roo.grid.GridEditor(c.editor);
26380 this.lookup[c.id] = c;
26384 * The width of columns which have no width specified (defaults to 100)
26387 this.defaultWidth = 100;
26390 * Default sortable of columns which have no sortable specified (defaults to false)
26393 this.defaultSortable = false;
26397 * @event widthchange
26398 * Fires when the width of a column changes.
26399 * @param {ColumnModel} this
26400 * @param {Number} columnIndex The column index
26401 * @param {Number} newWidth The new width
26403 "widthchange": true,
26405 * @event headerchange
26406 * Fires when the text of a header changes.
26407 * @param {ColumnModel} this
26408 * @param {Number} columnIndex The column index
26409 * @param {Number} newText The new header text
26411 "headerchange": true,
26413 * @event hiddenchange
26414 * Fires when a column is hidden or "unhidden".
26415 * @param {ColumnModel} this
26416 * @param {Number} columnIndex The column index
26417 * @param {Boolean} hidden true if hidden, false otherwise
26419 "hiddenchange": true,
26421 * @event columnmoved
26422 * Fires when a column is moved.
26423 * @param {ColumnModel} this
26424 * @param {Number} oldIndex
26425 * @param {Number} newIndex
26427 "columnmoved" : true,
26429 * @event columlockchange
26430 * Fires when a column's locked state is changed
26431 * @param {ColumnModel} this
26432 * @param {Number} colIndex
26433 * @param {Boolean} locked true if locked
26435 "columnlockchange" : true
26437 Roo.grid.ColumnModel.superclass.constructor.call(this);
26439 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
26441 * @cfg {String} header The header text to display in the Grid view.
26444 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
26445 * {@link Roo.data.Record} definition from which to draw the column's value. If not
26446 * specified, the column's index is used as an index into the Record's data Array.
26449 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
26450 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
26453 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
26454 * Defaults to the value of the {@link #defaultSortable} property.
26455 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
26458 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
26461 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
26464 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
26467 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
26470 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
26471 * given the cell's data value. See {@link #setRenderer}. If not specified, the
26472 * default renderer uses the raw data value.
26475 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
26478 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
26482 * Returns the id of the column at the specified index.
26483 * @param {Number} index The column index
26484 * @return {String} the id
26486 getColumnId : function(index){
26487 return this.config[index].id;
26491 * Returns the column for a specified id.
26492 * @param {String} id The column id
26493 * @return {Object} the column
26495 getColumnById : function(id){
26496 return this.lookup[id];
26500 * Returns the index for a specified column id.
26501 * @param {String} id The column id
26502 * @return {Number} the index, or -1 if not found
26504 getIndexById : function(id){
26505 for(var i = 0, len = this.config.length; i < len; i++){
26506 if(this.config[i].id == id){
26513 * Returns the index for a specified column dataIndex.
26514 * @param {String} dataIndex The column dataIndex
26515 * @return {Number} the index, or -1 if not found
26518 findColumnIndex : function(dataIndex){
26519 for(var i = 0, len = this.config.length; i < len; i++){
26520 if(this.config[i].dataIndex == dataIndex){
26528 moveColumn : function(oldIndex, newIndex){
26529 var c = this.config[oldIndex];
26530 this.config.splice(oldIndex, 1);
26531 this.config.splice(newIndex, 0, c);
26532 this.dataMap = null;
26533 this.fireEvent("columnmoved", this, oldIndex, newIndex);
26536 isLocked : function(colIndex){
26537 return this.config[colIndex].locked === true;
26540 setLocked : function(colIndex, value, suppressEvent){
26541 if(this.isLocked(colIndex) == value){
26544 this.config[colIndex].locked = value;
26545 if(!suppressEvent){
26546 this.fireEvent("columnlockchange", this, colIndex, value);
26550 getTotalLockedWidth : function(){
26551 var totalWidth = 0;
26552 for(var i = 0; i < this.config.length; i++){
26553 if(this.isLocked(i) && !this.isHidden(i)){
26554 this.totalWidth += this.getColumnWidth(i);
26560 getLockedCount : function(){
26561 for(var i = 0, len = this.config.length; i < len; i++){
26562 if(!this.isLocked(i)){
26569 * Returns the number of columns.
26572 getColumnCount : function(visibleOnly){
26573 if(visibleOnly === true){
26575 for(var i = 0, len = this.config.length; i < len; i++){
26576 if(!this.isHidden(i)){
26582 return this.config.length;
26586 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
26587 * @param {Function} fn
26588 * @param {Object} scope (optional)
26589 * @return {Array} result
26591 getColumnsBy : function(fn, scope){
26593 for(var i = 0, len = this.config.length; i < len; i++){
26594 var c = this.config[i];
26595 if(fn.call(scope||this, c, i) === true){
26603 * Returns true if the specified column is sortable.
26604 * @param {Number} col The column index
26605 * @return {Boolean}
26607 isSortable : function(col){
26608 if(typeof this.config[col].sortable == "undefined"){
26609 return this.defaultSortable;
26611 return this.config[col].sortable;
26615 * Returns the rendering (formatting) function defined for the column.
26616 * @param {Number} col The column index.
26617 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
26619 getRenderer : function(col){
26620 if(!this.config[col].renderer){
26621 return Roo.grid.ColumnModel.defaultRenderer;
26623 return this.config[col].renderer;
26627 * Sets the rendering (formatting) function for a column.
26628 * @param {Number} col The column index
26629 * @param {Function} fn The function to use to process the cell's raw data
26630 * to return HTML markup for the grid view. The render function is called with
26631 * the following parameters:<ul>
26632 * <li>Data value.</li>
26633 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
26634 * <li>css A CSS style string to apply to the table cell.</li>
26635 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
26636 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
26637 * <li>Row index</li>
26638 * <li>Column index</li>
26639 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
26641 setRenderer : function(col, fn){
26642 this.config[col].renderer = fn;
26646 * Returns the width for the specified column.
26647 * @param {Number} col The column index
26650 getColumnWidth : function(col){
26651 return this.config[col].width || this.defaultWidth;
26655 * Sets the width for a column.
26656 * @param {Number} col The column index
26657 * @param {Number} width The new width
26659 setColumnWidth : function(col, width, suppressEvent){
26660 this.config[col].width = width;
26661 this.totalWidth = null;
26662 if(!suppressEvent){
26663 this.fireEvent("widthchange", this, col, width);
26668 * Returns the total width of all columns.
26669 * @param {Boolean} includeHidden True to include hidden column widths
26672 getTotalWidth : function(includeHidden){
26673 if(!this.totalWidth){
26674 this.totalWidth = 0;
26675 for(var i = 0, len = this.config.length; i < len; i++){
26676 if(includeHidden || !this.isHidden(i)){
26677 this.totalWidth += this.getColumnWidth(i);
26681 return this.totalWidth;
26685 * Returns the header for the specified column.
26686 * @param {Number} col The column index
26689 getColumnHeader : function(col){
26690 return this.config[col].header;
26694 * Sets the header for a column.
26695 * @param {Number} col The column index
26696 * @param {String} header The new header
26698 setColumnHeader : function(col, header){
26699 this.config[col].header = header;
26700 this.fireEvent("headerchange", this, col, header);
26704 * Returns the tooltip for the specified column.
26705 * @param {Number} col The column index
26708 getColumnTooltip : function(col){
26709 return this.config[col].tooltip;
26712 * Sets the tooltip for a column.
26713 * @param {Number} col The column index
26714 * @param {String} tooltip The new tooltip
26716 setColumnTooltip : function(col, tooltip){
26717 this.config[col].tooltip = tooltip;
26721 * Returns the dataIndex for the specified column.
26722 * @param {Number} col The column index
26725 getDataIndex : function(col){
26726 return this.config[col].dataIndex;
26730 * Sets the dataIndex for a column.
26731 * @param {Number} col The column index
26732 * @param {Number} dataIndex The new dataIndex
26734 setDataIndex : function(col, dataIndex){
26735 this.config[col].dataIndex = dataIndex;
26741 * Returns true if the cell is editable.
26742 * @param {Number} colIndex The column index
26743 * @param {Number} rowIndex The row index
26744 * @return {Boolean}
26746 isCellEditable : function(colIndex, rowIndex){
26747 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
26751 * Returns the editor defined for the cell/column.
26752 * return false or null to disable editing.
26753 * @param {Number} colIndex The column index
26754 * @param {Number} rowIndex The row index
26757 getCellEditor : function(colIndex, rowIndex){
26758 return this.config[colIndex].editor;
26762 * Sets if a column is editable.
26763 * @param {Number} col The column index
26764 * @param {Boolean} editable True if the column is editable
26766 setEditable : function(col, editable){
26767 this.config[col].editable = editable;
26772 * Returns true if the column is hidden.
26773 * @param {Number} colIndex The column index
26774 * @return {Boolean}
26776 isHidden : function(colIndex){
26777 return this.config[colIndex].hidden;
26782 * Returns true if the column width cannot be changed
26784 isFixed : function(colIndex){
26785 return this.config[colIndex].fixed;
26789 * Returns true if the column can be resized
26790 * @return {Boolean}
26792 isResizable : function(colIndex){
26793 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
26796 * Sets if a column is hidden.
26797 * @param {Number} colIndex The column index
26798 * @param {Boolean} hidden True if the column is hidden
26800 setHidden : function(colIndex, hidden){
26801 this.config[colIndex].hidden = hidden;
26802 this.totalWidth = null;
26803 this.fireEvent("hiddenchange", this, colIndex, hidden);
26807 * Sets the editor for a column.
26808 * @param {Number} col The column index
26809 * @param {Object} editor The editor object
26811 setEditor : function(col, editor){
26812 this.config[col].editor = editor;
26816 Roo.grid.ColumnModel.defaultRenderer = function(value){
26817 if(typeof value == "string" && value.length < 1){
26823 // Alias for backwards compatibility
26824 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
26827 * Ext JS Library 1.1.1
26828 * Copyright(c) 2006-2007, Ext JS, LLC.
26830 * Originally Released Under LGPL - original licence link has changed is not relivant.
26833 * <script type="text/javascript">
26837 * @class Roo.grid.AbstractSelectionModel
26838 * @extends Roo.util.Observable
26839 * Abstract base class for grid SelectionModels. It provides the interface that should be
26840 * implemented by descendant classes. This class should not be directly instantiated.
26843 Roo.grid.AbstractSelectionModel = function(){
26844 this.locked = false;
26845 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
26848 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
26849 /** @ignore Called by the grid automatically. Do not call directly. */
26850 init : function(grid){
26856 * Locks the selections.
26859 this.locked = true;
26863 * Unlocks the selections.
26865 unlock : function(){
26866 this.locked = false;
26870 * Returns true if the selections are locked.
26871 * @return {Boolean}
26873 isLocked : function(){
26874 return this.locked;
26878 * Ext JS Library 1.1.1
26879 * Copyright(c) 2006-2007, Ext JS, LLC.
26881 * Originally Released Under LGPL - original licence link has changed is not relivant.
26884 * <script type="text/javascript">
26887 * @extends Roo.grid.AbstractSelectionModel
26888 * @class Roo.grid.RowSelectionModel
26889 * The default SelectionModel used by {@link Roo.grid.Grid}.
26890 * It supports multiple selections and keyboard selection/navigation.
26892 * @param {Object} config
26894 Roo.grid.RowSelectionModel = function(config){
26895 Roo.apply(this, config);
26896 this.selections = new Roo.util.MixedCollection(false, function(o){
26901 this.lastActive = false;
26905 * @event selectionchange
26906 * Fires when the selection changes
26907 * @param {SelectionModel} this
26909 "selectionchange" : true,
26911 * @event afterselectionchange
26912 * Fires after the selection changes (eg. by key press or clicking)
26913 * @param {SelectionModel} this
26915 "afterselectionchange" : true,
26917 * @event beforerowselect
26918 * Fires when a row is selected being selected, return false to cancel.
26919 * @param {SelectionModel} this
26920 * @param {Number} rowIndex The selected index
26921 * @param {Boolean} keepExisting False if other selections will be cleared
26923 "beforerowselect" : true,
26926 * Fires when a row is selected.
26927 * @param {SelectionModel} this
26928 * @param {Number} rowIndex The selected index
26929 * @param {Roo.data.Record} r The record
26931 "rowselect" : true,
26933 * @event rowdeselect
26934 * Fires when a row is deselected.
26935 * @param {SelectionModel} this
26936 * @param {Number} rowIndex The selected index
26938 "rowdeselect" : true
26940 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
26941 this.locked = false;
26944 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
26946 * @cfg {Boolean} singleSelect
26947 * True to allow selection of only one row at a time (defaults to false)
26949 singleSelect : false,
26952 initEvents : function(){
26954 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
26955 this.grid.on("mousedown", this.handleMouseDown, this);
26956 }else{ // allow click to work like normal
26957 this.grid.on("rowclick", this.handleDragableRowClick, this);
26960 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
26961 "up" : function(e){
26963 this.selectPrevious(e.shiftKey);
26964 }else if(this.last !== false && this.lastActive !== false){
26965 var last = this.last;
26966 this.selectRange(this.last, this.lastActive-1);
26967 this.grid.getView().focusRow(this.lastActive);
26968 if(last !== false){
26972 this.selectFirstRow();
26974 this.fireEvent("afterselectionchange", this);
26976 "down" : function(e){
26978 this.selectNext(e.shiftKey);
26979 }else if(this.last !== false && this.lastActive !== false){
26980 var last = this.last;
26981 this.selectRange(this.last, this.lastActive+1);
26982 this.grid.getView().focusRow(this.lastActive);
26983 if(last !== false){
26987 this.selectFirstRow();
26989 this.fireEvent("afterselectionchange", this);
26994 var view = this.grid.view;
26995 view.on("refresh", this.onRefresh, this);
26996 view.on("rowupdated", this.onRowUpdated, this);
26997 view.on("rowremoved", this.onRemove, this);
27001 onRefresh : function(){
27002 var ds = this.grid.dataSource, i, v = this.grid.view;
27003 var s = this.selections;
27004 s.each(function(r){
27005 if((i = ds.indexOfId(r.id)) != -1){
27014 onRemove : function(v, index, r){
27015 this.selections.remove(r);
27019 onRowUpdated : function(v, index, r){
27020 if(this.isSelected(r)){
27021 v.onRowSelect(index);
27027 * @param {Array} records The records to select
27028 * @param {Boolean} keepExisting (optional) True to keep existing selections
27030 selectRecords : function(records, keepExisting){
27032 this.clearSelections();
27034 var ds = this.grid.dataSource;
27035 for(var i = 0, len = records.length; i < len; i++){
27036 this.selectRow(ds.indexOf(records[i]), true);
27041 * Gets the number of selected rows.
27044 getCount : function(){
27045 return this.selections.length;
27049 * Selects the first row in the grid.
27051 selectFirstRow : function(){
27056 * Select the last row.
27057 * @param {Boolean} keepExisting (optional) True to keep existing selections
27059 selectLastRow : function(keepExisting){
27060 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
27064 * Selects the row immediately following the last selected row.
27065 * @param {Boolean} keepExisting (optional) True to keep existing selections
27067 selectNext : function(keepExisting){
27068 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
27069 this.selectRow(this.last+1, keepExisting);
27070 this.grid.getView().focusRow(this.last);
27075 * Selects the row that precedes the last selected row.
27076 * @param {Boolean} keepExisting (optional) True to keep existing selections
27078 selectPrevious : function(keepExisting){
27080 this.selectRow(this.last-1, keepExisting);
27081 this.grid.getView().focusRow(this.last);
27086 * Returns the selected records
27087 * @return {Array} Array of selected records
27089 getSelections : function(){
27090 return [].concat(this.selections.items);
27094 * Returns the first selected record.
27097 getSelected : function(){
27098 return this.selections.itemAt(0);
27103 * Clears all selections.
27105 clearSelections : function(fast){
27106 if(this.locked) return;
27108 var ds = this.grid.dataSource;
27109 var s = this.selections;
27110 s.each(function(r){
27111 this.deselectRow(ds.indexOfId(r.id));
27115 this.selections.clear();
27122 * Selects all rows.
27124 selectAll : function(){
27125 if(this.locked) return;
27126 this.selections.clear();
27127 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
27128 this.selectRow(i, true);
27133 * Returns True if there is a selection.
27134 * @return {Boolean}
27136 hasSelection : function(){
27137 return this.selections.length > 0;
27141 * Returns True if the specified row is selected.
27142 * @param {Number/Record} record The record or index of the record to check
27143 * @return {Boolean}
27145 isSelected : function(index){
27146 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
27147 return (r && this.selections.key(r.id) ? true : false);
27151 * Returns True if the specified record id is selected.
27152 * @param {String} id The id of record to check
27153 * @return {Boolean}
27155 isIdSelected : function(id){
27156 return (this.selections.key(id) ? true : false);
27160 handleMouseDown : function(e, t){
27161 var view = this.grid.getView(), rowIndex;
27162 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
27165 if(e.shiftKey && this.last !== false){
27166 var last = this.last;
27167 this.selectRange(last, rowIndex, e.ctrlKey);
27168 this.last = last; // reset the last
27169 view.focusRow(rowIndex);
27171 var isSelected = this.isSelected(rowIndex);
27172 if(e.button !== 0 && isSelected){
27173 view.focusRow(rowIndex);
27174 }else if(e.ctrlKey && isSelected){
27175 this.deselectRow(rowIndex);
27176 }else if(!isSelected){
27177 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
27178 view.focusRow(rowIndex);
27181 this.fireEvent("afterselectionchange", this);
27184 handleDragableRowClick : function(grid, rowIndex, e)
27186 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
27187 this.selectRow(rowIndex, false);
27188 grid.view.focusRow(rowIndex);
27189 this.fireEvent("afterselectionchange", this);
27194 * Selects multiple rows.
27195 * @param {Array} rows Array of the indexes of the row to select
27196 * @param {Boolean} keepExisting (optional) True to keep existing selections
27198 selectRows : function(rows, keepExisting){
27200 this.clearSelections();
27202 for(var i = 0, len = rows.length; i < len; i++){
27203 this.selectRow(rows[i], true);
27208 * Selects a range of rows. All rows in between startRow and endRow are also selected.
27209 * @param {Number} startRow The index of the first row in the range
27210 * @param {Number} endRow The index of the last row in the range
27211 * @param {Boolean} keepExisting (optional) True to retain existing selections
27213 selectRange : function(startRow, endRow, keepExisting){
27214 if(this.locked) return;
27216 this.clearSelections();
27218 if(startRow <= endRow){
27219 for(var i = startRow; i <= endRow; i++){
27220 this.selectRow(i, true);
27223 for(var i = startRow; i >= endRow; i--){
27224 this.selectRow(i, true);
27230 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
27231 * @param {Number} startRow The index of the first row in the range
27232 * @param {Number} endRow The index of the last row in the range
27234 deselectRange : function(startRow, endRow, preventViewNotify){
27235 if(this.locked) return;
27236 for(var i = startRow; i <= endRow; i++){
27237 this.deselectRow(i, preventViewNotify);
27243 * @param {Number} row The index of the row to select
27244 * @param {Boolean} keepExisting (optional) True to keep existing selections
27246 selectRow : function(index, keepExisting, preventViewNotify){
27247 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
27248 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
27249 if(!keepExisting || this.singleSelect){
27250 this.clearSelections();
27252 var r = this.grid.dataSource.getAt(index);
27253 this.selections.add(r);
27254 this.last = this.lastActive = index;
27255 if(!preventViewNotify){
27256 this.grid.getView().onRowSelect(index);
27258 this.fireEvent("rowselect", this, index, r);
27259 this.fireEvent("selectionchange", this);
27265 * @param {Number} row The index of the row to deselect
27267 deselectRow : function(index, preventViewNotify){
27268 if(this.locked) return;
27269 if(this.last == index){
27272 if(this.lastActive == index){
27273 this.lastActive = false;
27275 var r = this.grid.dataSource.getAt(index);
27276 this.selections.remove(r);
27277 if(!preventViewNotify){
27278 this.grid.getView().onRowDeselect(index);
27280 this.fireEvent("rowdeselect", this, index);
27281 this.fireEvent("selectionchange", this);
27285 restoreLast : function(){
27287 this.last = this._last;
27292 acceptsNav : function(row, col, cm){
27293 return !cm.isHidden(col) && cm.isCellEditable(col, row);
27297 onEditorKey : function(field, e){
27298 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
27303 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
27305 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
27307 }else if(k == e.ENTER && !e.ctrlKey){
27311 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
27313 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
27315 }else if(k == e.ESC){
27319 g.startEditing(newCell[0], newCell[1]);
27324 * Ext JS Library 1.1.1
27325 * Copyright(c) 2006-2007, Ext JS, LLC.
27327 * Originally Released Under LGPL - original licence link has changed is not relivant.
27330 * <script type="text/javascript">
27333 * @class Roo.grid.CellSelectionModel
27334 * @extends Roo.grid.AbstractSelectionModel
27335 * This class provides the basic implementation for cell selection in a grid.
27337 * @param {Object} config The object containing the configuration of this model.
27339 Roo.grid.CellSelectionModel = function(config){
27340 Roo.apply(this, config);
27342 this.selection = null;
27346 * @event beforerowselect
27347 * Fires before a cell is selected.
27348 * @param {SelectionModel} this
27349 * @param {Number} rowIndex The selected row index
27350 * @param {Number} colIndex The selected cell index
27352 "beforecellselect" : true,
27354 * @event cellselect
27355 * Fires when a cell is selected.
27356 * @param {SelectionModel} this
27357 * @param {Number} rowIndex The selected row index
27358 * @param {Number} colIndex The selected cell index
27360 "cellselect" : true,
27362 * @event selectionchange
27363 * Fires when the active selection changes.
27364 * @param {SelectionModel} this
27365 * @param {Object} selection null for no selection or an object (o) with two properties
27367 <li>o.record: the record object for the row the selection is in</li>
27368 <li>o.cell: An array of [rowIndex, columnIndex]</li>
27371 "selectionchange" : true
27373 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
27376 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
27379 initEvents : function(){
27380 this.grid.on("mousedown", this.handleMouseDown, this);
27381 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
27382 var view = this.grid.view;
27383 view.on("refresh", this.onViewChange, this);
27384 view.on("rowupdated", this.onRowUpdated, this);
27385 view.on("beforerowremoved", this.clearSelections, this);
27386 view.on("beforerowsinserted", this.clearSelections, this);
27387 if(this.grid.isEditor){
27388 this.grid.on("beforeedit", this.beforeEdit, this);
27393 beforeEdit : function(e){
27394 this.select(e.row, e.column, false, true, e.record);
27398 onRowUpdated : function(v, index, r){
27399 if(this.selection && this.selection.record == r){
27400 v.onCellSelect(index, this.selection.cell[1]);
27405 onViewChange : function(){
27406 this.clearSelections(true);
27410 * Returns the currently selected cell,.
27411 * @return {Array} The selected cell (row, column) or null if none selected.
27413 getSelectedCell : function(){
27414 return this.selection ? this.selection.cell : null;
27418 * Clears all selections.
27419 * @param {Boolean} true to prevent the gridview from being notified about the change.
27421 clearSelections : function(preventNotify){
27422 var s = this.selection;
27424 if(preventNotify !== true){
27425 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
27427 this.selection = null;
27428 this.fireEvent("selectionchange", this, null);
27433 * Returns true if there is a selection.
27434 * @return {Boolean}
27436 hasSelection : function(){
27437 return this.selection ? true : false;
27441 handleMouseDown : function(e, t){
27442 var v = this.grid.getView();
27443 if(this.isLocked()){
27446 var row = v.findRowIndex(t);
27447 var cell = v.findCellIndex(t);
27448 if(row !== false && cell !== false){
27449 this.select(row, cell);
27455 * @param {Number} rowIndex
27456 * @param {Number} collIndex
27458 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
27459 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
27460 this.clearSelections();
27461 r = r || this.grid.dataSource.getAt(rowIndex);
27464 cell : [rowIndex, colIndex]
27466 if(!preventViewNotify){
27467 var v = this.grid.getView();
27468 v.onCellSelect(rowIndex, colIndex);
27469 if(preventFocus !== true){
27470 v.focusCell(rowIndex, colIndex);
27473 this.fireEvent("cellselect", this, rowIndex, colIndex);
27474 this.fireEvent("selectionchange", this, this.selection);
27479 isSelectable : function(rowIndex, colIndex, cm){
27480 return !cm.isHidden(colIndex);
27484 handleKeyDown : function(e){
27485 if(!e.isNavKeyPress()){
27488 var g = this.grid, s = this.selection;
27491 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
27493 this.select(cell[0], cell[1]);
27498 var walk = function(row, col, step){
27499 return g.walkCells(row, col, step, sm.isSelectable, sm);
27501 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
27507 newCell = walk(r, c-1, -1);
27509 newCell = walk(r, c+1, 1);
27513 newCell = walk(r+1, c, 1);
27516 newCell = walk(r-1, c, -1);
27519 newCell = walk(r, c+1, 1);
27522 newCell = walk(r, c-1, -1);
27525 if(g.isEditor && !g.editing){
27526 g.startEditing(r, c);
27533 this.select(newCell[0], newCell[1]);
27538 acceptsNav : function(row, col, cm){
27539 return !cm.isHidden(col) && cm.isCellEditable(col, row);
27542 onEditorKey : function(field, e){
27543 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
27546 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
27548 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
27551 }else if(k == e.ENTER && !e.ctrlKey){
27554 }else if(k == e.ESC){
27558 g.startEditing(newCell[0], newCell[1]);
27563 * Ext JS Library 1.1.1
27564 * Copyright(c) 2006-2007, Ext JS, LLC.
27566 * Originally Released Under LGPL - original licence link has changed is not relivant.
27569 * <script type="text/javascript">
27573 * @class Roo.grid.EditorGrid
27574 * @extends Roo.grid.Grid
27575 * Class for creating and editable grid.
27576 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
27577 * The container MUST have some type of size defined for the grid to fill. The container will be
27578 * automatically set to position relative if it isn't already.
27579 * @param {Object} dataSource The data model to bind to
27580 * @param {Object} colModel The column model with info about this grid's columns
27582 Roo.grid.EditorGrid = function(container, config){
27583 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
27584 this.getGridEl().addClass("xedit-grid");
27586 if(!this.selModel){
27587 this.selModel = new Roo.grid.CellSelectionModel();
27590 this.activeEditor = null;
27594 * @event beforeedit
27595 * Fires before cell editing is triggered. The edit event object has the following properties <br />
27596 * <ul style="padding:5px;padding-left:16px;">
27597 * <li>grid - This grid</li>
27598 * <li>record - The record being edited</li>
27599 * <li>field - The field name being edited</li>
27600 * <li>value - The value for the field being edited.</li>
27601 * <li>row - The grid row index</li>
27602 * <li>column - The grid column index</li>
27603 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
27605 * @param {Object} e An edit event (see above for description)
27607 "beforeedit" : true,
27610 * Fires after a cell is edited. <br />
27611 * <ul style="padding:5px;padding-left:16px;">
27612 * <li>grid - This grid</li>
27613 * <li>record - The record being edited</li>
27614 * <li>field - The field name being edited</li>
27615 * <li>value - The value being set</li>
27616 * <li>originalValue - The original value for the field, before the edit.</li>
27617 * <li>row - The grid row index</li>
27618 * <li>column - The grid column index</li>
27620 * @param {Object} e An edit event (see above for description)
27622 "afteredit" : true,
27624 * @event validateedit
27625 * Fires after a cell is edited, but before the value is set in the record.
27626 * You can use this to modify the value being set in the field, Return false
27627 * to cancel the change. The edit event object has the following properties <br />
27628 * <ul style="padding:5px;padding-left:16px;">
27629 * <li>editor - This editor</li>
27630 * <li>grid - This grid</li>
27631 * <li>record - The record being edited</li>
27632 * <li>field - The field name being edited</li>
27633 * <li>value - The value being set</li>
27634 * <li>originalValue - The original value for the field, before the edit.</li>
27635 * <li>row - The grid row index</li>
27636 * <li>column - The grid column index</li>
27637 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
27639 * @param {Object} e An edit event (see above for description)
27641 "validateedit" : true
27643 this.on("bodyscroll", this.stopEditing, this);
27644 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
27647 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
27649 * @cfg {Number} clicksToEdit
27650 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
27657 trackMouseOver: false, // causes very odd FF errors
27659 onCellDblClick : function(g, row, col){
27660 this.startEditing(row, col);
27663 onEditComplete : function(ed, value, startValue){
27664 this.editing = false;
27665 this.activeEditor = null;
27666 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
27668 var field = this.colModel.getDataIndex(ed.col);
27673 originalValue: startValue,
27680 if(String(value) !== String(startValue)){
27682 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
27683 r.set(field, e.value);
27684 delete e.cancel; //?? why!!!
27685 this.fireEvent("afteredit", e);
27688 this.fireEvent("afteredit", e); // always fir it!
27690 this.view.focusCell(ed.row, ed.col);
27694 * Starts editing the specified for the specified row/column
27695 * @param {Number} rowIndex
27696 * @param {Number} colIndex
27698 startEditing : function(row, col){
27699 this.stopEditing();
27700 if(this.colModel.isCellEditable(col, row)){
27701 this.view.ensureVisible(row, col, true);
27702 var r = this.dataSource.getAt(row);
27703 var field = this.colModel.getDataIndex(col);
27708 value: r.data[field],
27713 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
27714 this.editing = true;
27715 var ed = this.colModel.getCellEditor(col, row);
27721 ed.render(ed.parentEl || document.body);
27724 (function(){ // complex but required for focus issues in safari, ie and opera
27728 ed.on("complete", this.onEditComplete, this, {single: true});
27729 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
27730 this.activeEditor = ed;
27731 var v = r.data[field];
27732 ed.startEdit(this.view.getCell(row, col), v);
27733 }).defer(50, this);
27739 * Stops any active editing
27741 stopEditing : function(){
27742 if(this.activeEditor){
27743 this.activeEditor.completeEdit();
27745 this.activeEditor = null;
27749 * Ext JS Library 1.1.1
27750 * Copyright(c) 2006-2007, Ext JS, LLC.
27752 * Originally Released Under LGPL - original licence link has changed is not relivant.
27755 * <script type="text/javascript">
27758 // private - not really -- you end up using it !
27759 // This is a support class used internally by the Grid components
27762 * @class Roo.grid.GridEditor
27763 * @extends Roo.Editor
27764 * Class for creating and editable grid elements.
27765 * @param {Object} config any settings (must include field)
27767 Roo.grid.GridEditor = function(field, config){
27768 if (!config && field.field) {
27770 field = Roo.factory(config.field, Roo.form);
27772 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
27773 field.monitorTab = false;
27776 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
27779 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
27782 alignment: "tl-tl",
27785 cls: "x-small-editor x-grid-editor",
27790 * Ext JS Library 1.1.1
27791 * Copyright(c) 2006-2007, Ext JS, LLC.
27793 * Originally Released Under LGPL - original licence link has changed is not relivant.
27796 * <script type="text/javascript">
27801 Roo.grid.PropertyRecord = Roo.data.Record.create([
27802 {name:'name',type:'string'}, 'value'
27806 Roo.grid.PropertyStore = function(grid, source){
27808 this.store = new Roo.data.Store({
27809 recordType : Roo.grid.PropertyRecord
27811 this.store.on('update', this.onUpdate, this);
27813 this.setSource(source);
27815 Roo.grid.PropertyStore.superclass.constructor.call(this);
27820 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
27821 setSource : function(o){
27823 this.store.removeAll();
27826 if(this.isEditableValue(o[k])){
27827 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
27830 this.store.loadRecords({records: data}, {}, true);
27833 onUpdate : function(ds, record, type){
27834 if(type == Roo.data.Record.EDIT){
27835 var v = record.data['value'];
27836 var oldValue = record.modified['value'];
27837 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
27838 this.source[record.id] = v;
27840 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
27847 getProperty : function(row){
27848 return this.store.getAt(row);
27851 isEditableValue: function(val){
27852 if(val && val instanceof Date){
27854 }else if(typeof val == 'object' || typeof val == 'function'){
27860 setValue : function(prop, value){
27861 this.source[prop] = value;
27862 this.store.getById(prop).set('value', value);
27865 getSource : function(){
27866 return this.source;
27870 Roo.grid.PropertyColumnModel = function(grid, store){
27873 g.PropertyColumnModel.superclass.constructor.call(this, [
27874 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
27875 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
27877 this.store = store;
27878 this.bselect = Roo.DomHelper.append(document.body, {
27879 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
27880 {tag: 'option', value: 'true', html: 'true'},
27881 {tag: 'option', value: 'false', html: 'false'}
27884 Roo.id(this.bselect);
27887 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
27888 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
27889 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
27890 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
27891 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
27893 this.renderCellDelegate = this.renderCell.createDelegate(this);
27894 this.renderPropDelegate = this.renderProp.createDelegate(this);
27897 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
27901 valueText : 'Value',
27903 dateFormat : 'm/j/Y',
27906 renderDate : function(dateVal){
27907 return dateVal.dateFormat(this.dateFormat);
27910 renderBool : function(bVal){
27911 return bVal ? 'true' : 'false';
27914 isCellEditable : function(colIndex, rowIndex){
27915 return colIndex == 1;
27918 getRenderer : function(col){
27920 this.renderCellDelegate : this.renderPropDelegate;
27923 renderProp : function(v){
27924 return this.getPropertyName(v);
27927 renderCell : function(val){
27929 if(val instanceof Date){
27930 rv = this.renderDate(val);
27931 }else if(typeof val == 'boolean'){
27932 rv = this.renderBool(val);
27934 return Roo.util.Format.htmlEncode(rv);
27937 getPropertyName : function(name){
27938 var pn = this.grid.propertyNames;
27939 return pn && pn[name] ? pn[name] : name;
27942 getCellEditor : function(colIndex, rowIndex){
27943 var p = this.store.getProperty(rowIndex);
27944 var n = p.data['name'], val = p.data['value'];
27946 if(typeof(this.grid.customEditors[n]) == 'string'){
27947 return this.editors[this.grid.customEditors[n]];
27949 if(typeof(this.grid.customEditors[n]) != 'undefined'){
27950 return this.grid.customEditors[n];
27952 if(val instanceof Date){
27953 return this.editors['date'];
27954 }else if(typeof val == 'number'){
27955 return this.editors['number'];
27956 }else if(typeof val == 'boolean'){
27957 return this.editors['boolean'];
27959 return this.editors['string'];
27965 * @class Roo.grid.PropertyGrid
27966 * @extends Roo.grid.EditorGrid
27967 * This class represents the interface of a component based property grid control.
27968 * <br><br>Usage:<pre><code>
27969 var grid = new Roo.grid.PropertyGrid("my-container-id", {
27977 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
27978 * The container MUST have some type of size defined for the grid to fill. The container will be
27979 * automatically set to position relative if it isn't already.
27980 * @param {Object} config A config object that sets properties on this grid.
27982 Roo.grid.PropertyGrid = function(container, config){
27983 config = config || {};
27984 var store = new Roo.grid.PropertyStore(this);
27985 this.store = store;
27986 var cm = new Roo.grid.PropertyColumnModel(this, store);
27987 store.store.sort('name', 'ASC');
27988 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
27991 enableColLock:false,
27992 enableColumnMove:false,
27994 trackMouseOver: false,
27997 this.getGridEl().addClass('x-props-grid');
27998 this.lastEditRow = null;
27999 this.on('columnresize', this.onColumnResize, this);
28002 * @event beforepropertychange
28003 * Fires before a property changes (return false to stop?)
28004 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
28005 * @param {String} id Record Id
28006 * @param {String} newval New Value
28007 * @param {String} oldval Old Value
28009 "beforepropertychange": true,
28011 * @event propertychange
28012 * Fires after a property changes
28013 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
28014 * @param {String} id Record Id
28015 * @param {String} newval New Value
28016 * @param {String} oldval Old Value
28018 "propertychange": true
28020 this.customEditors = this.customEditors || {};
28022 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
28025 * @cfg {Object} customEditors map of colnames=> custom editors.
28026 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
28027 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
28028 * false disables editing of the field.
28032 * @cfg {Object} propertyNames map of property Names to their displayed value
28035 render : function(){
28036 Roo.grid.PropertyGrid.superclass.render.call(this);
28037 this.autoSize.defer(100, this);
28040 autoSize : function(){
28041 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
28043 this.view.fitColumns();
28047 onColumnResize : function(){
28048 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
28052 * Sets the data for the Grid
28053 * accepts a Key => Value object of all the elements avaiable.
28054 * @param {Object} data to appear in grid.
28056 setSource : function(source){
28057 this.store.setSource(source);
28061 * Gets all the data from the grid.
28062 * @return {Object} data data stored in grid
28064 getSource : function(){
28065 return this.store.getSource();
28069 * Ext JS Library 1.1.1
28070 * Copyright(c) 2006-2007, Ext JS, LLC.
28072 * Originally Released Under LGPL - original licence link has changed is not relivant.
28075 * <script type="text/javascript">
28079 * @class Roo.LoadMask
28080 * A simple utility class for generically masking elements while loading data. If the element being masked has
28081 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
28082 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
28083 * element's UpdateManager load indicator and will be destroyed after the initial load.
28085 * Create a new LoadMask
28086 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
28087 * @param {Object} config The config object
28089 Roo.LoadMask = function(el, config){
28090 this.el = Roo.get(el);
28091 Roo.apply(this, config);
28093 this.store.on('beforeload', this.onBeforeLoad, this);
28094 this.store.on('load', this.onLoad, this);
28095 this.store.on('loadexception', this.onLoad, this);
28096 this.removeMask = false;
28098 var um = this.el.getUpdateManager();
28099 um.showLoadIndicator = false; // disable the default indicator
28100 um.on('beforeupdate', this.onBeforeLoad, this);
28101 um.on('update', this.onLoad, this);
28102 um.on('failure', this.onLoad, this);
28103 this.removeMask = true;
28107 Roo.LoadMask.prototype = {
28109 * @cfg {Boolean} removeMask
28110 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
28111 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
28114 * @cfg {String} msg
28115 * The text to display in a centered loading message box (defaults to 'Loading...')
28117 msg : 'Loading...',
28119 * @cfg {String} msgCls
28120 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
28122 msgCls : 'x-mask-loading',
28125 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
28131 * Disables the mask to prevent it from being displayed
28133 disable : function(){
28134 this.disabled = true;
28138 * Enables the mask so that it can be displayed
28140 enable : function(){
28141 this.disabled = false;
28145 onLoad : function(){
28146 this.el.unmask(this.removeMask);
28150 onBeforeLoad : function(){
28151 if(!this.disabled){
28152 this.el.mask(this.msg, this.msgCls);
28157 destroy : function(){
28159 this.store.un('beforeload', this.onBeforeLoad, this);
28160 this.store.un('load', this.onLoad, this);
28161 this.store.un('loadexception', this.onLoad, this);
28163 var um = this.el.getUpdateManager();
28164 um.un('beforeupdate', this.onBeforeLoad, this);
28165 um.un('update', this.onLoad, this);
28166 um.un('failure', this.onLoad, this);
28171 * Ext JS Library 1.1.1
28172 * Copyright(c) 2006-2007, Ext JS, LLC.
28174 * Originally Released Under LGPL - original licence link has changed is not relivant.
28177 * <script type="text/javascript">
28179 Roo.XTemplate = function(){
28180 Roo.XTemplate.superclass.constructor.apply(this, arguments);
28183 s = ['<tpl>', s, '</tpl>'].join('');
28185 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
28187 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
28188 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
28189 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
28193 while(m = s.match(re)){
28194 var m2 = m[0].match(nameRe);
28195 var m3 = m[0].match(ifRe);
28196 var m4 = m[0].match(execRe);
28197 var exp = null, fn = null, exec = null;
28198 var name = m2 && m2[1] ? m2[1] : '';
28200 exp = m3 && m3[1] ? m3[1] : null;
28202 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
28206 exp = m4 && m4[1] ? m4[1] : null;
28208 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
28213 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
28214 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
28215 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
28225 s = s.replace(m[0], '{xtpl'+ id + '}');
28228 for(var i = tpls.length-1; i >= 0; --i){
28229 this.compileTpl(tpls[i]);
28231 this.master = tpls[tpls.length-1];
28234 Roo.extend(Roo.XTemplate, Roo.Template, {
28236 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
28238 applySubTemplate : function(id, values, parent){
28239 var t = this.tpls[id];
28240 if(t.test && !t.test.call(this, values, parent)){
28243 if(t.exec && t.exec.call(this, values, parent)){
28246 var vs = t.target ? t.target.call(this, values, parent) : values;
28247 parent = t.target ? values : parent;
28248 if(t.target && vs instanceof Array){
28250 for(var i = 0, len = vs.length; i < len; i++){
28251 buf[buf.length] = t.compiled.call(this, vs[i], parent);
28253 return buf.join('');
28255 return t.compiled.call(this, vs, parent);
28258 compileTpl : function(tpl){
28259 var fm = Roo.util.Format;
28260 var useF = this.disableFormats !== true;
28261 var sep = Roo.isGecko ? "+" : ",";
28262 var fn = function(m, name, format, args){
28263 if(name.substr(0, 4) == 'xtpl'){
28264 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
28267 if(name.indexOf('.') != -1){
28270 v = "values['" + name + "']";
28272 if(format && useF){
28273 args = args ? ',' + args : "";
28274 if(format.substr(0, 5) != "this."){
28275 format = "fm." + format + '(';
28277 format = 'this.call("'+ format.substr(5) + '", ';
28281 args= ''; format = "("+v+" === undefined ? '' : ";
28283 return "'"+ sep + format + v + args + ")"+sep+"'";
28286 // branched to use + in gecko and [].join() in others
28288 body = "tpl.compiled = function(values, parent){ return '" +
28289 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
28292 body = ["tpl.compiled = function(values, parent){ return ['"];
28293 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
28294 body.push("'].join('');};");
28295 body = body.join('');
28297 /** eval:var:zzzzzzz */
28302 applyTemplate : function(values){
28303 return this.master.compiled.call(this, values, {});
28307 apply : function(){
28308 return this.applyTemplate.apply(this, arguments);
28311 compile : function(){return this;}
28314 Roo.XTemplate.from = function(el){
28315 el = Roo.getDom(el);
28316 return new Roo.XTemplate(el.value || el.innerHTML);
28318 * Original code for Roojs - LGPL
28319 * <script type="text/javascript">
28323 * @class Roo.XComponent
28324 * A delayed Element creator...
28326 * Mypart.xyx = new Roo.XComponent({
28328 parent : 'Mypart.xyz', // empty == document.element.!!
28332 disabled : function() {}
28334 tree : function() { // return an tree of xtype declared components
28338 xtype : 'NestedLayoutPanel',
28345 * @extends Roo.util.Observable
28347 Roo.XComponent = function(cfg) {
28348 Roo.apply(this, cfg);
28352 * Fires when this the componnt is built
28353 * @param {Roo.XComponent} c the component
28357 * @event buildcomplete
28358 * Fires on the top level element when all elements have been built
28359 * @param {Roo.XComponent} c the top level component.
28361 'buildcomplete' : true,
28365 Roo.XComponent.register(this);
28366 this.modules = false;
28367 this.el = false; // where the layout goes..
28371 Roo.extend(Roo.XComponent, Roo.util.Observable, {
28374 * The created element (with Roo.factory())
28375 * @type {Roo.Layout}
28381 * for BC - use el in new code
28382 * @type {Roo.Layout}
28388 * for BC - use el in new code
28389 * @type {Roo.Layout}
28394 * @cfg {Function|boolean} disabled
28395 * If this module is disabled by some rule, return true from the funtion
28400 * @cfg {String} parent
28401 * Name of parent element which it get xtype added to..
28406 * @cfg {String} order
28407 * Used to set the order in which elements are created (usefull for multiple tabs)
28412 * @cfg {String} name
28413 * String to display while loading.
28417 * @cfg {Array} items
28418 * A single item array - the first element is the root of the tree..
28419 * It's done this way to stay compatible with the Xtype system...
28427 Roo.apply(Roo.XComponent, {
28430 * @property buildCompleted
28431 * True when the builder has completed building the interface.
28434 buildCompleted : false,
28437 * @property topModule
28438 * the upper most module - uses document.element as it's constructor.
28445 * @property modules
28446 * array of modules to be created by registration system.
28447 * @type Roo.XComponent
28454 * Register components to be built later.
28455 * @param {Object} details about module
28457 * This solves the following issues
28458 * - Building is not done on page load, but after an authentication process has occured.
28459 * - Interface elements are registered on page load
28460 * - Parent Interface elements may not be loaded before child, so this handles that..
28467 module : 'Pman.Tab.projectMgr',
28469 parent : 'Pman.layout',
28470 disabled : false, // or use a function..
28474 register : function(obj) {
28475 this.modules.push(obj);
28479 * convert a string to an object..
28483 toObject : function(str)
28485 if (!str || typeof(str) == 'object') {
28488 var ar = str.split('.');
28492 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
28494 throw "Module not found : " + str;
28496 Roo.each(ar, function(e) {
28497 if (typeof(o[e]) == 'undefined') {
28498 throw "Module not found : " + str;
28508 * move modules into their correct place in the tree..
28511 preBuild : function ()
28514 Roo.each(this.modules , function (obj)
28516 obj.parent = this.toObject(obj.parent);
28519 this.topModule = obj;
28523 if (!obj.parent.modules) {
28524 obj.parent.modules = new Roo.util.MixedCollection(false,
28525 function(o) { return o.order + '' }
28529 obj.parent.modules.add(obj);
28534 * make a list of modules to build.
28535 * @return {Array} list of modules.
28538 buildOrder : function()
28541 var cmp = function(a,b) {
28542 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
28545 if (!this.topModule || !this.topModule.modules) {
28546 throw "No top level modules to build";
28549 // make a flat list in order of modules to build.
28550 var mods = [ this.topModule ];
28553 // add modules to their parents..
28554 var addMod = function(m) {
28555 // console.log(m.modKey);
28559 m.modules.keySort('ASC', cmp );
28560 m.modules.each(addMod);
28562 // not sure if this is used any more..
28564 m.finalize.name = m.name + " (clean up) ";
28565 mods.push(m.finalize);
28569 this.topModule.modules.keySort('ASC', cmp );
28570 this.topModule.modules.each(addMod);
28575 * Build the registered modules.
28576 * @param {Object} parent element.
28577 * @param {Function} optional method to call after module has been added.
28585 var mods = this.buildOrder();
28587 //this.allmods = mods;
28588 //console.log(mods);
28590 if (!mods.length) { // should not happen
28591 throw "NO modules!!!";
28596 // flash it up as modal - so we store the mask!?
28597 Roo.MessageBox.show({ title: 'loading' });
28598 Roo.MessageBox.show({
28599 title: "Please wait...",
28600 msg: "Building Interface...",
28607 var total = mods.length;
28610 var progressRun = function() {
28611 if (!mods.length) {
28612 console.log('hide?');
28613 Roo.MessageBox.hide();
28614 _this.topModule.fireEvent('buildcomplete', _this.topModule);
28618 var m = mods.shift();
28620 if (typeof(m) == 'function') { // not sure if this is supported any more..
28622 return progressRun.defer(10, _this);
28625 Roo.MessageBox.updateProgress(
28626 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
28628 (m.name ? (' - ' + m.name) : '')
28633 var disabled = (typeof(m.disabled) == 'function') ?
28634 m.disabled.call(m.module.disabled) : m.disabled;
28638 return progressRun(); // we do not update the display!
28642 // it's a top level one..
28643 var layoutbase = new Ext.BorderLayout(document.body, {
28649 tabPosition: 'top',
28650 //resizeTabs: true,
28651 alwaysShowTabs: true,
28655 var tree = m.tree();
28656 tree.region = 'center';
28657 m.el = layoutbase.addxtype(tree);
28659 m.layout = m.panel.layout;
28660 return progressRun.defer(10, _this);
28663 var tree = m.tree();
28664 tree.region = tree.region || m.region;
28665 m.el = m.parent.el.addxtype(tree);
28666 m.fireEvent('built', m);
28668 m.layout = m.panel.layout;
28669 progressRun.defer(10, _this);
28672 progressRun.defer(1, _this);