roojs-ui-debug.js
[roojs1] / roojs-ui-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13 /**
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}).
16  * @singleton
17  */
18 Roo.ComponentMgr = function(){
19     var all = new Roo.util.MixedCollection();
20
21     return {
22         /**
23          * Registers a component.
24          * @param {Roo.Component} c The component
25          */
26         register : function(c){
27             all.add(c);
28         },
29
30         /**
31          * Unregisters a component.
32          * @param {Roo.Component} c The component
33          */
34         unregister : function(c){
35             all.remove(c);
36         },
37
38         /**
39          * Returns a component by id
40          * @param {String} id The component id
41          */
42         get : function(id){
43             return all.get(id);
44         },
45
46         /**
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
51          */
52         onAvailable : function(id, fn, scope){
53             all.on("add", function(index, o){
54                 if(o.id == id){
55                     fn.call(scope || o, o);
56                     all.un("add", fn, scope);
57                 }
58             });
59         }
60     };
61 }();/*
62  * Based on:
63  * Ext JS Library 1.1.1
64  * Copyright(c) 2006-2007, Ext JS, LLC.
65  *
66  * Originally Released Under LGPL - original licence link has changed is not relivant.
67  *
68  * Fork - LGPL
69  * <script type="text/javascript">
70  */
71  
72 /**
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.
80  * @constructor
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.
84  */
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};
89     }
90     this.initialConfig = config;
91
92     Roo.apply(this, config);
93     this.addEvents({
94         /**
95          * @event disable
96          * Fires after the component is disabled.
97              * @param {Roo.Component} this
98              */
99         disable : true,
100         /**
101          * @event enable
102          * Fires after the component is enabled.
103              * @param {Roo.Component} this
104              */
105         enable : true,
106         /**
107          * @event beforeshow
108          * Fires before the component is shown.  Return false to stop the show.
109              * @param {Roo.Component} this
110              */
111         beforeshow : true,
112         /**
113          * @event show
114          * Fires after the component is shown.
115              * @param {Roo.Component} this
116              */
117         show : true,
118         /**
119          * @event beforehide
120          * Fires before the component is hidden. Return false to stop the hide.
121              * @param {Roo.Component} this
122              */
123         beforehide : true,
124         /**
125          * @event hide
126          * Fires after the component is hidden.
127              * @param {Roo.Component} this
128              */
129         hide : true,
130         /**
131          * @event beforerender
132          * Fires before the component is rendered. Return false to stop the render.
133              * @param {Roo.Component} this
134              */
135         beforerender : true,
136         /**
137          * @event render
138          * Fires after the component is rendered.
139              * @param {Roo.Component} this
140              */
141         render : true,
142         /**
143          * @event beforedestroy
144          * Fires before the component is destroyed. Return false to stop the destroy.
145              * @param {Roo.Component} this
146              */
147         beforedestroy : true,
148         /**
149          * @event destroy
150          * Fires after the component is destroyed.
151              * @param {Roo.Component} this
152              */
153         destroy : true
154     });
155     if(!this.id){
156         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
157     }
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;
164     }
165 };
166
167 // private
168 Roo.Component.AUTO_ID = 1000;
169
170 Roo.extend(Roo.Component, Roo.util.Observable, {
171     /**
172      * @property {Boolean} hidden
173      * true if this component is hidden. Read-only.
174      */
175     hidden : false,
176     /**
177      * true if this component is disabled. Read-only.
178      */
179     disabled : false,
180     /**
181      * true if this component has been rendered. Read-only.
182      */
183     rendered : false,
184     
185     /** @cfg {String} disableClass
186      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
187      */
188     disabledClass : "x-item-disabled",
189         /** @cfg {Boolean} allowDomMove
190          * Whether the component can move the Dom node when rendering (defaults to true).
191          */
192     allowDomMove : 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".
197      */
198     hideMode: 'display',
199
200     // private
201     ctype : "Roo.Component",
202
203     /** @cfg {String} actionMode 
204      * which property holds the element that used for  hide() / show() / disable() / enable()
205      * default is 'el' 
206      */
207     actionMode : "el",
208
209     // private
210     getActionEl : function(){
211         return this[this.actionMode];
212     },
213
214     initComponent : Roo.emptyFn,
215     /**
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.
218      */
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;
225             }
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];
231                 }else{
232                     position = Roo.getDom(position);
233                 }
234             }
235             this.onRender(this.container, position || null);
236             if(this.cls){
237                 this.el.addClass(this.cls);
238                 delete this.cls;
239             }
240             if(this.style){
241                 this.el.applyStyles(this.style);
242                 delete this.style;
243             }
244             this.fireEvent("render", this);
245             this.afterRender(this.container);
246             if(this.hidden){
247                 this.hide();
248             }
249             if(this.disabled){
250                 this.disable();
251             }
252         }
253         return this;
254     },
255
256     // private
257     // default function is not really useful
258     onRender : function(ct, position){
259         if(this.el){
260             this.el = Roo.get(this.el);
261             if(this.allowDomMove !== false){
262                 ct.dom.insertBefore(this.el.dom, position);
263             }
264         }
265     },
266
267     // private
268     getAutoCreate : function(){
269         var cfg = typeof this.autoCreate == "object" ?
270                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
271         if(this.id && !cfg.id){
272             cfg.id = this.id;
273         }
274         return cfg;
275     },
276
277     // private
278     afterRender : Roo.emptyFn,
279
280     /**
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}.
283      */
284     destroy : function(){
285         if(this.fireEvent("beforedestroy", this) !== false){
286             this.purgeListeners();
287             this.beforeDestroy();
288             if(this.rendered){
289                 this.el.removeAllListeners();
290                 this.el.remove();
291                 if(this.actionMode == "container"){
292                     this.container.remove();
293                 }
294             }
295             this.onDestroy();
296             Roo.ComponentMgr.unregister(this);
297             this.fireEvent("destroy", this);
298         }
299     },
300
301         // private
302     beforeDestroy : function(){
303
304     },
305
306         // private
307         onDestroy : function(){
308
309     },
310
311     /**
312      * Returns the underlying {@link Roo.Element}.
313      * @return {Roo.Element} The element
314      */
315     getEl : function(){
316         return this.el;
317     },
318
319     /**
320      * Returns the id of this component.
321      * @return {String}
322      */
323     getId : function(){
324         return this.id;
325     },
326
327     /**
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
331      */
332     focus : function(selectText){
333         if(this.rendered){
334             this.el.focus();
335             if(selectText === true){
336                 this.el.dom.select();
337             }
338         }
339         return this;
340     },
341
342     // private
343     blur : function(){
344         if(this.rendered){
345             this.el.blur();
346         }
347         return this;
348     },
349
350     /**
351      * Disable this component.
352      * @return {Roo.Component} this
353      */
354     disable : function(){
355         if(this.rendered){
356             this.onDisable();
357         }
358         this.disabled = true;
359         this.fireEvent("disable", this);
360         return this;
361     },
362
363         // private
364     onDisable : function(){
365         this.getActionEl().addClass(this.disabledClass);
366         this.el.dom.disabled = true;
367     },
368
369     /**
370      * Enable this component.
371      * @return {Roo.Component} this
372      */
373     enable : function(){
374         if(this.rendered){
375             this.onEnable();
376         }
377         this.disabled = false;
378         this.fireEvent("enable", this);
379         return this;
380     },
381
382         // private
383     onEnable : function(){
384         this.getActionEl().removeClass(this.disabledClass);
385         this.el.dom.disabled = false;
386     },
387
388     /**
389      * Convenience function for setting disabled/enabled by boolean.
390      * @param {Boolean} disabled
391      */
392     setDisabled : function(disabled){
393         this[disabled ? "disable" : "enable"]();
394     },
395
396     /**
397      * Show this component.
398      * @return {Roo.Component} this
399      */
400     show: function(){
401         if(this.fireEvent("beforeshow", this) !== false){
402             this.hidden = false;
403             if(this.rendered){
404                 this.onShow();
405             }
406             this.fireEvent("show", this);
407         }
408         return this;
409     },
410
411     // private
412     onShow : function(){
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');
418         }else{
419             ae.dom.style.display = "";
420         }
421     },
422
423     /**
424      * Hide this component.
425      * @return {Roo.Component} this
426      */
427     hide: function(){
428         if(this.fireEvent("beforehide", this) !== false){
429             this.hidden = true;
430             if(this.rendered){
431                 this.onHide();
432             }
433             this.fireEvent("hide", this);
434         }
435         return this;
436     },
437
438     // private
439     onHide : function(){
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');
445         }else{
446             ae.dom.style.display = "none";
447         }
448     },
449
450     /**
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
454      */
455     setVisible: function(visible){
456         if(visible) {
457             this.show();
458         }else{
459             this.hide();
460         }
461         return this;
462     },
463
464     /**
465      * Returns true if this component is visible.
466      */
467     isVisible : function(){
468         return this.getActionEl().isVisible();
469     },
470
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);
477     }
478 });/*
479  * Based on:
480  * Ext JS Library 1.1.1
481  * Copyright(c) 2006-2007, Ext JS, LLC.
482  *
483  * Originally Released Under LGPL - original licence link has changed is not relivant.
484  *
485  * Fork - LGPL
486  * <script type="text/javascript">
487  */
488  (function(){ 
489 /**
490  * @class Roo.Layer
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)
502  * @constructor
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.
505  */
506
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;
511     if(existingEl){
512         this.dom = Roo.getDom(existingEl);
513     }
514     if(!this.dom){
515         var o = config.dh || {tag: "div", cls: "x-layer"};
516         this.dom = dh.append(pel, o);
517     }
518     if(config.cls){
519         this.addClass(config.cls);
520     }
521     this.constrain = config.constrain !== false;
522     this.visibilityMode = Roo.Element.VISIBILITY;
523     if(config.id){
524         this.id = this.dom.id = config.id;
525     }else{
526         this.id = Roo.id(this.dom);
527     }
528     this.zindex = config.zindex || this.getZIndex();
529     this.position("absolute", this.zindex);
530     if(config.shadow){
531         this.shadowOffset = config.shadowOffset || 4;
532         this.shadow = new Roo.Shadow({
533             offset : this.shadowOffset,
534             mode : config.shadow
535         });
536     }else{
537         this.shadowOffset = 0;
538     }
539     this.useShim = config.shim !== false && Roo.useShims;
540     this.useDisplay = config.useDisplay;
541     this.hide();
542 };
543
544 var supr = Roo.Element.prototype;
545
546 // shims are shared among layer to keep from having 100 iframes
547 var shims = [];
548
549 Roo.extend(Roo.Layer, Roo.Element, {
550
551     getZIndex : function(){
552         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
553     },
554
555     getShim : function(){
556         if(!this.useShim){
557             return null;
558         }
559         if(this.shim){
560             return this.shim;
561         }
562         var shim = shims.shift();
563         if(!shim){
564             shim = this.createShim();
565             shim.enableDisplayMode('block');
566             shim.dom.style.display = 'none';
567             shim.dom.style.visibility = 'visible';
568         }
569         var pn = this.dom.parentNode;
570         if(shim.dom.parentNode != pn){
571             pn.insertBefore(shim.dom, this.dom);
572         }
573         shim.setStyle('z-index', this.getZIndex()-2);
574         this.shim = shim;
575         return shim;
576     },
577
578     hideShim : function(){
579         if(this.shim){
580             this.shim.setDisplayed(false);
581             shims.push(this.shim);
582             delete this.shim;
583         }
584     },
585
586     disableShadow : function(){
587         if(this.shadow){
588             this.shadowDisabled = true;
589             this.shadow.hide();
590             this.lastShadowOffset = this.shadowOffset;
591             this.shadowOffset = 0;
592         }
593     },
594
595     enableShadow : function(show){
596         if(this.shadow){
597             this.shadowDisabled = false;
598             this.shadowOffset = this.lastShadowOffset;
599             delete this.lastShadowOffset;
600             if(show){
601                 this.sync(true);
602             }
603         }
604     },
605
606     // private
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();
613
614             var w = this.getWidth(),
615                 h = this.getHeight();
616
617             var l = this.getLeft(true),
618                 t = this.getTop(true);
619
620             if(sw && !this.shadowDisabled){
621                 if(doShow && !sw.isVisible()){
622                     sw.show(this);
623                 }else{
624                     sw.realign(l, t, w, h);
625                 }
626                 if(sh){
627                     if(doShow){
628                        sh.show();
629                     }
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";
636                 }
637             }else if(sh){
638                 if(doShow){
639                    sh.show();
640                 }
641                 sh.setSize(w, h);
642                 sh.setLeftTop(l, t);
643             }
644             
645         }
646     },
647
648     // private
649     destroy : function(){
650         this.hideShim();
651         if(this.shadow){
652             this.shadow.hide();
653         }
654         this.removeAllListeners();
655         var pn = this.dom.parentNode;
656         if(pn){
657             pn.removeChild(this.dom);
658         }
659         Roo.Element.uncache(this.id);
660     },
661
662     remove : function(){
663         this.destroy();
664     },
665
666     // private
667     beginUpdate : function(){
668         this.updating = true;
669     },
670
671     // private
672     endUpdate : function(){
673         this.updating = false;
674         this.sync(true);
675     },
676
677     // private
678     hideUnders : function(negOffset){
679         if(this.shadow){
680             this.shadow.hide();
681         }
682         this.hideShim();
683     },
684
685     // private
686     constrainXY : function(){
687         if(this.constrain){
688             var vw = Roo.lib.Dom.getViewWidth(),
689                 vh = Roo.lib.Dom.getViewHeight();
690             var s = Roo.get(document).getScroll();
691
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
696             var moved = false;
697             // first validate right/bottom
698             if((x + w) > vw+s.left){
699                 x = vw - w - this.shadowOffset;
700                 moved = true;
701             }
702             if((y + h) > vh+s.top){
703                 y = vh - h - this.shadowOffset;
704                 moved = true;
705             }
706             // then make sure top/left isn't negative
707             if(x < s.left){
708                 x = s.left;
709                 moved = true;
710             }
711             if(y < s.top){
712                 y = s.top;
713                 moved = true;
714             }
715             if(moved){
716                 if(this.avoidY){
717                     var ay = this.avoidY;
718                     if(y <= ay && (y+h) >= ay){
719                         y = ay-h-5;   
720                     }
721                 }
722                 xy = [x, y];
723                 this.storeXY(xy);
724                 supr.setXY.call(this, xy);
725                 this.sync();
726             }
727         }
728     },
729
730     isVisible : function(){
731         return this.visible;    
732     },
733
734     // private
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]);
743         }
744     },
745
746     // private
747     hideAction : function(){
748         this.visible = false;
749         if(this.useDisplay === true){
750             this.setDisplayed(false);
751         }else{
752             this.setLeftTop(-10000,-10000);
753         }
754     },
755
756     // overridden Element method
757     setVisible : function(v, a, d, c, e){
758         if(v){
759             this.showAction();
760         }
761         if(a && v){
762             var cb = function(){
763                 this.sync(true);
764                 if(c){
765                     c();
766                 }
767             }.createDelegate(this);
768             supr.setVisible.call(this, true, true, d, cb, e);
769         }else{
770             if(!v){
771                 this.hideUnders(true);
772             }
773             var cb = c;
774             if(a){
775                 cb = function(){
776                     this.hideAction();
777                     if(c){
778                         c();
779                     }
780                 }.createDelegate(this);
781             }
782             supr.setVisible.call(this, v, a, d, cb, e);
783             if(v){
784                 this.sync(true);
785             }else if(!a){
786                 this.hideAction();
787             }
788         }
789     },
790
791     storeXY : function(xy){
792         delete this.lastLT;
793         this.lastXY = xy;
794     },
795
796     storeLeftTop : function(left, top){
797         delete this.lastXY;
798         this.lastLT = [left, top];
799     },
800
801     // private
802     beforeFx : function(){
803         this.beforeAction();
804         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
805     },
806
807     // private
808     afterFx : function(){
809         Roo.Layer.superclass.afterFx.apply(this, arguments);
810         this.sync(this.isVisible());
811     },
812
813     // private
814     beforeAction : function(){
815         if(!this.updating && this.shadow){
816             this.shadow.hide();
817         }
818     },
819
820     // overridden Element method
821     setLeft : function(left){
822         this.storeLeftTop(left, this.getTop(true));
823         supr.setLeft.apply(this, arguments);
824         this.sync();
825     },
826
827     setTop : function(top){
828         this.storeLeftTop(this.getLeft(true), top);
829         supr.setTop.apply(this, arguments);
830         this.sync();
831     },
832
833     setLeftTop : function(left, top){
834         this.storeLeftTop(left, top);
835         supr.setLeftTop.apply(this, arguments);
836         this.sync();
837     },
838
839     setXY : function(xy, a, d, c, e){
840         this.fixDisplay();
841         this.beforeAction();
842         this.storeXY(xy);
843         var cb = this.createCB(c);
844         supr.setXY.call(this, xy, a, d, cb, e);
845         if(!a){
846             cb();
847         }
848     },
849
850     // private
851     createCB : function(c){
852         var el = this;
853         return function(){
854             el.constrainXY();
855             el.sync(true);
856             if(c){
857                 c();
858             }
859         };
860     },
861
862     // overridden Element method
863     setX : function(x, a, d, c, e){
864         this.setXY([x, this.getY()], a, d, c, e);
865     },
866
867     // overridden Element method
868     setY : function(y, a, d, c, e){
869         this.setXY([this.getX(), y], a, d, c, e);
870     },
871
872     // overridden Element method
873     setSize : function(w, h, a, d, c, e){
874         this.beforeAction();
875         var cb = this.createCB(c);
876         supr.setSize.call(this, w, h, a, d, cb, e);
877         if(!a){
878             cb();
879         }
880     },
881
882     // overridden Element method
883     setWidth : function(w, a, d, c, e){
884         this.beforeAction();
885         var cb = this.createCB(c);
886         supr.setWidth.call(this, w, a, d, cb, e);
887         if(!a){
888             cb();
889         }
890     },
891
892     // overridden Element method
893     setHeight : function(h, a, d, c, e){
894         this.beforeAction();
895         var cb = this.createCB(c);
896         supr.setHeight.call(this, h, a, d, cb, e);
897         if(!a){
898             cb();
899         }
900     },
901
902     // overridden Element method
903     setBounds : function(x, y, w, h, a, d, c, e){
904         this.beforeAction();
905         var cb = this.createCB(c);
906         if(!a){
907             this.storeXY([x, y]);
908             supr.setXY.call(this, [x, y]);
909             supr.setSize.call(this, w, h, a, d, cb, e);
910             cb();
911         }else{
912             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
913         }
914         return this;
915     },
916     
917     /**
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
923      */
924     setZIndex : function(zindex){
925         this.zindex = zindex;
926         this.setStyle("z-index", zindex + 2);
927         if(this.shadow){
928             this.shadow.setZIndex(zindex + 1);
929         }
930         if(this.shim){
931             this.shim.setStyle("z-index", zindex);
932         }
933     }
934 });
935 })();/*
936  * Based on:
937  * Ext JS Library 1.1.1
938  * Copyright(c) 2006-2007, Ext JS, LLC.
939  *
940  * Originally Released Under LGPL - original licence link has changed is not relivant.
941  *
942  * Fork - LGPL
943  * <script type="text/javascript">
944  */
945
946
947 /**
948  * @class Roo.Shadow
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.
952  * @constructor
953  * Create a new Shadow
954  * @param {Object} config The config object
955  */
956 Roo.Shadow = function(config){
957     Roo.apply(this, config);
958     if(typeof this.mode != "string"){
959         this.mode = this.defaultMode;
960     }
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
964         case "drop":
965             a.w = 0;
966             a.l = a.t = o;
967             a.t -= 1;
968             if(Roo.isIE){
969                 a.l -= this.offset + rad;
970                 a.t -= this.offset + rad;
971                 a.w -= rad;
972                 a.h -= rad;
973                 a.t += 1;
974             }
975         break;
976         case "sides":
977             a.w = (o*2);
978             a.l = -o;
979             a.t = o-1;
980             if(Roo.isIE){
981                 a.l -= (this.offset - rad);
982                 a.t -= this.offset + rad;
983                 a.l += 1;
984                 a.w -= (this.offset - rad)*2;
985                 a.w -= rad + 1;
986                 a.h -= 1;
987             }
988         break;
989         case "frame":
990             a.w = a.h = (o*2);
991             a.l = a.t = -o;
992             a.t += 1;
993             a.h -= 2;
994             if(Roo.isIE){
995                 a.l -= (this.offset - rad);
996                 a.t -= (this.offset - rad);
997                 a.l += 1;
998                 a.w -= (this.offset + rad + 1);
999                 a.h -= (this.offset + rad);
1000                 a.h += 1;
1001             }
1002         break;
1003     };
1004
1005     this.adjusts = a;
1006 };
1007
1008 Roo.Shadow.prototype = {
1009     /**
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)
1015      */
1016     /**
1017      * @cfg {String} offset
1018      * The number of pixels to offset the shadow from the element (defaults to 4)
1019      */
1020     offset: 4,
1021
1022     // private
1023     defaultMode: "drop",
1024
1025     /**
1026      * Displays the shadow under the target element
1027      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
1028      */
1029     show : function(target){
1030         target = Roo.get(target);
1031         if(!this.el){
1032             this.el = Roo.Shadow.Pool.pull();
1033             if(this.el.dom.nextSibling != target.dom){
1034                 this.el.insertBefore(target);
1035             }
1036         }
1037         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
1038         if(Roo.isIE){
1039             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
1040         }
1041         this.realign(
1042             target.getLeft(true),
1043             target.getTop(true),
1044             target.getWidth(),
1045             target.getHeight()
1046         );
1047         this.el.dom.style.display = "block";
1048     },
1049
1050     /**
1051      * Returns true if the shadow is visible, else false
1052      */
1053     isVisible : function(){
1054         return this.el ? true : false;  
1055     },
1056
1057     /**
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
1064      */
1065     realign : function(l, t, w, h){
1066         if(!this.el){
1067             return;
1068         }
1069         var a = this.adjusts, d = this.el.dom, s = d.style;
1070         var iea = 0;
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){
1075             s.width = sws;
1076             s.height = shs;
1077             if(!Roo.isIE){
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";
1084             }
1085         }
1086     },
1087
1088     /**
1089      * Hides this shadow
1090      */
1091     hide : function(){
1092         if(this.el){
1093             this.el.dom.style.display = "none";
1094             Roo.Shadow.Pool.push(this.el);
1095             delete this.el;
1096         }
1097     },
1098
1099     /**
1100      * Adjust the z-index of this shadow
1101      * @param {Number} zindex The new z-index
1102      */
1103     setZIndex : function(z){
1104         this.zIndex = z;
1105         if(this.el){
1106             this.el.setStyle("z-index", z);
1107         }
1108     }
1109 };
1110
1111 // Private utility class that manages the internal Shadow cache
1112 Roo.Shadow.Pool = function(){
1113     var p = [];
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>';
1117     return {
1118         pull : function(){
1119             var sh = p.shift();
1120             if(!sh){
1121                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
1122                 sh.autoBoxAdjust = false;
1123             }
1124             return sh;
1125         },
1126
1127         push : function(sh){
1128             p.push(sh);
1129         }
1130     };
1131 }();/*
1132  * Based on:
1133  * Ext JS Library 1.1.1
1134  * Copyright(c) 2006-2007, Ext JS, LLC.
1135  *
1136  * Originally Released Under LGPL - original licence link has changed is not relivant.
1137  *
1138  * Fork - LGPL
1139  * <script type="text/javascript">
1140  */
1141
1142 /**
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.
1149  * @constructor
1150  * @param {Roo.Element/String/Object} config The configuration options.
1151  */
1152 Roo.BoxComponent = function(config){
1153     Roo.Component.call(this, config);
1154     this.addEvents({
1155         /**
1156          * @event resize
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
1163              */
1164         resize : true,
1165         /**
1166          * @event move
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
1171              */
1172         move : true
1173     });
1174 };
1175
1176 Roo.extend(Roo.BoxComponent, Roo.Component, {
1177     // private, set in afterRender to signify that the component has been rendered
1178     boxReady : false,
1179     // private, used to defer height settings to subclasses
1180     deferHeight: false,
1181     /** @cfg {Number} width
1182      * width (optional) size of component
1183      */
1184      /** @cfg {Number} height
1185      * height (optional) size of component
1186      */
1187      
1188     /**
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
1194      */
1195     setSize : function(w, h){
1196         // support for standard size objects
1197         if(typeof w == 'object'){
1198             h = w.height;
1199             w = w.width;
1200         }
1201         // not rendered
1202         if(!this.boxReady){
1203             this.width = w;
1204             this.height = h;
1205             return this;
1206         }
1207
1208         // prevent recalcs when not needed
1209         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
1210             return this;
1211         }
1212         this.lastSize = {width: w, height: h};
1213
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){
1219                 rz.setSize(aw, ah);
1220             }else if(!this.deferHeight && ah !== undefined){
1221                 rz.setHeight(ah);
1222             }else if(aw !== undefined){
1223                 rz.setWidth(aw);
1224             }
1225             this.onResize(aw, ah, w, h);
1226             this.fireEvent('resize', this, aw, ah, w, h);
1227         }
1228         return this;
1229     },
1230
1231     /**
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)}
1234      */
1235     getSize : function(){
1236         return this.el.getSize();
1237     },
1238
1239     /**
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])
1243      */
1244     getPosition : function(local){
1245         if(local === true){
1246             return [this.el.getLeft(true), this.el.getTop(true)];
1247         }
1248         return this.xy || this.el.getXY();
1249     },
1250
1251     /**
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}
1255      */
1256     getBox : function(local){
1257         var s = this.el.getSize();
1258         if(local){
1259             s.x = this.el.getLeft(true);
1260             s.y = this.el.getTop(true);
1261         }else{
1262             var xy = this.xy || this.el.getXY();
1263             s.x = xy[0];
1264             s.y = xy[1];
1265         }
1266         return s;
1267     },
1268
1269     /**
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
1273      */
1274     updateBox : function(box){
1275         this.setSize(box.width, box.height);
1276         this.setPagePosition(box.x, box.y);
1277         return this;
1278     },
1279
1280     // protected
1281     getResizeEl : function(){
1282         return this.resizeEl || this.el;
1283     },
1284
1285     // protected
1286     getPositionEl : function(){
1287         return this.positionEl || this.el;
1288     },
1289
1290     /**
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
1296      */
1297     setPosition : function(x, y){
1298         this.x = x;
1299         this.y = y;
1300         if(!this.boxReady){
1301             return this;
1302         }
1303         var adj = this.adjustPosition(x, y);
1304         var ax = adj.x, ay = adj.y;
1305
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){
1311                 el.setLeft(ax);
1312             }else if(ay !== undefined){
1313                 el.setTop(ay);
1314             }
1315             this.onPosition(ax, ay);
1316             this.fireEvent('move', this, ax, ay);
1317         }
1318         return this;
1319     },
1320
1321     /**
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
1327      */
1328     setPagePosition : function(x, y){
1329         this.pageX = x;
1330         this.pageY = y;
1331         if(!this.boxReady){
1332             return;
1333         }
1334         if(x === undefined || y === undefined){ // cannot translate undefined points
1335             return;
1336         }
1337         var p = this.el.translatePoints(x, y);
1338         this.setPosition(p.left, p.top);
1339         return this;
1340     },
1341
1342     // private
1343     onRender : function(ct, position){
1344         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
1345         if(this.resizeEl){
1346             this.resizeEl = Roo.get(this.resizeEl);
1347         }
1348         if(this.positionEl){
1349             this.positionEl = Roo.get(this.positionEl);
1350         }
1351     },
1352
1353     // private
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);
1360         }
1361         if(this.pageX || this.pageY){
1362             this.setPagePosition(this.pageX, this.pageY);
1363         }
1364     },
1365
1366     /**
1367      * Force the component's size to recalculate based on the underlying element's current height and width.
1368      * @returns {Roo.BoxComponent} this
1369      */
1370     syncSize : function(){
1371         delete this.lastSize;
1372         this.setSize(this.el.getWidth(), this.el.getHeight());
1373         return this;
1374     },
1375
1376     /**
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
1383      */
1384     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
1385
1386     },
1387
1388     /**
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
1393      */
1394     onPosition : function(x, y){
1395
1396     },
1397
1398     // private
1399     adjustSize : function(w, h){
1400         if(this.autoWidth){
1401             w = 'auto';
1402         }
1403         if(this.autoHeight){
1404             h = 'auto';
1405         }
1406         return {width : w, height: h};
1407     },
1408
1409     // private
1410     adjustPosition : function(x, y){
1411         return {x : x, y: y};
1412     }
1413 });/*
1414  * Based on:
1415  * Ext JS Library 1.1.1
1416  * Copyright(c) 2006-2007, Ext JS, LLC.
1417  *
1418  * Originally Released Under LGPL - original licence link has changed is not relivant.
1419  *
1420  * Fork - LGPL
1421  * <script type="text/javascript">
1422  */
1423
1424
1425 /**
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).
1429  * <br><br>
1430  * Usage:
1431  * <pre><code>
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);
1439 </code></pre>
1440  * @constructor
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).
1448  */
1449 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
1450     
1451     /** @private */
1452     this.el = Roo.get(dragElement, true);
1453     this.el.dom.unselectable = "on";
1454     /** @private */
1455     this.resizingEl = Roo.get(resizingElement, true);
1456
1457     /**
1458      * @private
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
1461      * @type Number
1462      */
1463     this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
1464     
1465     /**
1466      * The minimum size of the resizing element. (Defaults to 0)
1467      * @type Number
1468      */
1469     this.minSize = 0;
1470     
1471     /**
1472      * The maximum size of the resizing element. (Defaults to 2000)
1473      * @type Number
1474      */
1475     this.maxSize = 2000;
1476     
1477     /**
1478      * Whether to animate the transition to the new size
1479      * @type Boolean
1480      */
1481     this.animate = false;
1482     
1483     /**
1484      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
1485      * @type Boolean
1486      */
1487     this.useShim = false;
1488     
1489     /** @private */
1490     this.shim = null;
1491     
1492     if(!existingProxy){
1493         /** @private */
1494         this.proxy = Roo.SplitBar.createProxy(this.orientation);
1495     }else{
1496         this.proxy = Roo.get(existingProxy).dom;
1497     }
1498     /** @private */
1499     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
1500     
1501     /** @private */
1502     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
1503     
1504     /** @private */
1505     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
1506     
1507     /** @private */
1508     this.dragSpecs = {};
1509     
1510     /**
1511      * @private The adapter to use to positon and resize elements
1512      */
1513     this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
1514     this.adapter.init(this);
1515     
1516     if(this.orientation == Roo.SplitBar.HORIZONTAL){
1517         /** @private */
1518         this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
1519         this.el.addClass("x-splitbar-h");
1520     }else{
1521         /** @private */
1522         this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
1523         this.el.addClass("x-splitbar-v");
1524     }
1525     
1526     this.addEvents({
1527         /**
1528          * @event resize
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
1532          */
1533         "resize" : true,
1534         /**
1535          * @event moved
1536          * Fires when the splitter is moved
1537          * @param {Roo.SplitBar} this
1538          * @param {Number} newSize the new width or height
1539          */
1540         "moved" : true,
1541         /**
1542          * @event beforeresize
1543          * Fires before the splitter is dragged
1544          * @param {Roo.SplitBar} this
1545          */
1546         "beforeresize" : true,
1547
1548         "beforeapply" : true
1549     });
1550
1551     Roo.util.Observable.call(this);
1552 };
1553
1554 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
1555     onStartProxyDrag : function(x, y){
1556         this.fireEvent("beforeresize", this);
1557         if(!this.overlay){
1558             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
1559             o.unselectable();
1560             o.enableDisplayMode("block");
1561             // all splitbars share the same overlay
1562             Roo.SplitBar.prototype.overlay = o;
1563         }
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
1577             );
1578             this.dd.setYConstraint(0, 0);
1579         }else{
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
1585             );
1586          }
1587         this.dragSpecs.startSize = size;
1588         this.dragSpecs.startPoint = [x, y];
1589         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
1590     },
1591     
1592     /** 
1593      * @private Called after the drag operation by the DDProxy
1594      */
1595     onEndProxyDrag : function(e){
1596         Roo.get(this.proxy).setDisplayed(false);
1597         var endPoint = Roo.lib.Event.getXY(e);
1598         if(this.overlay){
1599             this.overlay.hide();
1600         }
1601         var newSize;
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]
1607                 );
1608         }else{
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]
1613                 );
1614         }
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);
1621             }
1622         }
1623     },
1624     
1625     /**
1626      * Get the adapter this SplitBar uses
1627      * @return The adapter object
1628      */
1629     getAdapter : function(){
1630         return this.adapter;
1631     },
1632     
1633     /**
1634      * Set the adapter this SplitBar uses
1635      * @param {Object} adapter A SplitBar adapter object
1636      */
1637     setAdapter : function(adapter){
1638         this.adapter = adapter;
1639         this.adapter.init(this);
1640     },
1641     
1642     /**
1643      * Gets the minimum size for the resizing element
1644      * @return {Number} The minimum size
1645      */
1646     getMinimumSize : function(){
1647         return this.minSize;
1648     },
1649     
1650     /**
1651      * Sets the minimum size for the resizing element
1652      * @param {Number} minSize The minimum size
1653      */
1654     setMinimumSize : function(minSize){
1655         this.minSize = minSize;
1656     },
1657     
1658     /**
1659      * Gets the maximum size for the resizing element
1660      * @return {Number} The maximum size
1661      */
1662     getMaximumSize : function(){
1663         return this.maxSize;
1664     },
1665     
1666     /**
1667      * Sets the maximum size for the resizing element
1668      * @param {Number} maxSize The maximum size
1669      */
1670     setMaximumSize : function(maxSize){
1671         this.maxSize = maxSize;
1672     },
1673     
1674     /**
1675      * Sets the initialize size for the resizing element
1676      * @param {Number} size The initial size
1677      */
1678     setCurrentSize : function(size){
1679         var oldAnimate = this.animate;
1680         this.animate = false;
1681         this.adapter.setElementSize(this, size);
1682         this.animate = oldAnimate;
1683     },
1684     
1685     /**
1686      * Destroy this splitbar. 
1687      * @param {Boolean} removeEl True to remove the element
1688      */
1689     destroy : function(removeEl){
1690         if(this.shim){
1691             this.shim.remove();
1692         }
1693         this.dd.unreg();
1694         this.proxy.parentNode.removeChild(this.proxy);
1695         if(removeEl){
1696             this.el.remove();
1697         }
1698     }
1699 });
1700
1701 /**
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.
1703  */
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);
1710     return proxy.dom;
1711 };
1712
1713 /** 
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.
1717  */
1718 Roo.SplitBar.BasicLayoutAdapter = function(){
1719 };
1720
1721 Roo.SplitBar.BasicLayoutAdapter.prototype = {
1722     // do nothing for now
1723     init : function(s){
1724     
1725     },
1726     /**
1727      * Called before drag operations to get the current size of the resizing element. 
1728      * @param {Roo.SplitBar} s The SplitBar using this adapter
1729      */
1730      getElementSize : function(s){
1731         if(s.orientation == Roo.SplitBar.HORIZONTAL){
1732             return s.resizingEl.getWidth();
1733         }else{
1734             return s.resizingEl.getHeight();
1735         }
1736     },
1737     
1738     /**
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
1743      */
1744     setElementSize : function(s, newSize, onComplete){
1745         if(s.orientation == Roo.SplitBar.HORIZONTAL){
1746             if(!s.animate){
1747                 s.resizingEl.setWidth(newSize);
1748                 if(onComplete){
1749                     onComplete(s, newSize);
1750                 }
1751             }else{
1752                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
1753             }
1754         }else{
1755             
1756             if(!s.animate){
1757                 s.resizingEl.setHeight(newSize);
1758                 if(onComplete){
1759                     onComplete(s, newSize);
1760                 }
1761             }else{
1762                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
1763             }
1764         }
1765     }
1766 };
1767
1768 /** 
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.
1775  */
1776 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
1777     this.basic = new Roo.SplitBar.BasicLayoutAdapter();
1778     this.container = Roo.get(container);
1779 };
1780
1781 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
1782     init : function(s){
1783         this.basic.init(s);
1784     },
1785     
1786     getElementSize : function(s){
1787         return this.basic.getElementSize(s);
1788     },
1789     
1790     setElementSize : function(s, newSize, onComplete){
1791         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
1792     },
1793     
1794     moveSplitter : function(s){
1795         var yes = Roo.SplitBar;
1796         switch(s.placement){
1797             case yes.LEFT:
1798                 s.el.setX(s.resizingEl.getRight());
1799                 break;
1800             case yes.RIGHT:
1801                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
1802                 break;
1803             case yes.TOP:
1804                 s.el.setY(s.resizingEl.getBottom());
1805                 break;
1806             case yes.BOTTOM:
1807                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
1808                 break;
1809         }
1810     }
1811 };
1812
1813 /**
1814  * Orientation constant - Create a vertical SplitBar
1815  * @static
1816  * @type Number
1817  */
1818 Roo.SplitBar.VERTICAL = 1;
1819
1820 /**
1821  * Orientation constant - Create a horizontal SplitBar
1822  * @static
1823  * @type Number
1824  */
1825 Roo.SplitBar.HORIZONTAL = 2;
1826
1827 /**
1828  * Placement constant - The resizing element is to the left of the splitter element
1829  * @static
1830  * @type Number
1831  */
1832 Roo.SplitBar.LEFT = 1;
1833
1834 /**
1835  * Placement constant - The resizing element is to the right of the splitter element
1836  * @static
1837  * @type Number
1838  */
1839 Roo.SplitBar.RIGHT = 2;
1840
1841 /**
1842  * Placement constant - The resizing element is positioned above the splitter element
1843  * @static
1844  * @type Number
1845  */
1846 Roo.SplitBar.TOP = 3;
1847
1848 /**
1849  * Placement constant - The resizing element is positioned under splitter element
1850  * @static
1851  * @type Number
1852  */
1853 Roo.SplitBar.BOTTOM = 4;
1854 /*
1855  * Based on:
1856  * Ext JS Library 1.1.1
1857  * Copyright(c) 2006-2007, Ext JS, LLC.
1858  *
1859  * Originally Released Under LGPL - original licence link has changed is not relivant.
1860  *
1861  * Fork - LGPL
1862  * <script type="text/javascript">
1863  */
1864
1865 /**
1866  * @class Roo.View
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:
1871  <pre><code>
1872  var store = new Roo.data.Store(...);
1873
1874  var view = new Roo.View("my-element",
1875  '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
1876  {
1877  singleSelect: true,
1878  selectedClass: "ydataview-selected",
1879  store: store
1880  });
1881
1882  // listen for node click?
1883  view.on("click", function(vw, index, node, e){
1884  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
1885  });
1886
1887  // load XML data
1888  dataModel.load("foobar.xml");
1889  </code></pre>
1890  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
1891  * <br><br>
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>
1894  * @constructor
1895  * Create a new View
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
1899  */
1900 Roo.View = function(container, tpl, config){
1901     this.el = Roo.get(container);
1902     if(typeof tpl == "string"){
1903         tpl = new Roo.Template(tpl);
1904     }
1905     tpl.compile();
1906     /**
1907      * The template used by this View
1908      * @type {Roo.DomHelper.Template}
1909      */
1910     this.tpl = tpl;
1911
1912     Roo.apply(this, config);
1913
1914     /** @private */
1915     this.addEvents({
1916     /**
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
1923      */
1924         "beforeclick" : true,
1925     /**
1926      * @event click
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
1932      */
1933         "click" : true,
1934     /**
1935      * @event dblclick
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
1941      */
1942         "dblclick" : true,
1943     /**
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
1950      */
1951         "contextmenu" : true,
1952     /**
1953      * @event selectionchange
1954      * Fires when the selected nodes change.
1955      * @param {Roo.View} this
1956      * @param {Array} selections Array of the selected nodes
1957      */
1958         "selectionchange" : true,
1959
1960     /**
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
1966      */
1967         "beforeselect" : true
1968     });
1969
1970     this.el.on({
1971         "click": this.onClick,
1972         "dblclick": this.onDblClick,
1973         "contextmenu": this.onContextMenu,
1974         scope:this
1975     });
1976
1977     this.selections = [];
1978     this.nodes = [];
1979     this.cmp = new Roo.CompositeElementLite([]);
1980     if(this.store){
1981         this.store = Roo.factory(this.store, Roo.data);
1982         this.setStore(this.store, true);
1983     }
1984     Roo.View.superclass.constructor.call(this);
1985 };
1986
1987 Roo.extend(Roo.View, Roo.util.Observable, {
1988     /**
1989      * The css class to add to selected nodes
1990      * @type {Roo.DomHelper.Template}
1991      */
1992     selectedClass : "x-view-selected",
1993     
1994     emptyText : "",
1995     /**
1996      * Returns the element this view is bound to.
1997      * @return {Roo.Element}
1998      */
1999     getEl : function(){
2000         return this.el;
2001     },
2002
2003     /**
2004      * Refreshes the view.
2005      */
2006     refresh : function(){
2007         var t = this.tpl;
2008         this.clearSelections();
2009         this.el.update("");
2010         var html = [];
2011         var records = this.store.getRange();
2012         if(records.length < 1){
2013             this.el.update(this.emptyText);
2014             return;
2015         }
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);
2019         }
2020         this.el.update(html.join(""));
2021         this.nodes = this.el.dom.childNodes;
2022         this.updateIndexes(0);
2023     },
2024
2025     /**
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).
2030      */
2031     prepareData : function(data){
2032         return data;
2033     },
2034
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);
2042     },
2043
2044     onAdd : function(ds, records, index){
2045         this.clearSelections();
2046         if(this.nodes.length == 0){
2047             this.refresh();
2048             return;
2049         }
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);
2053             if(n){
2054                 this.tpl.insertBefore(n, d);
2055             }else{
2056                 this.tpl.append(this.el, d);
2057             }
2058         }
2059         this.updateIndexes(index);
2060     },
2061
2062     onRemove : function(ds, record, index){
2063         this.clearSelections();
2064         this.el.dom.removeChild(this.nodes[index]);
2065         this.updateIndexes(index);
2066     },
2067
2068     /**
2069      * Refresh an individual node.
2070      * @param {Number} index
2071      */
2072     refreshNode : function(index){
2073         this.onUpdate(this.store, this.store.getAt(index));
2074     },
2075
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;
2082         }
2083     },
2084
2085     /**
2086      * Changes the data store this view uses and refresh the view.
2087      * @param {Store} store
2088      */
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);
2096         }
2097         if(store){
2098           
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);
2104         }
2105         
2106         if(store){
2107             this.refresh();
2108         }
2109     },
2110
2111     /**
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
2115      */
2116     findItemFromChild : function(node){
2117         var el = this.el.dom;
2118         if(!node || node.parentNode == el){
2119                     return node;
2120             }
2121             var p = node.parentNode;
2122             while(p && p != el){
2123             if(p.parentNode == el){
2124                 return p;
2125             }
2126             p = p.parentNode;
2127         }
2128             return null;
2129     },
2130
2131     /** @ignore */
2132     onClick : function(e){
2133         var item = this.findItemFromChild(e.getTarget());
2134         if(item){
2135             var index = this.indexOf(item);
2136             if(this.onItemClick(item, index, e) !== false){
2137                 this.fireEvent("click", this, index, item, e);
2138             }
2139         }else{
2140             this.clearSelections();
2141         }
2142     },
2143
2144     /** @ignore */
2145     onContextMenu : function(e){
2146         var item = this.findItemFromChild(e.getTarget());
2147         if(item){
2148             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
2149         }
2150     },
2151
2152     /** @ignore */
2153     onDblClick : function(e){
2154         var item = this.findItemFromChild(e.getTarget());
2155         if(item){
2156             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
2157         }
2158     },
2159
2160     onItemClick : function(item, index, e){
2161         if(this.fireEvent("beforeclick", this, index, item, e) === false){
2162             return false;
2163         }
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);
2167             }else{
2168                 this.select(item, this.multiSelect && e.ctrlKey);
2169                 this.lastSelection = item;
2170             }
2171             e.preventDefault();
2172         }
2173         return true;
2174     },
2175
2176     /**
2177      * Get the number of selected nodes.
2178      * @return {Number}
2179      */
2180     getSelectionCount : function(){
2181         return this.selections.length;
2182     },
2183
2184     /**
2185      * Get the currently selected nodes.
2186      * @return {Array} An array of HTMLElements
2187      */
2188     getSelectedNodes : function(){
2189         return this.selections;
2190     },
2191
2192     /**
2193      * Get the indexes of the selected nodes.
2194      * @return {Array}
2195      */
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);
2200         }
2201         return indexes;
2202     },
2203
2204     /**
2205      * Clear all selections
2206      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
2207      */
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 = [];
2213             if(!suppressEvent){
2214                 this.fireEvent("selectionchange", this, this.selections);
2215             }
2216         }
2217     },
2218
2219     /**
2220      * Returns true if the passed node is selected
2221      * @param {HTMLElement/Number} node The node or node index
2222      * @return {Boolean}
2223      */
2224     isSelected : function(node){
2225         var s = this.selections;
2226         if(s.length < 1){
2227             return false;
2228         }
2229         node = this.getNode(node);
2230         return s.indexOf(node) !== -1;
2231     },
2232
2233     /**
2234      * Selects nodes.
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
2238      */
2239     select : function(nodeInfo, keepExisting, suppressEvent){
2240         if(nodeInfo instanceof Array){
2241             if(!keepExisting){
2242                 this.clearSelections(true);
2243             }
2244             for(var i = 0, len = nodeInfo.length; i < len; i++){
2245                 this.select(nodeInfo[i], true, true);
2246             }
2247         } else{
2248             var node = this.getNode(nodeInfo);
2249             if(node && !this.isSelected(node)){
2250                 if(!keepExisting){
2251                     this.clearSelections(true);
2252                 }
2253                 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
2254                     Roo.fly(node).addClass(this.selectedClass);
2255                     this.selections.push(node);
2256                     if(!suppressEvent){
2257                         this.fireEvent("selectionchange", this, this.selections);
2258                     }
2259                 }
2260             }
2261         }
2262     },
2263
2264     /**
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
2268      */
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];
2274         }
2275         return nodeInfo;
2276     },
2277
2278     /**
2279      * Gets a range template nodes.
2280      * @param {Number} startIndex
2281      * @param {Number} endIndex
2282      * @return {Array} An array of nodes
2283      */
2284     getNodes : function(start, end){
2285         var ns = this.nodes;
2286         start = start || 0;
2287         end = typeof end == "undefined" ? ns.length - 1 : end;
2288         var nodes = [];
2289         if(start <= end){
2290             for(var i = start; i <= end; i++){
2291                 nodes.push(ns[i]);
2292             }
2293         } else{
2294             for(var i = start; i >= end; i--){
2295                 nodes.push(ns[i]);
2296             }
2297         }
2298         return nodes;
2299     },
2300
2301     /**
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
2305      */
2306     indexOf : function(node){
2307         node = this.getNode(node);
2308         if(typeof node.nodeIndex == "number"){
2309             return node.nodeIndex;
2310         }
2311         var ns = this.nodes;
2312         for(var i = 0, len = ns.length; i < len; i++){
2313             if(ns[i] == node){
2314                 return i;
2315             }
2316         }
2317         return -1;
2318     }
2319 });
2320 /*
2321  * Based on:
2322  * Ext JS Library 1.1.1
2323  * Copyright(c) 2006-2007, Ext JS, LLC.
2324  *
2325  * Originally Released Under LGPL - original licence link has changed is not relivant.
2326  *
2327  * Fork - LGPL
2328  * <script type="text/javascript">
2329  */
2330
2331 /**
2332  * @class Roo.JsonView
2333  * @extends Roo.View
2334  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
2335 <pre><code>
2336 var view = new Roo.JsonView("my-element",
2337     '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
2338     { multiSelect: true, jsonRoot: "data" }
2339 );
2340
2341 // listen for node click?
2342 view.on("click", function(vw, index, node, e){
2343     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
2344 });
2345
2346 // direct load of JSON data
2347 view.load("foobar.php");
2348
2349 // Example from my blog list
2350 var tpl = new Roo.Template(
2351     '&lt;div class="entry"&gt;' +
2352     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
2353     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
2354     "&lt;/div&gt;&lt;hr /&gt;"
2355 );
2356
2357 var moreView = new Roo.JsonView("entry-list", tpl, {
2358     jsonRoot: "posts"
2359 });
2360 moreView.on("beforerender", this.sortEntries, this);
2361 moreView.load({
2362     url: "/blog/get-posts.php",
2363     params: "allposts=true",
2364     text: "Loading Blog Entries..."
2365 });
2366 </code></pre>
2367  * @constructor
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
2372  */
2373 Roo.JsonView = function(container, tpl, config){
2374     Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
2375
2376     var um = this.el.getUpdateManager();
2377     um.setRenderer(this);
2378     um.on("update", this.onLoad, this);
2379     um.on("failure", this.onLoadException, this);
2380
2381     /**
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
2386      */
2387     /**
2388      * @event load
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
2393      */
2394     /**
2395      * @event loadexception
2396      * Fires when loading fails.
2397      * @param {Roo.JsonView} this
2398      * @param {Object} response The raw Connect response object
2399      */
2400     this.addEvents({
2401         'beforerender' : true,
2402         'load' : true,
2403         'loadexception' : true
2404     });
2405 };
2406 Roo.extend(Roo.JsonView, Roo.View, {
2407     /**
2408      * The root property in the loaded JSON object that contains the data
2409      * @type {String}
2410      */
2411     jsonRoot : "",
2412
2413     /**
2414      * Refreshes the view.
2415      */
2416     refresh : function(){
2417         this.clearSelections();
2418         this.el.update("");
2419         var html = [];
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);
2425             }
2426         }else{
2427             html.push(this.emptyText);
2428         }
2429         this.el.update(html.join(""));
2430         this.nodes = this.el.dom.childNodes;
2431         this.updateIndexes(0);
2432     },
2433
2434     /**
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:
2437      <pre><code>
2438      view.load({
2439          url: "your-url.php",
2440          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
2441          callback: yourFunction,
2442          scope: yourObject, //(optional scope)
2443          discardUrl: false,
2444          nocache: false,
2445          text: "Loading...",
2446          timeout: 30,
2447          scripts: false
2448      });
2449      </code></pre>
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&amp;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.
2455      */
2456     load : function(){
2457         var um = this.el.getUpdateManager();
2458         um.update.apply(um, arguments);
2459     },
2460
2461     render : function(el, response){
2462         this.clearSelections();
2463         this.el.update("");
2464         var o;
2465         try{
2466             o = Roo.util.JSON.decode(response.responseText);
2467             if(this.jsonRoot){
2468                 
2469                 o = /** eval:var:o */ eval("o." + this.jsonRoot);
2470             }
2471         } catch(e){
2472         }
2473         /**
2474          * The current JSON data or null
2475          */
2476         this.jsonData = o;
2477         this.beforeRender();
2478         this.refresh();
2479     },
2480
2481 /**
2482  * Get the number of records in the current JSON dataset
2483  * @return {Number}
2484  */
2485     getCount : function(){
2486         return this.jsonData ? this.jsonData.length : 0;
2487     },
2488
2489 /**
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
2494  */
2495     getNodeData : function(node){
2496         if(node instanceof Array){
2497             var data = [];
2498             for(var i = 0, len = node.length; i < len; i++){
2499                 data.push(this.getNodeData(node[i]));
2500             }
2501             return data;
2502         }
2503         return this.jsonData[this.indexOf(node)] || null;
2504     },
2505
2506     beforeRender : function(){
2507         this.snapshot = this.jsonData;
2508         if(this.sortInfo){
2509             this.sort.apply(this, this.sortInfo);
2510         }
2511         this.fireEvent("beforerender", this, this.jsonData);
2512     },
2513
2514     onLoad : function(el, o){
2515         this.fireEvent("load", this, this.jsonData, o);
2516     },
2517
2518     onLoadException : function(el, o){
2519         this.fireEvent("loadexception", this, o);
2520     },
2521
2522 /**
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
2527  */
2528     filter : function(property, value){
2529         if(this.jsonData){
2530             var data = [];
2531             var ss = this.snapshot;
2532             if(typeof value == "string"){
2533                 var vlen = value.length;
2534                 if(vlen == 0){
2535                     this.clearFilter();
2536                     return;
2537                 }
2538                 value = value.toLowerCase();
2539                 for(var i = 0, len = ss.length; i < len; i++){
2540                     var o = ss[i];
2541                     if(o[property].substr(0, vlen).toLowerCase() == value){
2542                         data.push(o);
2543                     }
2544                 }
2545             } else if(value.exec){ // regex?
2546                 for(var i = 0, len = ss.length; i < len; i++){
2547                     var o = ss[i];
2548                     if(value.test(o[property])){
2549                         data.push(o);
2550                     }
2551                 }
2552             } else{
2553                 return;
2554             }
2555             this.jsonData = data;
2556             this.refresh();
2557         }
2558     },
2559
2560 /**
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)
2566  */
2567     filterBy : function(fn, scope){
2568         if(this.jsonData){
2569             var data = [];
2570             var ss = this.snapshot;
2571             for(var i = 0, len = ss.length; i < len; i++){
2572                 var o = ss[i];
2573                 if(fn.call(scope || this, o)){
2574                     data.push(o);
2575                 }
2576             }
2577             this.jsonData = data;
2578             this.refresh();
2579         }
2580     },
2581
2582 /**
2583  * Clears the current filter.
2584  */
2585     clearFilter : function(){
2586         if(this.snapshot && this.jsonData != this.snapshot){
2587             this.jsonData = this.snapshot;
2588             this.refresh();
2589         }
2590     },
2591
2592
2593 /**
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.
2598  */
2599     sort : function(property, dir, sortType){
2600         this.sortInfo = Array.prototype.slice.call(arguments, 0);
2601         if(this.jsonData){
2602             var p = property;
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];
2607                 ;
2608                 if(v1 < v2){
2609                     return dsc ? +1 : -1;
2610                 } else if(v1 > v2){
2611                     return dsc ? -1 : +1;
2612                 } else{
2613                     return 0;
2614                 }
2615             };
2616             this.jsonData.sort(f);
2617             this.refresh();
2618             if(this.jsonData != this.snapshot){
2619                 this.snapshot.sort(f);
2620             }
2621         }
2622     }
2623 });/*
2624  * Based on:
2625  * Ext JS Library 1.1.1
2626  * Copyright(c) 2006-2007, Ext JS, LLC.
2627  *
2628  * Originally Released Under LGPL - original licence link has changed is not relivant.
2629  *
2630  * Fork - LGPL
2631  * <script type="text/javascript">
2632  */
2633  
2634
2635 /**
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:
2640  * <pre><code>
2641 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
2642 cp.render('my-div');
2643
2644 cp.on('select', function(palette, selColor){
2645     // do something with selColor
2646 });
2647 </code></pre>
2648  * @constructor
2649  * Create a new ColorPalette
2650  * @param {Object} config The config object
2651  */
2652 Roo.ColorPalette = function(config){
2653     Roo.ColorPalette.superclass.constructor.call(this, config);
2654     this.addEvents({
2655         /**
2656              * @event select
2657              * Fires when a color is selected
2658              * @param {ColorPalette} this
2659              * @param {String} color The 6-digit color hex code (without the # symbol)
2660              */
2661         select: true
2662     });
2663
2664     if(this.handler){
2665         this.on("select", this.handler, this.scope, true);
2666     }
2667 };
2668 Roo.extend(Roo.ColorPalette, Roo.Component, {
2669     /**
2670      * @cfg {String} itemCls
2671      * The CSS class to apply to the containing element (defaults to "x-color-palette")
2672      */
2673     itemCls : "x-color-palette",
2674     /**
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.
2678      */
2679     value : null,
2680     clickEvent:'click',
2681     // private
2682     ctype: "Roo.ColorPalette",
2683
2684     /**
2685      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
2686      */
2687     allowReselect : false,
2688
2689     /**
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>
2695      * <pre><code>
2696 var cp = new Roo.ColorPalette();
2697 cp.colors[0] = "FF0000";  // change the first box to red
2698 </code></pre>
2699
2700 Or you can provide a custom array of your own for complete control:
2701 <pre><code>
2702 var cp = new Roo.ColorPalette();
2703 cp.colors = ["000000", "993300", "333300"];
2704 </code></pre>
2705      * @type Array
2706      */
2707     colors : [
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"
2713     ],
2714
2715     // private
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">&#160;</span></em></a></tpl>'
2719         );
2720         var c = this.colors;
2721         for(var i = 0, len = c.length; i < len; i++){
2722             t.add([c[i]]);
2723         }
2724         var el = document.createElement("div");
2725         el.className = this.itemCls;
2726         t.overwrite(el);
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});
2732         }
2733     },
2734
2735     // private
2736     afterRender : function(){
2737         Roo.ColorPalette.superclass.afterRender.call(this);
2738         if(this.value){
2739             var s = this.value;
2740             this.value = null;
2741             this.select(s);
2742         }
2743     },
2744
2745     // private
2746     handleClick : function(e, t){
2747         e.preventDefault();
2748         if(!this.disabled){
2749             var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
2750             this.select(c.toUpperCase());
2751         }
2752     },
2753
2754     /**
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)
2757      */
2758     select : function(color){
2759         color = color.replace("#", "");
2760         if(color != this.value || this.allowReselect){
2761             var el = this.el;
2762             if(this.value){
2763                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
2764             }
2765             el.child("a.color-"+color).addClass("x-color-palette-sel");
2766             this.value = color;
2767             this.fireEvent("select", this, color);
2768         }
2769     }
2770 });/*
2771  * Based on:
2772  * Ext JS Library 1.1.1
2773  * Copyright(c) 2006-2007, Ext JS, LLC.
2774  *
2775  * Originally Released Under LGPL - original licence link has changed is not relivant.
2776  *
2777  * Fork - LGPL
2778  * <script type="text/javascript">
2779  */
2780  
2781 /**
2782  * @class Roo.DatePicker
2783  * @extends Roo.Component
2784  * Simple date picker class.
2785  * @constructor
2786  * Create a new DatePicker
2787  * @param {Object} config The config object
2788  */
2789 Roo.DatePicker = function(config){
2790     Roo.DatePicker.superclass.constructor.call(this, config);
2791
2792     this.value = config && config.value ?
2793                  config.value.clearTime() : new Date().clearTime();
2794
2795     this.addEvents({
2796         /**
2797              * @event select
2798              * Fires when a date is selected
2799              * @param {DatePicker} this
2800              * @param {Date} date The selected date
2801              */
2802         select: true
2803     });
2804
2805     if(this.handler){
2806         this.on("select", this.handler,  this.scope || this);
2807     }
2808     // build the disabledDatesRE
2809     if(!this.disabledDatesRE && this.disabledDates){
2810         var dd = this.disabledDates;
2811         var re = "(?:";
2812         for(var i = 0; i < dd.length; i++){
2813             re += dd[i];
2814             if(i != dd.length-1) re += "|";
2815         }
2816         this.disabledDatesRE = new RegExp(re + ")");
2817     }
2818 };
2819
2820 Roo.extend(Roo.DatePicker, Roo.Component, {
2821     /**
2822      * @cfg {String} todayText
2823      * The text to display on the button that selects the current date (defaults to "Today")
2824      */
2825     todayText : "Today",
2826     /**
2827      * @cfg {String} okText
2828      * The text to display on the ok button
2829      */
2830     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
2831     /**
2832      * @cfg {String} cancelText
2833      * The text to display on the cancel button
2834      */
2835     cancelText : "Cancel",
2836     /**
2837      * @cfg {String} todayTip
2838      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
2839      */
2840     todayTip : "{0} (Spacebar)",
2841     /**
2842      * @cfg {Date} minDate
2843      * Minimum allowable date (JavaScript date object, defaults to null)
2844      */
2845     minDate : null,
2846     /**
2847      * @cfg {Date} maxDate
2848      * Maximum allowable date (JavaScript date object, defaults to null)
2849      */
2850     maxDate : null,
2851     /**
2852      * @cfg {String} minText
2853      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
2854      */
2855     minText : "This date is before the minimum date",
2856     /**
2857      * @cfg {String} maxText
2858      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
2859      */
2860     maxText : "This date is after the maximum date",
2861     /**
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').
2865      */
2866     format : "m/d/y",
2867     /**
2868      * @cfg {Array} disabledDays
2869      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
2870      */
2871     disabledDays : null,
2872     /**
2873      * @cfg {String} disabledDaysText
2874      * The tooltip to display when the date falls on a disabled day (defaults to "")
2875      */
2876     disabledDaysText : "",
2877     /**
2878      * @cfg {RegExp} disabledDatesRE
2879      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
2880      */
2881     disabledDatesRE : null,
2882     /**
2883      * @cfg {String} disabledDatesText
2884      * The tooltip text to display when the date falls on a disabled date (defaults to "")
2885      */
2886     disabledDatesText : "",
2887     /**
2888      * @cfg {Boolean} constrainToViewport
2889      * True to constrain the date picker to the viewport (defaults to true)
2890      */
2891     constrainToViewport : true,
2892     /**
2893      * @cfg {Array} monthNames
2894      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
2895      */
2896     monthNames : Date.monthNames,
2897     /**
2898      * @cfg {Array} dayNames
2899      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
2900      */
2901     dayNames : Date.dayNames,
2902     /**
2903      * @cfg {String} nextText
2904      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
2905      */
2906     nextText: 'Next Month (Control+Right)',
2907     /**
2908      * @cfg {String} prevText
2909      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
2910      */
2911     prevText: 'Previous Month (Control+Left)',
2912     /**
2913      * @cfg {String} monthYearText
2914      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
2915      */
2916     monthYearText: 'Choose a month (Control+Up/Down to move years)',
2917     /**
2918      * @cfg {Number} startDay
2919      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
2920      */
2921     startDay : 0,
2922     /**
2923      * @cfg {Bool} showClear
2924      * Show a clear button (usefull for date form elements that can be blank.)
2925      */
2926     
2927     showClear: false,
2928     
2929     /**
2930      * Sets the value of the date field
2931      * @param {Date} value The date to set
2932      */
2933     setValue : function(value){
2934         var old = this.value;
2935         this.value = value.clearTime(true);
2936         if(this.el){
2937             this.update(this.value);
2938         }
2939     },
2940
2941     /**
2942      * Gets the current selected value of the date field
2943      * @return {Date} The selected date
2944      */
2945     getValue : function(){
2946         return this.value;
2947     },
2948
2949     // private
2950     focus : function(){
2951         if(this.el){
2952             this.update(this.activeDate);
2953         }
2954     },
2955
2956     // private
2957     onRender : function(container, position){
2958         var m = [
2959              '<table cellspacing="0">',
2960                 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</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;
2965             if(d > 6){
2966                 d = d-7;
2967             }
2968             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
2969         }
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>";
2974             }
2975             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
2976         }
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>';
2979
2980         var el = document.createElement("div");
2981         el.className = "x-date-picker";
2982         el.innerHTML = m.join("");
2983
2984         container.dom.insertBefore(el, position);
2985
2986         this.el = Roo.get(el);
2987         this.eventEl = Roo.get(el.firstChild);
2988
2989         new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
2990             handler: this.showPrevMonth,
2991             scope: this,
2992             preventDefault:true,
2993             stopDefault:true
2994         });
2995
2996         new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
2997             handler: this.showNextMonth,
2998             scope: this,
2999             preventDefault:true,
3000             stopDefault:true
3001         });
3002
3003         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
3004
3005         this.monthPicker = this.el.down('div.x-date-mp');
3006         this.monthPicker.enableDisplayMode('block');
3007         
3008         var kn = new Roo.KeyNav(this.eventEl, {
3009             "left" : function(e){
3010                 e.ctrlKey ?
3011                     this.showPrevMonth() :
3012                     this.update(this.activeDate.add("d", -1));
3013             },
3014
3015             "right" : function(e){
3016                 e.ctrlKey ?
3017                     this.showNextMonth() :
3018                     this.update(this.activeDate.add("d", 1));
3019             },
3020
3021             "up" : function(e){
3022                 e.ctrlKey ?
3023                     this.showNextYear() :
3024                     this.update(this.activeDate.add("d", -7));
3025             },
3026
3027             "down" : function(e){
3028                 e.ctrlKey ?
3029                     this.showPrevYear() :
3030                     this.update(this.activeDate.add("d", 7));
3031             },
3032
3033             "pageUp" : function(e){
3034                 this.showNextMonth();
3035             },
3036
3037             "pageDown" : function(e){
3038                 this.showPrevMonth();
3039             },
3040
3041             "enter" : function(e){
3042                 e.stopPropagation();
3043                 return true;
3044             },
3045
3046             scope : this
3047         });
3048
3049         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
3050
3051         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
3052
3053         this.el.unselectable();
3054         
3055         this.cells = this.el.select("table.x-date-inner tbody td");
3056         this.textNodes = this.el.query("table.x-date-inner tbody span");
3057
3058         this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
3059             text: "&#160;",
3060             tooltip: this.monthYearText
3061         });
3062
3063         this.mbtn.on('click', this.showMonthPicker, this);
3064         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
3065
3066
3067         var today = (new Date()).dateFormat(this.format);
3068         
3069         var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
3070         baseTb.add({
3071             text: String.format(this.todayText, today),
3072             tooltip: String.format(this.todayTip, today),
3073             handler: this.selectToday,
3074             scope: this
3075         });
3076         
3077         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
3078             
3079         //});
3080         if (this.showClear) {
3081             
3082             baseTb.add( new Roo.Toolbar.Fill());
3083             baseTb.add({
3084                 text: '&#160;',
3085                 cls: 'x-btn-icon x-btn-clear',
3086                 handler: function() {
3087                     //this.value = '';
3088                     this.fireEvent("select", this, '');
3089                 },
3090                 scope: this
3091             });
3092         }
3093         
3094         
3095         if(Roo.isIE){
3096             this.el.repaint();
3097         }
3098         this.update(this.value);
3099     },
3100
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++){
3105                 buf.push(
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>',
3108                     i == 0 ?
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>'
3111                 );
3112             }
3113             buf.push(
3114                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
3115                     this.okText,
3116                     '</button><button type="button" class="x-date-mp-cancel">',
3117                     this.cancelText,
3118                     '</button></td></tr>',
3119                 '</table>'
3120             );
3121             this.monthPicker.update(buf.join(''));
3122             this.monthPicker.on('click', this.onMonthClick, this);
3123             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
3124
3125             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
3126             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
3127
3128             this.mpMonths.each(function(m, a, i){
3129                 i += 1;
3130                 if((i%2) == 0){
3131                     m.dom.xmonth = 5 + Math.round(i * .5);
3132                 }else{
3133                     m.dom.xmonth = Math.round((i-1) * .5);
3134                 }
3135             });
3136         }
3137     },
3138
3139     showMonthPicker : function(){
3140         this.createMonthPicker();
3141         var size = this.el.getSize();
3142         this.monthPicker.setSize(size);
3143         this.monthPicker.child('table').setSize(size);
3144
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);
3149
3150         this.monthPicker.slideIn('t', {duration:.2});
3151     },
3152
3153     updateMPYear : function(y){
3154         this.mpyear = y;
3155         var ys = this.mpYears.elements;
3156         for(var i = 1; i <= 10; i++){
3157             var td = ys[i-1], y2;
3158             if((i%2) == 0){
3159                 y2 = y + Math.round(i * .5);
3160                 td.firstChild.innerHTML = y2;
3161                 td.xyear = y2;
3162             }else{
3163                 y2 = y - (5-Math.round(i * .5));
3164                 td.firstChild.innerHTML = y2;
3165                 td.xyear = y2;
3166             }
3167             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
3168         }
3169     },
3170
3171     updateMPMonth : function(sm){
3172         this.mpMonths.each(function(m, a, i){
3173             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
3174         });
3175     },
3176
3177     selectMPMonth: function(m){
3178         
3179     },
3180
3181     onMonthClick : function(e, t){
3182         e.stopEvent();
3183         var el = new Roo.Element(t), pn;
3184         if(el.is('button.x-date-mp-cancel')){
3185             this.hideMonthPicker();
3186         }
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();
3190         }
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;
3195         }
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;
3200         }
3201         else if(el.is('a.x-date-mp-prev')){
3202             this.updateMPYear(this.mpyear-10);
3203         }
3204         else if(el.is('a.x-date-mp-next')){
3205             this.updateMPYear(this.mpyear+10);
3206         }
3207     },
3208
3209     onMonthDblClick : function(e, t){
3210         e.stopEvent();
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();
3215         }
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();
3219         }
3220     },
3221
3222     hideMonthPicker : function(disableAnim){
3223         if(this.monthPicker){
3224             if(disableAnim === true){
3225                 this.monthPicker.hide();
3226             }else{
3227                 this.monthPicker.slideOut('t', {duration:.2});
3228             }
3229         }
3230     },
3231
3232     // private
3233     showPrevMonth : function(e){
3234         this.update(this.activeDate.add("mo", -1));
3235     },
3236
3237     // private
3238     showNextMonth : function(e){
3239         this.update(this.activeDate.add("mo", 1));
3240     },
3241
3242     // private
3243     showPrevYear : function(){
3244         this.update(this.activeDate.add("y", -1));
3245     },
3246
3247     // private
3248     showNextYear : function(){
3249         this.update(this.activeDate.add("y", 1));
3250     },
3251
3252     // private
3253     handleMouseWheel : function(e){
3254         var delta = e.getWheelDelta();
3255         if(delta > 0){
3256             this.showPrevMonth();
3257             e.stopEvent();
3258         } else if(delta < 0){
3259             this.showNextMonth();
3260             e.stopEvent();
3261         }
3262     },
3263
3264     // private
3265     handleDateClick : function(e, t){
3266         e.stopEvent();
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);
3270         }
3271     },
3272
3273     // private
3274     selectToday : function(){
3275         this.setValue(new Date().clearTime());
3276         this.fireEvent("select", this, this.value);
3277     },
3278
3279     // private
3280     update : function(date){
3281         var vd = this.activeDate;
3282         this.activeDate = date;
3283         if(vd && this.el){
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){}
3292                        }, 50);
3293                        return false;
3294                    }
3295                 });
3296                 return;
3297             }
3298         }
3299         var days = date.getDaysInMonth();
3300         var firstOfMonth = date.getFirstDateOfMonth();
3301         var startingPos = firstOfMonth.getDay()-this.startDay;
3302
3303         if(startingPos <= this.startDay){
3304             startingPos += 7;
3305         }
3306
3307         var pm = date.add("mo", -1);
3308         var prevStart = pm.getDaysInMonth()-startingPos;
3309
3310         var cells = this.cells.elements;
3311         var textEls = this.textNodes;
3312         days += startingPos;
3313
3314         // convert everything to numbers so it's fast
3315         var day = 86400000;
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;
3326
3327         var setCellClass = function(cal, cell){
3328             cell.title = "";
3329             var t = d.getTime();
3330             cell.firstChild.dateValue = t;
3331             if(t == today){
3332                 cell.className += " x-date-today";
3333                 cell.title = cal.todayText;
3334             }
3335             if(t == sel){
3336                 cell.className += " x-date-selected";
3337                 setTimeout(function(){
3338                     try{cell.firstChild.focus();}catch(e){}
3339                 }, 50);
3340             }
3341             // disabling
3342             if(t < min) {
3343                 cell.className = " x-date-disabled";
3344                 cell.title = cal.minText;
3345                 return;
3346             }
3347             if(t > max) {
3348                 cell.className = " x-date-disabled";
3349                 cell.title = cal.maxText;
3350                 return;
3351             }
3352             if(ddays){
3353                 if(ddays.indexOf(d.getDay()) != -1){
3354                     cell.title = ddaysText;
3355                     cell.className = " x-date-disabled";
3356                 }
3357             }
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";
3363                 }
3364             }
3365         };
3366
3367         var i = 0;
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]);
3373         }
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]);
3380         }
3381         var extraDays = 0;
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]);
3387         }
3388
3389         this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
3390
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]);
3404             }
3405         }
3406     }
3407 });/*
3408  * Based on:
3409  * Ext JS Library 1.1.1
3410  * Copyright(c) 2006-2007, Ext JS, LLC.
3411  *
3412  * Originally Released Under LGPL - original licence link has changed is not relivant.
3413  *
3414  * Fork - LGPL
3415  * <script type="text/javascript">
3416  */
3417 /**
3418  * @class Roo.TabPanel
3419  * @extends Roo.util.Observable
3420  * A lightweight tab container.
3421  * <br><br>
3422  * Usage:
3423  * <pre><code>
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");
3429
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.");
3433
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);
3439
3440 // Use setUrl for Ajax loading
3441 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
3442 tab3.setUrl("ajax2.htm", null, true);
3443
3444 // Disabled tab
3445 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
3446 tab4.disable();
3447
3448 jtabs.activate("jtabs-1");
3449  * </code></pre>
3450  * @constructor
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.
3454  */
3455 Roo.TabPanel = function(container, config){
3456     /**
3457     * The container element for this TabPanel.
3458     * @type Roo.Element
3459     */
3460     this.el = Roo.get(container, true);
3461     if(config){
3462         if(typeof config == "boolean"){
3463             this.tabPosition = config ? "bottom" : "top";
3464         }else{
3465             Roo.apply(this, config);
3466         }
3467     }
3468     if(this.tabPosition == "bottom"){
3469         this.bodyEl = Roo.get(this.createBody(this.el.dom));
3470         this.el.addClass("x-tabs-bottom");
3471     }
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);
3475     if(Roo.isIE){
3476         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
3477     }
3478     if(this.tabPosition != "bottom"){
3479     /** The body element that contains {@link Roo.TabPanelItem} bodies.
3480      * @type Roo.Element
3481      */
3482       this.bodyEl = Roo.get(this.createBody(this.el.dom));
3483       this.el.addClass("x-tabs-top");
3484     }
3485     this.items = [];
3486
3487     this.bodyEl.setStyle("position", "relative");
3488
3489     this.active = null;
3490     this.activateDelegate = this.activate.createDelegate(this);
3491
3492     this.addEvents({
3493         /**
3494          * @event tabchange
3495          * Fires when the active tab changes
3496          * @param {Roo.TabPanel} this
3497          * @param {Roo.TabPanelItem} activePanel The new active tab
3498          */
3499         "tabchange": true,
3500         /**
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
3506          */
3507         "beforetabchange" : true
3508     });
3509
3510     Roo.EventManager.onWindowResize(this.onResize, this);
3511     this.cpad = this.el.getPadding("lr");
3512     this.hiddenCount = 0;
3513
3514     Roo.TabPanel.superclass.constructor.call(this);
3515 };
3516
3517 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
3518         /*
3519          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
3520          */
3521     tabPosition : "top",
3522         /*
3523          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
3524          */
3525     currentTabWidth : 0,
3526         /*
3527          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
3528          */
3529     minTabWidth : 40,
3530         /*
3531          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
3532          */
3533     maxTabWidth : 250,
3534         /*
3535          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
3536          */
3537     preferredTabWidth : 175,
3538         /*
3539          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
3540          */
3541     resizeTabs : false,
3542         /*
3543          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
3544          */
3545     monitorResize : true,
3546
3547     /**
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
3554      */
3555     addTab : function(id, text, content, closable){
3556         var item = new Roo.TabPanelItem(this, id, text, closable);
3557         this.addTabItem(item);
3558         if(content){
3559             item.setContent(content);
3560         }
3561         return item;
3562     },
3563
3564     /**
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}
3568      */
3569     getTab : function(id){
3570         return this.items[id];
3571     },
3572
3573     /**
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.
3576      */
3577     hideTab : function(id){
3578         var t = this.items[id];
3579         if(!t.isHidden()){
3580            t.setHidden(true);
3581            this.hiddenCount++;
3582            this.autoSizeTabs();
3583         }
3584     },
3585
3586     /**
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.
3589      */
3590     unhideTab : function(id){
3591         var t = this.items[id];
3592         if(t.isHidden()){
3593            t.setHidden(false);
3594            this.hiddenCount--;
3595            this.autoSizeTabs();
3596         }
3597     },
3598
3599     /**
3600      * Adds an existing {@link Roo.TabPanelItem}.
3601      * @param {Roo.TabPanelItem} item The TabPanelItem to add
3602      */
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();
3609         }else{
3610             item.autoSize();
3611         }
3612     },
3613
3614     /**
3615      * Removes a {@link Roo.TabPanelItem}.
3616      * @param {String/Number} id The id or index of the TabPanelItem to remove.
3617      */
3618     removeTab : function(id){
3619         var items = this.items;
3620         var tab = items[id];
3621         if(!tab) return;
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();
3626         }
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);
3630         }
3631         items.splice(index, 1);
3632         delete this.items[tab.id];
3633         tab.fireEvent("close", tab);
3634         tab.purgeListeners();
3635         this.autoSizeTabs();
3636     },
3637
3638     getNextAvailable : function(start){
3639         var items = this.items;
3640         var index = start;
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()){
3646                 return item;
3647             }
3648         }
3649         // if one isn't found select the previous tab (on the left)
3650         index = start;
3651         while(index >= 0){
3652             var item = items[--index];
3653             if(item && !item.isHidden()){
3654                 return item;
3655             }
3656         }
3657         return null;
3658     },
3659
3660     /**
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.
3663      */
3664     disableTab : function(id){
3665         var tab = this.items[id];
3666         if(tab && this.active != tab){
3667             tab.disable();
3668         }
3669     },
3670
3671     /**
3672      * Enables a {@link Roo.TabPanelItem} that is disabled.
3673      * @param {String/Number} id The id or index of the TabPanelItem to enable.
3674      */
3675     enableTab : function(id){
3676         var tab = this.items[id];
3677         tab.enable();
3678     },
3679
3680     /**
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.
3684      */
3685     activate : function(id){
3686         var tab = this.items[id];
3687         if(!tab){
3688             return null;
3689         }
3690         if(tab == this.active || tab.disabled){
3691             return tab;
3692         }
3693         var e = {};
3694         this.fireEvent("beforetabchange", this, e, tab);
3695         if(e.cancel !== true && !tab.disabled){
3696             if(this.active){
3697                 this.active.hide();
3698             }
3699             this.active = this.items[id];
3700             this.active.show();
3701             this.fireEvent("tabchange", this, this.active);
3702         }
3703         return tab;
3704     },
3705
3706     /**
3707      * Gets the active {@link Roo.TabPanelItem}.
3708      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
3709      */
3710     getActiveTab : function(){
3711         return this.active;
3712     },
3713
3714     /**
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
3718      */
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);
3724         return newHeight;
3725     },
3726
3727     onResize : function(){
3728         if(this.monitorResize){
3729             this.autoSizeTabs();
3730         }
3731     },
3732
3733     /**
3734      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
3735      */
3736     beginUpdate : function(){
3737         this.updating = true;
3738     },
3739
3740     /**
3741      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
3742      */
3743     endUpdate : function(){
3744         this.updating = false;
3745         this.autoSizeTabs();
3746     },
3747
3748     /**
3749      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
3750      */
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();
3764                 }
3765                 this.showScroll();
3766                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
3767             }
3768         }else{
3769             if(this.currentTabWidth < this.preferredTabWidth){
3770                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
3771             }
3772         }
3773     },
3774
3775     /**
3776      * Returns the number of tabs in this TabPanel.
3777      * @return {Number}
3778      */
3779      getCount : function(){
3780          return this.items.length;
3781      },
3782
3783     /**
3784      * Resizes all the tabs to the passed width
3785      * @param {Number} The new width
3786      */
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);
3791         }
3792     },
3793
3794     /**
3795      * Destroys this TabPanel
3796      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
3797      */
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();
3802         }
3803         if(removeEl === true){
3804             this.el.update("");
3805             this.el.remove();
3806         }
3807     }
3808 });
3809
3810 /**
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)
3818  */
3819 Roo.TabPanelItem = function(tabPanel, id, text, closable){
3820     /**
3821      * The {@link Roo.TabPanel} this TabPanelItem belongs to
3822      * @type Roo.TabPanel
3823      */
3824     this.tabPanel = tabPanel;
3825     /**
3826      * The id for this TabPanelItem
3827      * @type String
3828      */
3829     this.id = id;
3830     /** @private */
3831     this.disabled = false;
3832     /** @private */
3833     this.text = text;
3834     /** @private */
3835     this.loaded = false;
3836     this.closable = closable;
3837
3838     /**
3839      * The body element for this TabPanelItem.
3840      * @type Roo.Element
3841      */
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");
3846     this.hideAction();
3847
3848     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
3849     /** @private */
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);
3856     /** @private */
3857     if(closable){
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);
3862      }
3863
3864     this.addEvents({
3865          /**
3866          * @event activate
3867          * Fires when this tab becomes the active tab.
3868          * @param {Roo.TabPanel} tabPanel The parent TabPanel
3869          * @param {Roo.TabPanelItem} this
3870          */
3871         "activate": true,
3872         /**
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.
3877          */
3878         "beforeclose": true,
3879         /**
3880          * @event close
3881          * Fires when this tab is closed.
3882          * @param {Roo.TabPanelItem} this
3883          */
3884          "close": true,
3885         /**
3886          * @event deactivate
3887          * Fires when this tab is no longer the active tab.
3888          * @param {Roo.TabPanel} tabPanel The parent TabPanel
3889          * @param {Roo.TabPanelItem} this
3890          */
3891          "deactivate" : true
3892     });
3893     this.hidden = false;
3894
3895     Roo.TabPanelItem.superclass.constructor.call(this);
3896 };
3897
3898 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
3899     purgeListeners : function(){
3900        Roo.util.Observable.prototype.purgeListeners.call(this);
3901        this.el.removeAllListeners();
3902     },
3903     /**
3904      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
3905      */
3906     show : function(){
3907         this.pnode.addClass("on");
3908         this.showAction();
3909         if(Roo.isOpera){
3910             this.tabPanel.stripWrap.repaint();
3911         }
3912         this.fireEvent("activate", this.tabPanel, this);
3913     },
3914
3915     /**
3916      * Returns true if this tab is the active tab.
3917      * @return {Boolean}
3918      */
3919     isActive : function(){
3920         return this.tabPanel.getActiveTab() == this;
3921     },
3922
3923     /**
3924      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
3925      */
3926     hide : function(){
3927         this.pnode.removeClass("on");
3928         this.hideAction();
3929         this.fireEvent("deactivate", this.tabPanel, this);
3930     },
3931
3932     hideAction : function(){
3933         this.bodyEl.hide();
3934         this.bodyEl.setStyle("position", "absolute");
3935         this.bodyEl.setLeft("-20000px");
3936         this.bodyEl.setTop("-20000px");
3937     },
3938
3939     showAction : function(){
3940         this.bodyEl.setStyle("position", "relative");
3941         this.bodyEl.setTop("");
3942         this.bodyEl.setLeft("");
3943         this.bodyEl.show();
3944     },
3945
3946     /**
3947      * Set the tooltip for the tab.
3948      * @param {String} tooltip The tab's tooltip
3949      */
3950     setTooltip : function(text){
3951         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
3952             this.textEl.dom.qtip = text;
3953             this.textEl.dom.removeAttribute('title');
3954         }else{
3955             this.textEl.dom.title = text;
3956         }
3957     },
3958
3959     onTabClick : function(e){
3960         e.preventDefault();
3961         this.tabPanel.activate(this.id);
3962     },
3963
3964     onTabMouseDown : function(e){
3965         e.preventDefault();
3966         this.tabPanel.activate(this.id);
3967     },
3968
3969     getWidth : function(){
3970         return this.inner.getWidth();
3971     },
3972
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);
3978     },
3979
3980     /**
3981      * Show or hide the tab
3982      * @param {Boolean} hidden True to hide or false to show.
3983      */
3984     setHidden : function(hidden){
3985         this.hidden = hidden;
3986         this.pnode.setStyle("display", hidden ? "none" : "");
3987     },
3988
3989     /**
3990      * Returns true if this tab is "hidden"
3991      * @return {Boolean}
3992      */
3993     isHidden : function(){
3994         return this.hidden;
3995     },
3996
3997     /**
3998      * Returns the text for this tab
3999      * @return {String}
4000      */
4001     getText : function(){
4002         return this.text;
4003     },
4004
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();
4010     },
4011
4012     /**
4013      * Sets the text for the tab (Note: this also sets the tooltip text)
4014      * @param {String} text The tab's text and tooltip
4015      */
4016     setText : function(text){
4017         this.text = text;
4018         this.textEl.update(text);
4019         this.setTooltip(text);
4020         if(!this.tabPanel.resizeTabs){
4021             this.autoSize();
4022         }
4023     },
4024     /**
4025      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
4026      */
4027     activate : function(){
4028         this.tabPanel.activate(this.id);
4029     },
4030
4031     /**
4032      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
4033      */
4034     disable : function(){
4035         if(this.tabPanel.active != this){
4036             this.disabled = true;
4037             this.pnode.addClass("disabled");
4038         }
4039     },
4040
4041     /**
4042      * Enables this TabPanelItem if it was previously disabled.
4043      */
4044     enable : function(){
4045         this.disabled = false;
4046         this.pnode.removeClass("disabled");
4047     },
4048
4049     /**
4050      * Sets the content for this TabPanelItem.
4051      * @param {String} content The content
4052      * @param {Boolean} loadScripts true to look for and load scripts
4053      */
4054     setContent : function(content, loadScripts){
4055         this.bodyEl.update(content, loadScripts);
4056     },
4057
4058     /**
4059      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
4060      * @return {Roo.UpdateManager} The UpdateManager
4061      */
4062     getUpdateManager : function(){
4063         return this.bodyEl.getUpdateManager();
4064     },
4065
4066     /**
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
4072      */
4073     setUrl : function(url, params, loadOnce){
4074         if(this.refreshDelegate){
4075             this.un('activate', this.refreshDelegate);
4076         }
4077         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
4078         this.on("activate", this.refreshDelegate);
4079         return this.bodyEl.getUpdateManager();
4080     },
4081
4082     /** @private */
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));
4087         }
4088     },
4089
4090     /**
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.
4094      */
4095     refresh : function(){
4096         if(this.refreshDelegate){
4097            this.loaded = false;
4098            this.refreshDelegate();
4099         }
4100     },
4101
4102     /** @private */
4103     _setLoaded : function(){
4104         this.loaded = true;
4105     },
4106
4107     /** @private */
4108     closeClick : function(e){
4109         var o = {};
4110         e.stopEvent();
4111         this.fireEvent("beforeclose", this, o);
4112         if(o.cancel !== true){
4113             this.tabPanel.removeTab(this.id);
4114         }
4115     },
4116     /**
4117      * The text displayed in the tooltip for the close icon.
4118      * @type String
4119      */
4120     closeText : "Close this tab"
4121 });
4122
4123 /** @private */
4124 Roo.TabPanel.prototype.createStrip = function(container){
4125     var strip = document.createElement("div");
4126     strip.className = "x-tabs-wrap";
4127     container.appendChild(strip);
4128     return strip;
4129 };
4130 /** @private */
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;
4135 };
4136 /** @private */
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);
4142     return body;
4143 };
4144 /** @private */
4145 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
4146     var body = Roo.getDom(id);
4147     if(!body){
4148         body = document.createElement("div");
4149         body.id = id;
4150     }
4151     Roo.fly(body).addClass("x-tabs-item-body");
4152     bodyEl.insertBefore(body, bodyEl.firstChild);
4153     return body;
4154 };
4155 /** @private */
4156 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
4157     var td = document.createElement("td");
4158     stripEl.appendChild(td);
4159     if(closable){
4160         td.className = "x-tabs-closable";
4161         if(!this.closeTpl){
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">&#160;</div></em></span></a>'
4166             );
4167         }
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};
4172     } else {
4173         if(!this.tabTpl){
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>'
4177             );
4178         }
4179         var el = this.tabTpl.overwrite(td, {"text": text});
4180         var inner = el.getElementsByTagName("em")[0];
4181         return {"el": el, "inner": inner};
4182     }
4183 };/*
4184  * Based on:
4185  * Ext JS Library 1.1.1
4186  * Copyright(c) 2006-2007, Ext JS, LLC.
4187  *
4188  * Originally Released Under LGPL - original licence link has changed is not relivant.
4189  *
4190  * Fork - LGPL
4191  * <script type="text/javascript">
4192  */
4193
4194 /**
4195  * @class Roo.Button
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).
4213  * @constructor
4214  * Create a new button
4215  * @param {Object} config The config object
4216  */
4217 Roo.Button = function(renderTo, config)
4218 {
4219     if (!config) {
4220         config = renderTo;
4221         renderTo = config.renderTo || false;
4222     }
4223     
4224     Roo.apply(this, config);
4225     this.addEvents({
4226         /**
4227              * @event click
4228              * Fires when this button is clicked
4229              * @param {Button} this
4230              * @param {EventObject} e The click event
4231              */
4232             "click" : true,
4233         /**
4234              * @event toggle
4235              * Fires when the "pressed" state of this button changes (only if enableToggle = true)
4236              * @param {Button} this
4237              * @param {Boolean} pressed
4238              */
4239             "toggle" : true,
4240         /**
4241              * @event mouseover
4242              * Fires when the mouse hovers over the button
4243              * @param {Button} this
4244              * @param {Event} e The event object
4245              */
4246         'mouseover' : true,
4247         /**
4248              * @event mouseout
4249              * Fires when the mouse exits the button
4250              * @param {Button} this
4251              * @param {Event} e The event object
4252              */
4253         'mouseout': true,
4254          /**
4255              * @event render
4256              * Fires when the button is rendered
4257              * @param {Button} this
4258              */
4259         'render': true
4260     });
4261     if(this.menu){
4262         this.menu = Roo.menu.MenuMgr.get(this.menu);
4263     }
4264     if(renderTo){
4265         this.render(renderTo);
4266     }
4267     
4268     Roo.util.Observable.call(this);
4269 };
4270
4271 Roo.extend(Roo.Button, Roo.util.Observable, {
4272     /**
4273      * 
4274      */
4275     
4276     /**
4277      * Read-only. True if this button is hidden
4278      * @type Boolean
4279      */
4280     hidden : false,
4281     /**
4282      * Read-only. True if this button is disabled
4283      * @type Boolean
4284      */
4285     disabled : false,
4286     /**
4287      * Read-only. True if this button is pressed (only if enableToggle = true)
4288      * @type Boolean
4289      */
4290     pressed : false,
4291
4292     /**
4293      * @cfg {Number} tabIndex 
4294      * The DOM tabIndex for this button (defaults to undefined)
4295      */
4296     tabIndex : undefined,
4297
4298     /**
4299      * @cfg {Boolean} enableToggle
4300      * True to enable pressed/not pressed toggling (defaults to false)
4301      */
4302     enableToggle: false,
4303     /**
4304      * @cfg {Mixed} menu
4305      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
4306      */
4307     menu : undefined,
4308     /**
4309      * @cfg {String} menuAlign
4310      * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
4311      */
4312     menuAlign : "tl-bl?",
4313
4314     /**
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).
4317      */
4318     iconCls : undefined,
4319     /**
4320      * @cfg {String} type
4321      * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
4322      */
4323     type : 'button',
4324
4325     // private
4326     menuClassTarget: 'tr',
4327
4328     /**
4329      * @cfg {String} clickEvent
4330      * The type of event to map to the button's event handler (defaults to 'click')
4331      */
4332     clickEvent : 'click',
4333
4334     /**
4335      * @cfg {Boolean} handleMouseEvents
4336      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
4337      */
4338     handleMouseEvents : true,
4339
4340     /**
4341      * @cfg {String} tooltipType
4342      * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
4343      */
4344     tooltipType : 'qtip',
4345
4346     /**
4347      * @cfg {String} cls
4348      * A CSS class to apply to the button's main element.
4349      */
4350     
4351     /**
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.
4356      */
4357
4358     // private
4359     render : function(renderTo){
4360         var btn;
4361         if(this.hideParent){
4362             this.parentEl = Roo.get(renderTo);
4363         }
4364         if(!this.dhconfig){
4365             if(!this.template){
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>&#160;</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>&#160;</i></td>',
4371                         "</tr></tbody></table>");
4372                 }
4373                 this.template = Roo.Button.buttonTemplate;
4374             }
4375             btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
4376             var btnEl = btn.child("button:first");
4377             btnEl.on('focus', this.onFocus, this);
4378             btnEl.on('blur', this.onBlur, this);
4379             if(this.cls){
4380                 btn.addClass(this.cls);
4381             }
4382             if(this.icon){
4383                 btnEl.setStyle('background-image', 'url(' +this.icon +')');
4384             }
4385             if(this.iconCls){
4386                 btnEl.addClass(this.iconCls);
4387                 if(!this.cls){
4388                     btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
4389                 }
4390             }
4391             if(this.tabIndex !== undefined){
4392                 btnEl.dom.tabIndex = this.tabIndex;
4393             }
4394             if(this.tooltip){
4395                 if(typeof this.tooltip == 'object'){
4396                     Roo.QuickTips.tips(Roo.apply({
4397                           target: btnEl.id
4398                     }, this.tooltip));
4399                 } else {
4400                     btnEl.dom[this.tooltipType] = this.tooltip;
4401                 }
4402             }
4403         }else{
4404             btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
4405         }
4406         this.el = btn;
4407         if(this.id){
4408             this.el.dom.id = this.el.id = this.id;
4409         }
4410         if(this.menu){
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);
4414         }
4415         btn.addClass("x-btn");
4416         if(Roo.isIE && !Roo.isIE7){
4417             this.autoWidth.defer(1, this);
4418         }else{
4419             this.autoWidth();
4420         }
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);
4425         }
4426         btn.on(this.clickEvent, this.onClick, this);
4427         //btn.on("mouseup", this.onMouseUp, this);
4428         if(this.hidden){
4429             this.hide();
4430         }
4431         if(this.disabled){
4432             this.disable();
4433         }
4434         Roo.ButtonToggleMgr.register(this);
4435         if(this.pressed){
4436             this.el.addClass("x-btn-pressed");
4437         }
4438         if(this.repeat){
4439             var repeater = new Roo.util.ClickRepeater(btn,
4440                 typeof this.repeat == "object" ? this.repeat : {}
4441             );
4442             repeater.on("click", this.onClick,  this);
4443         }
4444         this.fireEvent('render', this);
4445         
4446     },
4447     /**
4448      * Returns the button's underlying element
4449      * @return {Roo.Element} The element
4450      */
4451     getEl : function(){
4452         return this.el;  
4453     },
4454     
4455     /**
4456      * Destroys this Button and removes any listeners.
4457      */
4458     destroy : function(){
4459         Roo.ButtonToggleMgr.unregister(this);
4460         this.el.removeAllListeners();
4461         this.purgeListeners();
4462         this.el.remove();
4463     },
4464
4465     // private
4466     autoWidth : function(){
4467         if(this.el){
4468             this.el.setWidth("auto");
4469             if(Roo.isIE7 && Roo.isStrict){
4470                 var ib = this.el.child('button');
4471                 if(ib && ib.getWidth() > 20){
4472                     ib.clip();
4473                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
4474                 }
4475             }
4476             if(this.minWidth){
4477                 if(this.hidden){
4478                     this.el.beginMeasure();
4479                 }
4480                 if(this.el.getWidth() < this.minWidth){
4481                     this.el.setWidth(this.minWidth);
4482                 }
4483                 if(this.hidden){
4484                     this.el.endMeasure();
4485                 }
4486             }
4487         }
4488     },
4489
4490     /**
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
4494      */
4495     setHandler : function(handler, scope){
4496         this.handler = handler;
4497         this.scope = scope;  
4498     },
4499     
4500     /**
4501      * Sets this button's text
4502      * @param {String} text The button text
4503      */
4504     setText : function(text){
4505         this.text = text;
4506         if(this.el){
4507             this.el.child("td.x-btn-center button.x-btn-text").update(text);
4508         }
4509         this.autoWidth();
4510     },
4511     
4512     /**
4513      * Gets the text for this button
4514      * @return {String} The button text
4515      */
4516     getText : function(){
4517         return this.text;  
4518     },
4519     
4520     /**
4521      * Show this button
4522      */
4523     show: function(){
4524         this.hidden = false;
4525         if(this.el){
4526             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
4527         }
4528     },
4529     
4530     /**
4531      * Hide this button
4532      */
4533     hide: function(){
4534         this.hidden = true;
4535         if(this.el){
4536             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
4537         }
4538     },
4539     
4540     /**
4541      * Convenience function for boolean show/hide
4542      * @param {Boolean} visible True to show, false to hide
4543      */
4544     setVisible: function(visible){
4545         if(visible) {
4546             this.show();
4547         }else{
4548             this.hide();
4549         }
4550     },
4551     
4552     /**
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
4555      */
4556     toggle : function(state){
4557         state = state === undefined ? !this.pressed : state;
4558         if(state != this.pressed){
4559             if(state){
4560                 this.el.addClass("x-btn-pressed");
4561                 this.pressed = true;
4562                 this.fireEvent("toggle", this, true);
4563             }else{
4564                 this.el.removeClass("x-btn-pressed");
4565                 this.pressed = false;
4566                 this.fireEvent("toggle", this, false);
4567             }
4568             if(this.toggleHandler){
4569                 this.toggleHandler.call(this.scope || this, this, state);
4570             }
4571         }
4572     },
4573     
4574     /**
4575      * Focus the button
4576      */
4577     focus : function(){
4578         this.el.child('button:first').focus();
4579     },
4580     
4581     /**
4582      * Disable this button
4583      */
4584     disable : function(){
4585         if(this.el){
4586             this.el.addClass("x-btn-disabled");
4587         }
4588         this.disabled = true;
4589     },
4590     
4591     /**
4592      * Enable this button
4593      */
4594     enable : function(){
4595         if(this.el){
4596             this.el.removeClass("x-btn-disabled");
4597         }
4598         this.disabled = false;
4599     },
4600
4601     /**
4602      * Convenience function for boolean enable/disable
4603      * @param {Boolean} enabled True to enable, false to disable
4604      */
4605     setDisabled : function(v){
4606         this[v !== true ? "enable" : "disable"]();
4607     },
4608
4609     // private
4610     onClick : function(e){
4611         if(e){
4612             e.preventDefault();
4613         }
4614         if(e.button != 0){
4615             return;
4616         }
4617         if(!this.disabled){
4618             if(this.enableToggle){
4619                 this.toggle();
4620             }
4621             if(this.menu && !this.menu.isVisible()){
4622                 this.menu.show(this.el, this.menuAlign);
4623             }
4624             this.fireEvent("click", this, e);
4625             if(this.handler){
4626                 this.el.removeClass("x-btn-over");
4627                 this.handler.call(this.scope || this, this, e);
4628             }
4629         }
4630     },
4631     // private
4632     onMouseOver : function(e){
4633         if(!this.disabled){
4634             this.el.addClass("x-btn-over");
4635             this.fireEvent('mouseover', this, e);
4636         }
4637     },
4638     // private
4639     onMouseOut : function(e){
4640         if(!e.within(this.el,  true)){
4641             this.el.removeClass("x-btn-over");
4642             this.fireEvent('mouseout', this, e);
4643         }
4644     },
4645     // private
4646     onFocus : function(e){
4647         if(!this.disabled){
4648             this.el.addClass("x-btn-focus");
4649         }
4650     },
4651     // private
4652     onBlur : function(e){
4653         this.el.removeClass("x-btn-focus");
4654     },
4655     // private
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);
4660         }
4661     },
4662     // private
4663     onMouseUp : function(e){
4664         if(e.button == 0){
4665             this.el.removeClass("x-btn-click");
4666             Roo.get(document).un('mouseup', this.onMouseUp, this);
4667         }
4668     },
4669     // private
4670     onMenuShow : function(e){
4671         this.el.addClass("x-btn-menu-active");
4672     },
4673     // private
4674     onMenuHide : function(e){
4675         this.el.removeClass("x-btn-menu-active");
4676     }   
4677 });
4678
4679 // Private utility class used by Button
4680 Roo.ButtonToggleMgr = function(){
4681    var groups = {};
4682    
4683    function toggleGroup(btn, state){
4684        if(state){
4685            var g = groups[btn.toggleGroup];
4686            for(var i = 0, l = g.length; i < l; i++){
4687                if(g[i] != btn){
4688                    g[i].toggle(false);
4689                }
4690            }
4691        }
4692    }
4693    
4694    return {
4695        register : function(btn){
4696            if(!btn.toggleGroup){
4697                return;
4698            }
4699            var g = groups[btn.toggleGroup];
4700            if(!g){
4701                g = groups[btn.toggleGroup] = [];
4702            }
4703            g.push(btn);
4704            btn.on("toggle", toggleGroup);
4705        },
4706        
4707        unregister : function(btn){
4708            if(!btn.toggleGroup){
4709                return;
4710            }
4711            var g = groups[btn.toggleGroup];
4712            if(g){
4713                g.remove(btn);
4714                btn.un("toggle", toggleGroup);
4715            }
4716        }
4717    };
4718 }();/*
4719  * Based on:
4720  * Ext JS Library 1.1.1
4721  * Copyright(c) 2006-2007, Ext JS, LLC.
4722  *
4723  * Originally Released Under LGPL - original licence link has changed is not relivant.
4724  *
4725  * Fork - LGPL
4726  * <script type="text/javascript">
4727  */
4728  
4729 /**
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
4737  * @constructor
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
4741  */
4742 Roo.SplitButton = function(renderTo, config){
4743     Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
4744     /**
4745      * @event arrowclick
4746      * Fires when this button's arrow is clicked
4747      * @param {SplitButton} this
4748      * @param {EventObject} e The click event
4749      */
4750     this.addEvents({"arrowclick":true});
4751 };
4752
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>&#160;</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">&#160;</button></td><td class="x-btn-right"><i>&#160;</i></td></tr>',
4763             "</tbody></table></td></tr></table>"
4764         );
4765         var btn = tpl.append(renderTo, [this.text, this.type], true);
4766         var btnEl = btn.child("button");
4767         if(this.cls){
4768             btn.addClass(this.cls);
4769         }
4770         if(this.icon){
4771             btnEl.setStyle('background-image', 'url(' +this.icon +')');
4772         }
4773         if(this.iconCls){
4774             btnEl.addClass(this.iconCls);
4775             if(!this.cls){
4776                 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
4777             }
4778         }
4779         this.el = btn;
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);
4785         }
4786         btn.on(this.clickEvent, this.onClick, this);
4787         if(this.tooltip){
4788             if(typeof this.tooltip == 'object'){
4789                 Roo.QuickTips.tips(Roo.apply({
4790                       target: btnEl.id
4791                 }, this.tooltip));
4792             } else {
4793                 btnEl.dom[this.tooltipType] = this.tooltip;
4794             }
4795         }
4796         if(this.arrowTooltip){
4797             btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
4798         }
4799         if(this.hidden){
4800             this.hide();
4801         }
4802         if(this.disabled){
4803             this.disable();
4804         }
4805         if(this.pressed){
4806             this.el.addClass("x-btn-pressed");
4807         }
4808         if(Roo.isIE && !Roo.isIE7){
4809             this.autoWidth.defer(1, this);
4810         }else{
4811             this.autoWidth();
4812         }
4813         if(this.menu){
4814             this.menu.on("show", this.onMenuShow, this);
4815             this.menu.on("hide", this.onMenuHide, this);
4816         }
4817         this.fireEvent('render', this);
4818     },
4819
4820     // private
4821     autoWidth : function(){
4822         if(this.el){
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){
4830                     ib.clip();
4831                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
4832                 }
4833             }
4834             if(this.minWidth){
4835                 if(this.hidden){
4836                     this.el.beginMeasure();
4837                 }
4838                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
4839                     tbl.setWidth(this.minWidth-tbl2.getWidth());
4840                 }
4841                 if(this.hidden){
4842                     this.el.endMeasure();
4843                 }
4844             }
4845             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
4846         } 
4847     },
4848     /**
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
4852      */
4853     setHandler : function(handler, scope){
4854         this.handler = handler;
4855         this.scope = scope;  
4856     },
4857     
4858     /**
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
4862      */
4863     setArrowHandler : function(handler, scope){
4864         this.arrowHandler = handler;
4865         this.scope = scope;  
4866     },
4867     
4868     /**
4869      * Focus the button
4870      */
4871     focus : function(){
4872         if(this.el){
4873             this.el.child("button:first").focus();
4874         }
4875     },
4876
4877     // private
4878     onClick : function(e){
4879         e.preventDefault();
4880         if(!this.disabled){
4881             if(e.getTarget(".x-btn-menu-arrow-wrap")){
4882                 if(this.menu && !this.menu.isVisible()){
4883                     this.menu.show(this.el, this.menuAlign);
4884                 }
4885                 this.fireEvent("arrowclick", this, e);
4886                 if(this.arrowHandler){
4887                     this.arrowHandler.call(this.scope || this, this, e);
4888                 }
4889             }else{
4890                 this.fireEvent("click", this, e);
4891                 if(this.handler){
4892                     this.handler.call(this.scope || this, this, e);
4893                 }
4894             }
4895         }
4896     },
4897     // private
4898     onMouseDown : function(e){
4899         if(!this.disabled){
4900             Roo.fly(e.getTarget("table")).addClass("x-btn-click");
4901         }
4902     },
4903     // private
4904     onMouseUp : function(e){
4905         Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
4906     }   
4907 });
4908
4909
4910 // backwards compat
4911 Roo.MenuButton = Roo.SplitButton;/*
4912  * Based on:
4913  * Ext JS Library 1.1.1
4914  * Copyright(c) 2006-2007, Ext JS, LLC.
4915  *
4916  * Originally Released Under LGPL - original licence link has changed is not relivant.
4917  *
4918  * Fork - LGPL
4919  * <script type="text/javascript">
4920  */
4921
4922 /**
4923  * @class Roo.Toolbar
4924  * Basic Toolbar class.
4925  * @constructor
4926  * Creates a new Toolbar
4927  * @param {Object} config The config object
4928  */ 
4929 Roo.Toolbar = function(container, buttons, config)
4930 {
4931     /// old consturctor format still supported..
4932     if(container instanceof Array){ // omit the container for later rendering
4933         buttons = container;
4934         config = buttons;
4935         container = null;
4936     }
4937     if (typeof(container) == 'object' && container.xtype) {
4938         config = container;
4939         container = config.container;
4940         buttons = config.buttons; // not really - use items!!
4941     }
4942     var xitems = [];
4943     if (config && config.items) {
4944         xitems = config.items;
4945         delete config.items;
4946     }
4947     Roo.apply(this, config);
4948     this.buttons = buttons;
4949     
4950     if(container){
4951         this.render(container);
4952     }
4953     Roo.each(xitems, function(b) {
4954         this.add(b);
4955     }, this);
4956     
4957 };
4958
4959 Roo.Toolbar.prototype = {
4960     /**
4961      * @cfg {Roo.data.Store} items
4962      * array of button configs or elements to add
4963      */
4964     
4965     /**
4966      * @cfg {String/HTMLElement/Element} container
4967      * The id or element that will contain the toolbar
4968      */
4969     // private
4970     render : function(ct){
4971         this.el = Roo.get(ct);
4972         if(this.cls){
4973             this.el.addClass(this.cls);
4974         }
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);
4979         var autoId = 0;
4980         this.items = new Roo.util.MixedCollection(false, function(o){
4981             return o.id || ("item" + (++autoId));
4982         });
4983         if(this.buttons){
4984             this.add.apply(this, this.buttons);
4985             delete this.buttons;
4986         }
4987     },
4988
4989     /**
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 />
4993      * <ul>
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>
5003      * </ul>
5004      * @param {Mixed} arg2
5005      * @param {Mixed} etc.
5006      */
5007     add : function(){
5008         var a = arguments, l = a.length;
5009         for(var i = 0; i < l; i++){
5010             this._add(a[i]);
5011         }
5012     },
5013     // private..
5014     _add : function(el) {
5015         
5016         if (el.xtype) {
5017             el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
5018         }
5019         
5020         if (el.applyTo){ // some kind of form field
5021             return this.addField(el);
5022         } 
5023         if (el.render){ // some kind of Toolbar.Item
5024             return this.addItem(el);
5025         }
5026         if (typeof el == "string"){ // string
5027             if(el == "separator" || el == "-"){
5028                 return this.addSeparator();
5029             }
5030             if (el == " "){
5031                 return this.addSpacer();
5032             }
5033             if(el == "->"){
5034                 return this.addFill();
5035             }
5036             return this.addText(el);
5037             
5038         }
5039         if(el.tagName){ // element
5040             return this.addElement(el);
5041         }
5042         if(typeof el == "object"){ // must be button config?
5043             return this.addButton(el);
5044         }
5045         // and now what?!?!
5046         return false;
5047         
5048     },
5049     
5050     /**
5051      * Add an Xtype element
5052      * @param {Object} xtype Xtype Object
5053      * @return {Object} created Object
5054      */
5055     addxtype : function(e){
5056         return this.add(e);  
5057     },
5058     
5059     /**
5060      * Returns the Element for this toolbar.
5061      * @return {Roo.Element}
5062      */
5063     getEl : function(){
5064         return this.el;  
5065     },
5066     
5067     /**
5068      * Adds a separator
5069      * @return {Roo.Toolbar.Item} The separator item
5070      */
5071     addSeparator : function(){
5072         return this.addItem(new Roo.Toolbar.Separator());
5073     },
5074
5075     /**
5076      * Adds a spacer element
5077      * @return {Roo.Toolbar.Spacer} The spacer item
5078      */
5079     addSpacer : function(){
5080         return this.addItem(new Roo.Toolbar.Spacer());
5081     },
5082
5083     /**
5084      * Adds a fill element that forces subsequent additions to the right side of the toolbar
5085      * @return {Roo.Toolbar.Fill} The fill item
5086      */
5087     addFill : function(){
5088         return this.addItem(new Roo.Toolbar.Fill());
5089     },
5090
5091     /**
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
5095      */
5096     addElement : function(el){
5097         return this.addItem(new Roo.Toolbar.Item(el));
5098     },
5099     /**
5100      * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
5101      * @type Roo.util.MixedCollection  
5102      */
5103     items : false,
5104      
5105     /**
5106      * Adds any Toolbar.Item or subclass
5107      * @param {Roo.Toolbar.Item} item
5108      * @return {Roo.Toolbar.Item} The item
5109      */
5110     addItem : function(item){
5111         var td = this.nextBlock();
5112         item.render(td);
5113         this.items.add(item);
5114         return item;
5115     },
5116     
5117     /**
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}
5121      */
5122     addButton : function(config){
5123         if(config instanceof Array){
5124             var buttons = [];
5125             for(var i = 0, len = config.length; i < len; i++) {
5126                 buttons.push(this.addButton(config[i]));
5127             }
5128             return buttons;
5129         }
5130         var b = config;
5131         if(!(config instanceof Roo.Toolbar.Button)){
5132             b = config.split ?
5133                 new Roo.Toolbar.SplitButton(config) :
5134                 new Roo.Toolbar.Button(config);
5135         }
5136         var td = this.nextBlock();
5137         b.render(td);
5138         this.items.add(b);
5139         return b;
5140     },
5141     
5142     /**
5143      * Adds text to the toolbar
5144      * @param {String} text The text to add
5145      * @return {Roo.Toolbar.Item} The element's item
5146      */
5147     addText : function(text){
5148         return this.addItem(new Roo.Toolbar.TextItem(text));
5149     },
5150     
5151     /**
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}
5156      */
5157     insertButton : function(index, item){
5158         if(item instanceof Array){
5159             var buttons = [];
5160             for(var i = 0, len = item.length; i < len; i++) {
5161                buttons.push(this.insertButton(index + i, item[i]));
5162             }
5163             return buttons;
5164         }
5165         if (!(item instanceof Roo.Toolbar.Button)){
5166            item = new Roo.Toolbar.Button(item);
5167         }
5168         var td = document.createElement("td");
5169         this.tr.insertBefore(td, this.tr.childNodes[index]);
5170         item.render(td);
5171         this.items.insert(index, item);
5172         return item;
5173     },
5174     
5175     /**
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
5179      */
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);
5184         ti.render(td);
5185         this.items.add(ti);
5186         return ti;
5187     },
5188
5189     /**
5190      * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
5191      * @type Roo.util.MixedCollection  
5192      */
5193     fields : false,
5194     
5195     /**
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}
5200      */
5201      
5202       
5203     addField : function(field) {
5204         if (!this.fields) {
5205             var autoId = 0;
5206             this.fields = new Roo.util.MixedCollection(false, function(o){
5207                 return o.id || ("item" + (++autoId));
5208             });
5209
5210         }
5211         
5212         var td = this.nextBlock();
5213         field.render(td);
5214         var ti = new Roo.Toolbar.Item(td.firstChild);
5215         ti.render(td);
5216         this.items.add(ti);
5217         this.fields.add(field);
5218         return ti;
5219     },
5220     /**
5221      * Hide the toolbar
5222      * @method hide
5223      */
5224      
5225       
5226     hide : function()
5227     {
5228         this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
5229         this.el.child('div').hide();
5230     },
5231     /**
5232      * Show the toolbar
5233      * @method show
5234      */
5235     show : function()
5236     {
5237         this.el.child('div').show();
5238     },
5239       
5240     // private
5241     nextBlock : function(){
5242         var td = document.createElement("td");
5243         this.tr.appendChild(td);
5244         return td;
5245     },
5246
5247     // private
5248     destroy : function(){
5249         if(this.items){ // rendered?
5250             Roo.destroy.apply(Roo, this.items.items);
5251         }
5252         if(this.fields){ // rendered?
5253             Roo.destroy.apply(Roo, this.fields.items);
5254         }
5255         Roo.Element.uncache(this.el, this.tr);
5256     }
5257 };
5258
5259 /**
5260  * @class Roo.Toolbar.Item
5261  * The base class that other classes should extend in order to get some basic common toolbar item functionality.
5262  * @constructor
5263  * Creates a new Item
5264  * @param {HTMLElement} el 
5265  */
5266 Roo.Toolbar.Item = function(el){
5267     this.el = Roo.getDom(el);
5268     this.id = Roo.id(this.el);
5269     this.hidden = false;
5270 };
5271
5272 Roo.Toolbar.Item.prototype = {
5273     
5274     /**
5275      * Get this item's HTML Element
5276      * @return {HTMLElement}
5277      */
5278     getEl : function(){
5279        return this.el;  
5280     },
5281
5282     // private
5283     render : function(td){
5284         this.td = td;
5285         td.appendChild(this.el);
5286     },
5287     
5288     /**
5289      * Removes and destroys this item.
5290      */
5291     destroy : function(){
5292         this.td.parentNode.removeChild(this.td);
5293     },
5294     
5295     /**
5296      * Shows this item.
5297      */
5298     show: function(){
5299         this.hidden = false;
5300         this.td.style.display = "";
5301     },
5302     
5303     /**
5304      * Hides this item.
5305      */
5306     hide: function(){
5307         this.hidden = true;
5308         this.td.style.display = "none";
5309     },
5310     
5311     /**
5312      * Convenience function for boolean show/hide.
5313      * @param {Boolean} visible true to show/false to hide
5314      */
5315     setVisible: function(visible){
5316         if(visible) {
5317             this.show();
5318         }else{
5319             this.hide();
5320         }
5321     },
5322     
5323     /**
5324      * Try to focus this item.
5325      */
5326     focus : function(){
5327         Roo.fly(this.el).focus();
5328     },
5329     
5330     /**
5331      * Disables this item.
5332      */
5333     disable : function(){
5334         Roo.fly(this.td).addClass("x-item-disabled");
5335         this.disabled = true;
5336         this.el.disabled = true;
5337     },
5338     
5339     /**
5340      * Enables this item.
5341      */
5342     enable : function(){
5343         Roo.fly(this.td).removeClass("x-item-disabled");
5344         this.disabled = false;
5345         this.el.disabled = false;
5346     }
5347 };
5348
5349
5350 /**
5351  * @class Roo.Toolbar.Separator
5352  * @extends Roo.Toolbar.Item
5353  * A simple toolbar separator class
5354  * @constructor
5355  * Creates a new Separator
5356  */
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);
5361 };
5362 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
5363     enable:Roo.emptyFn,
5364     disable:Roo.emptyFn,
5365     focus:Roo.emptyFn
5366 });
5367
5368 /**
5369  * @class Roo.Toolbar.Spacer
5370  * @extends Roo.Toolbar.Item
5371  * A simple element that adds extra horizontal space to a toolbar.
5372  * @constructor
5373  * Creates a new Spacer
5374  */
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);
5379 };
5380 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
5381     enable:Roo.emptyFn,
5382     disable:Roo.emptyFn,
5383     focus:Roo.emptyFn
5384 });
5385
5386 /**
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.
5390  * @constructor
5391  * Creates a new Spacer
5392  */
5393 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
5394     // private
5395     render : function(td){
5396         td.style.width = '100%';
5397         Roo.Toolbar.Fill.superclass.render.call(this, td);
5398     }
5399 });
5400
5401 /**
5402  * @class Roo.Toolbar.TextItem
5403  * @extends Roo.Toolbar.Item
5404  * A simple class that renders text directly into a toolbar.
5405  * @constructor
5406  * Creates a new TextItem
5407  * @param {String} text
5408  */
5409 Roo.Toolbar.TextItem = function(text){
5410     if (typeof(text) == 'object') {
5411         text = text.text;
5412     }
5413     var s = document.createElement("span");
5414     s.className = "ytb-text";
5415     s.innerHTML = text;
5416     Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
5417 };
5418 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
5419     enable:Roo.emptyFn,
5420     disable:Roo.emptyFn,
5421     focus:Roo.emptyFn
5422 });
5423
5424 /**
5425  * @class Roo.Toolbar.Button
5426  * @extends Roo.Button
5427  * A button that renders into a toolbar.
5428  * @constructor
5429  * Creates a new Button
5430  * @param {Object} config A standard {@link Roo.Button} config object
5431  */
5432 Roo.Toolbar.Button = function(config){
5433     Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
5434 };
5435 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
5436     render : function(td){
5437         this.td = td;
5438         Roo.Toolbar.Button.superclass.render.call(this, td);
5439     },
5440     
5441     /**
5442      * Removes and destroys this button
5443      */
5444     destroy : function(){
5445         Roo.Toolbar.Button.superclass.destroy.call(this);
5446         this.td.parentNode.removeChild(this.td);
5447     },
5448     
5449     /**
5450      * Shows this button
5451      */
5452     show: function(){
5453         this.hidden = false;
5454         this.td.style.display = "";
5455     },
5456     
5457     /**
5458      * Hides this button
5459      */
5460     hide: function(){
5461         this.hidden = true;
5462         this.td.style.display = "none";
5463     },
5464
5465     /**
5466      * Disables this item
5467      */
5468     disable : function(){
5469         Roo.fly(this.td).addClass("x-item-disabled");
5470         this.disabled = true;
5471     },
5472
5473     /**
5474      * Enables this item
5475      */
5476     enable : function(){
5477         Roo.fly(this.td).removeClass("x-item-disabled");
5478         this.disabled = false;
5479     }
5480 });
5481 // backwards compat
5482 Roo.ToolbarButton = Roo.Toolbar.Button;
5483
5484 /**
5485  * @class Roo.Toolbar.SplitButton
5486  * @extends Roo.SplitButton
5487  * A menu button that renders into a toolbar.
5488  * @constructor
5489  * Creates a new SplitButton
5490  * @param {Object} config A standard {@link Roo.SplitButton} config object
5491  */
5492 Roo.Toolbar.SplitButton = function(config){
5493     Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
5494 };
5495 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
5496     render : function(td){
5497         this.td = td;
5498         Roo.Toolbar.SplitButton.superclass.render.call(this, td);
5499     },
5500     
5501     /**
5502      * Removes and destroys this button
5503      */
5504     destroy : function(){
5505         Roo.Toolbar.SplitButton.superclass.destroy.call(this);
5506         this.td.parentNode.removeChild(this.td);
5507     },
5508     
5509     /**
5510      * Shows this button
5511      */
5512     show: function(){
5513         this.hidden = false;
5514         this.td.style.display = "";
5515     },
5516     
5517     /**
5518      * Hides this button
5519      */
5520     hide: function(){
5521         this.hidden = true;
5522         this.td.style.display = "none";
5523     }
5524 });
5525
5526 // backwards compat
5527 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
5528  * Based on:
5529  * Ext JS Library 1.1.1
5530  * Copyright(c) 2006-2007, Ext JS, LLC.
5531  *
5532  * Originally Released Under LGPL - original licence link has changed is not relivant.
5533  *
5534  * Fork - LGPL
5535  * <script type="text/javascript">
5536  */
5537  
5538 /**
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.
5542  * @constructor
5543  * Create a new PagingToolbar
5544  * @param {Object} config The config object
5545  */
5546 Roo.PagingToolbar = function(el, ds, config)
5547 {
5548     // old args format still supported... - xtype is prefered..
5549     if (typeof(el) == 'object' && el.xtype) {
5550         // created from xtype...
5551         config = el;
5552         ds = el.dataSource;
5553         el = config.container;
5554     }
5555     
5556     
5557     Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
5558     this.ds = ds;
5559     this.cursor = 0;
5560     this.renderButtons(this.el);
5561     this.bind(ds);
5562 };
5563
5564 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
5565     /**
5566      * @cfg {Roo.data.Store} dataSource
5567      * The underlying data store providing the paged data
5568      */
5569     /**
5570      * @cfg {String/HTMLElement/Element} container
5571      * container The id or element that will contain the toolbar
5572      */
5573     /**
5574      * @cfg {Boolean} displayInfo
5575      * True to display the displayMsg (defaults to false)
5576      */
5577     /**
5578      * @cfg {Number} pageSize
5579      * The number of records to display per page (defaults to 20)
5580      */
5581     pageSize: 20,
5582     /**
5583      * @cfg {String} displayMsg
5584      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
5585      */
5586     displayMsg : 'Displaying {0} - {1} of {2}',
5587     /**
5588      * @cfg {String} emptyMsg
5589      * The message to display when no records are found (defaults to "No data to display")
5590      */
5591     emptyMsg : 'No data to display',
5592     /**
5593      * Customizable piece of the default paging text (defaults to "Page")
5594      * @type String
5595      */
5596     beforePageText : "Page",
5597     /**
5598      * Customizable piece of the default paging text (defaults to "of %0")
5599      * @type String
5600      */
5601     afterPageText : "of {0}",
5602     /**
5603      * Customizable piece of the default paging text (defaults to "First Page")
5604      * @type String
5605      */
5606     firstText : "First Page",
5607     /**
5608      * Customizable piece of the default paging text (defaults to "Previous Page")
5609      * @type String
5610      */
5611     prevText : "Previous Page",
5612     /**
5613      * Customizable piece of the default paging text (defaults to "Next Page")
5614      * @type String
5615      */
5616     nextText : "Next Page",
5617     /**
5618      * Customizable piece of the default paging text (defaults to "Last Page")
5619      * @type String
5620      */
5621     lastText : "Last Page",
5622     /**
5623      * Customizable piece of the default paging text (defaults to "Refresh")
5624      * @type String
5625      */
5626     refreshText : "Refresh",
5627
5628     // private
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",
5634             disabled: true,
5635             handler: this.onClick.createDelegate(this, ["first"])
5636         });
5637         this.prev = this.addButton({
5638             tooltip: this.prevText,
5639             cls: "x-btn-icon x-grid-page-prev",
5640             disabled: true,
5641             handler: this.onClick.createDelegate(this, ["prev"])
5642         });
5643         this.addSeparator();
5644         this.add(this.beforePageText);
5645         this.field = Roo.get(this.addDom({
5646            tag: "input",
5647            type: "text",
5648            size: "3",
5649            value: "1",
5650            cls: "x-grid-page-number"
5651         }).el);
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",
5660             disabled: true,
5661             handler: this.onClick.createDelegate(this, ["next"])
5662         });
5663         this.last = this.addButton({
5664             tooltip: this.lastText,
5665             cls: "x-btn-icon x-grid-page-last",
5666             disabled: true,
5667             handler: this.onClick.createDelegate(this, ["last"])
5668         });
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"])
5674         });
5675
5676         if(this.displayInfo){
5677             this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
5678         }
5679     },
5680
5681     // private
5682     updateInfo : function(){
5683         if(this.displayEl){
5684             var count = this.ds.getCount();
5685             var msg = count == 0 ?
5686                 this.emptyMsg :
5687                 String.format(
5688                     this.displayMsg,
5689                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
5690                 );
5691             this.displayEl.update(msg);
5692         }
5693     },
5694
5695     // private
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;
5699
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();
5707        this.updateInfo();
5708     },
5709
5710     // private
5711     getPageData : function(){
5712         var total = this.ds.getTotalCount();
5713         return {
5714             total : total,
5715             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
5716             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
5717         };
5718     },
5719
5720     // private
5721     onLoadError : function(){
5722         this.loading.enable();
5723     },
5724
5725     // private
5726     onPagingKeydown : function(e){
5727         var k = e.getKey();
5728         var d = this.getPageData();
5729         if(k == e.RETURN){
5730             var v = this.field.dom.value, pageNum;
5731             if(!v || isNaN(pageNum = parseInt(v, 10))){
5732                 this.field.dom.value = d.activePage;
5733                 return;
5734             }
5735             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
5736             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
5737             e.stopEvent();
5738         }
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))
5740         {
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}});
5744           e.stopEvent();
5745         }
5746         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
5747         {
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)
5751             increment *= -1;
5752           if(!v || isNaN(pageNum = parseInt(v, 10))) {
5753             this.field.dom.value = d.activePage;
5754             return;
5755           }
5756           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
5757           {
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}});
5761           }
5762           e.stopEvent();
5763         }
5764     },
5765
5766     // private
5767     beforeLoad : function(){
5768         if(this.loading){
5769             this.loading.disable();
5770         }
5771     },
5772
5773     // private
5774     onClick : function(which){
5775         var ds = this.ds;
5776         switch(which){
5777             case "first":
5778                 ds.load({params:{start: 0, limit: this.pageSize}});
5779             break;
5780             case "prev":
5781                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
5782             break;
5783             case "next":
5784                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
5785             break;
5786             case "last":
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}});
5791             break;
5792             case "refresh":
5793                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
5794             break;
5795         }
5796     },
5797
5798     /**
5799      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
5800      * @param {Roo.data.Store} store The data store to unbind
5801      */
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;
5809     },
5810
5811     /**
5812      * Binds the paging toolbar to the specified {@link Roo.data.Store}
5813      * @param {Roo.data.Store} store The data store to bind
5814      */
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);
5821         this.ds = ds;
5822     }
5823 });/*
5824  * Based on:
5825  * Ext JS Library 1.1.1
5826  * Copyright(c) 2006-2007, Ext JS, LLC.
5827  *
5828  * Originally Released Under LGPL - original licence link has changed is not relivant.
5829  *
5830  * Fork - LGPL
5831  * <script type="text/javascript">
5832  */
5833
5834 /**
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>
5842  * <pre>
5843 Value   Description
5844 ------  -------------------
5845  'n'     north
5846  's'     south
5847  'e'     east
5848  'w'     west
5849  'nw'    northwest
5850  'sw'    southwest
5851  'se'    southeast
5852  'ne'    northeast
5853  'all'   all
5854 </pre>
5855  * <p>Here's an example showing the creation of a typical Resizable:</p>
5856  * <pre><code>
5857 var resizer = new Roo.Resizable("element-id", {
5858     handles: 'all',
5859     minWidth: 200,
5860     minHeight: 100,
5861     maxWidth: 500,
5862     maxHeight: 400,
5863     pinned: true
5864 });
5865 resizer.on("resize", myHandler);
5866 </code></pre>
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)
5897  * @constructor
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
5901   */
5902 Roo.Resizable = function(el, config){
5903     this.el = Roo.get(el);
5904
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);
5915         }
5916         if(config.pinned && !config.adjustments){
5917             config.adjustments = "auto";
5918         }
5919     }
5920
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');
5924
5925     Roo.apply(this, config);
5926
5927     if(this.pinned){
5928         this.disableTrackOver = true;
5929         this.el.addClass("x-resizable-pinned");
5930     }
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");
5935     }
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';
5940         }
5941     }
5942     if(this.handles == "all"){
5943         this.handles = "n s e w ne nw se sw";
5944     }
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);
5951         }
5952     }
5953     // legacy
5954     this.corner = this.southeast;
5955
5956     if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1){
5957         this.updateBox = true;
5958     }
5959
5960     this.activeHandle = null;
5961
5962     if(this.resizeChild){
5963         if(typeof this.resizeChild == "boolean"){
5964             this.resizeChild = Roo.get(this.el.dom.firstChild, true);
5965         }else{
5966             this.resizeChild = Roo.get(this.resizeChild, true);
5967         }
5968     }
5969
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);
5977         }
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
5981         ];
5982     }
5983
5984     if(this.draggable){
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);
5988     }
5989
5990     // public events
5991     this.addEvents({
5992         /**
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
5997          */
5998         "beforeresize" : true,
5999         /**
6000          * @event resize
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
6006          */
6007         "resize" : true
6008     });
6009
6010     if(this.width !== null && this.height !== null){
6011         this.resizeTo(this.width, this.height);
6012     }else{
6013         this.updateChildSize();
6014     }
6015     if(Roo.isIE){
6016         this.el.dom.style.zoom = 1;
6017     }
6018     Roo.Resizable.superclass.constructor.call(this);
6019 };
6020
6021 Roo.extend(Roo.Resizable, Roo.util.Observable, {
6022         resizeChild : false,
6023         adjustments : [0, 0],
6024         minWidth : 5,
6025         minHeight : 5,
6026         maxWidth : 10000,
6027         maxHeight : 10000,
6028         enabled : true,
6029         animate : false,
6030         duration : .35,
6031         dynamic : false,
6032         handles : false,
6033         multiDirectional : false,
6034         disableTrackOver : false,
6035         easing : 'easeOutStrong',
6036         widthIncrement : 0,
6037         heightIncrement : 0,
6038         pinned : false,
6039         width : null,
6040         height : null,
6041         preserveRatio : false,
6042         transparent: false,
6043         minX: 0,
6044         minY: 0,
6045         draggable: false,
6046
6047         /**
6048          * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
6049          */
6050         constrainTo: undefined,
6051         /**
6052          * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
6053          */
6054         resizeRegion: undefined,
6055
6056
6057     /**
6058      * Perform a manual resize
6059      * @param {Number} width
6060      * @param {Number} height
6061      */
6062     resizeTo : function(width, height){
6063         this.el.setSize(width, height);
6064         this.updateChildSize();
6065         this.fireEvent("resize", this, width, height, null);
6066     },
6067
6068     // private
6069     startSizing : function(e, handle){
6070         this.fireEvent("beforeresize", this, e);
6071         if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
6072
6073             if(!this.overlay){
6074                 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: "&#160;"});
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);
6079             }
6080             this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
6081
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]];
6087
6088             this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
6089             this.overlay.show();
6090
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')
6098                 );
6099             }
6100
6101             this.proxy.setStyle('visibility', 'hidden'); // workaround display none
6102             this.proxy.show();
6103             this.proxy.setBox(this.startBox);
6104             if(!this.dynamic){
6105                 this.proxy.setStyle('visibility', 'visible');
6106             }
6107         }
6108     },
6109
6110     // private
6111     onMouseDown : function(handle, e){
6112         if(this.enabled){
6113             e.stopEvent();
6114             this.activeHandle = handle;
6115             this.startSizing(e, handle);
6116         }
6117     },
6118
6119     // private
6120     onMouseUp : function(e){
6121         var size = this.resizeElement();
6122         this.resizing = false;
6123         this.handleOut();
6124         this.overlay.hide();
6125         this.proxy.hide();
6126         this.fireEvent("resize", this, size.width, size.height, e);
6127     },
6128
6129     // private
6130     updateChildSize : function(){
6131         if(this.resizeChild){
6132             var el = this.el;
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]);
6138             }
6139             // Second call here for IE
6140             // The first call enables instant resizing and
6141             // the second call corrects scroll bars if they
6142             // exist
6143             if(Roo.isIE){
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]);
6148                     }
6149                 }, 10);
6150             }
6151         }
6152     },
6153
6154     // private
6155     snap : function(value, inc, min){
6156         if(!inc || !value) return value;
6157         var newValue = value;
6158         var m = value % inc;
6159         if(m > 0){
6160             if(m > (inc/2)){
6161                 newValue = value + (inc-m);
6162             }else{
6163                 newValue = value - m;
6164             }
6165         }
6166         return Math.max(min, newValue);
6167     },
6168
6169     // private
6170     resizeElement : function(){
6171         var box = this.proxy.getBox();
6172         if(this.updateBox){
6173             this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
6174         }else{
6175             this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
6176         }
6177         this.updateChildSize();
6178         if(!this.dynamic){
6179             this.proxy.hide();
6180         }
6181         return box;
6182     },
6183
6184     // private
6185     constrain : function(v, diff, m, mx){
6186         if(v - diff < m){
6187             diff = v - m;
6188         }else if(v - diff > mx){
6189             diff = mx - v;
6190         }
6191         return diff;
6192     },
6193
6194     // private
6195     onMouseMove : function(e){
6196         if(this.enabled){
6197             try{// try catch so if something goes wrong the user doesn't get hung
6198
6199             if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
6200                 return;
6201             }
6202
6203             //var curXY = this.startPoint;
6204             var curSize = this.curSize || this.startBox;
6205             var x = this.startBox.x, y = this.startBox.y;
6206             var ox = x, oy = y;
6207             var w = curSize.width, h = curSize.height;
6208             var ow = w, oh = h;
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;
6213
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]));
6217
6218             var pos = this.activeHandle.position;
6219
6220             switch(pos){
6221                 case "east":
6222                     w += diffX;
6223                     w = Math.min(Math.max(mw, w), mxw);
6224                     break;
6225                 case "south":
6226                     h += diffY;
6227                     h = Math.min(Math.max(mh, h), mxh);
6228                     break;
6229                 case "southeast":
6230                     w += diffX;
6231                     h += diffY;
6232                     w = Math.min(Math.max(mw, w), mxw);
6233                     h = Math.min(Math.max(mh, h), mxh);
6234                     break;
6235                 case "north":
6236                     diffY = this.constrain(h, diffY, mh, mxh);
6237                     y += diffY;
6238                     h -= diffY;
6239                     break;
6240                 case "west":
6241                     diffX = this.constrain(w, diffX, mw, mxw);
6242                     x += diffX;
6243                     w -= diffX;
6244                     break;
6245                 case "northeast":
6246                     w += diffX;
6247                     w = Math.min(Math.max(mw, w), mxw);
6248                     diffY = this.constrain(h, diffY, mh, mxh);
6249                     y += diffY;
6250                     h -= diffY;
6251                     break;
6252                 case "northwest":
6253                     diffX = this.constrain(w, diffX, mw, mxw);
6254                     diffY = this.constrain(h, diffY, mh, mxh);
6255                     y += diffY;
6256                     h -= diffY;
6257                     x += diffX;
6258                     w -= diffX;
6259                     break;
6260                case "southwest":
6261                     diffX = this.constrain(w, diffX, mw, mxw);
6262                     h += diffY;
6263                     h = Math.min(Math.max(mh, h), mxh);
6264                     x += diffX;
6265                     w -= diffX;
6266                     break;
6267             }
6268
6269             var sw = this.snap(w, wi, mw);
6270             var sh = this.snap(h, hi, mh);
6271             if(sw != w || sh != h){
6272                 switch(pos){
6273                     case "northeast":
6274                         y -= sh - h;
6275                     break;
6276                     case "north":
6277                         y -= sh - h;
6278                         break;
6279                     case "southwest":
6280                         x -= sw - w;
6281                     break;
6282                     case "west":
6283                         x -= sw - w;
6284                         break;
6285                     case "northwest":
6286                         x -= sw - w;
6287                         y -= sh - h;
6288                     break;
6289                 }
6290                 w = sw;
6291                 h = sh;
6292             }
6293
6294             if(this.preserveRatio){
6295                 switch(pos){
6296                     case "southeast":
6297                     case "east":
6298                         h = oh * (w/ow);
6299                         h = Math.min(Math.max(mh, h), mxh);
6300                         w = ow * (h/oh);
6301                        break;
6302                     case "south":
6303                         w = ow * (h/oh);
6304                         w = Math.min(Math.max(mw, w), mxw);
6305                         h = oh * (w/ow);
6306                         break;
6307                     case "northeast":
6308                         w = ow * (h/oh);
6309                         w = Math.min(Math.max(mw, w), mxw);
6310                         h = oh * (w/ow);
6311                     break;
6312                     case "north":
6313                         var tw = w;
6314                         w = ow * (h/oh);
6315                         w = Math.min(Math.max(mw, w), mxw);
6316                         h = oh * (w/ow);
6317                         x += (tw - w) / 2;
6318                         break;
6319                     case "southwest":
6320                         h = oh * (w/ow);
6321                         h = Math.min(Math.max(mh, h), mxh);
6322                         var tw = w;
6323                         w = ow * (h/oh);
6324                         x += tw - w;
6325                         break;
6326                     case "west":
6327                         var th = h;
6328                         h = oh * (w/ow);
6329                         h = Math.min(Math.max(mh, h), mxh);
6330                         y += (th - h) / 2;
6331                         var tw = w;
6332                         w = ow * (h/oh);
6333                         x += tw - w;
6334                        break;
6335                     case "northwest":
6336                         var tw = w;
6337                         var th = h;
6338                         h = oh * (w/ow);
6339                         h = Math.min(Math.max(mh, h), mxh);
6340                         w = ow * (h/oh);
6341                         y += th - h;
6342                          x += tw - w;
6343                        break;
6344
6345                 }
6346             }
6347             this.proxy.setBounds(x, y, w, h);
6348             if(this.dynamic){
6349                 this.resizeElement();
6350             }
6351             }catch(e){}
6352         }
6353     },
6354
6355     // private
6356     handleOver : function(){
6357         if(this.enabled){
6358             this.el.addClass("x-resizable-over");
6359         }
6360     },
6361
6362     // private
6363     handleOut : function(){
6364         if(!this.resizing){
6365             this.el.removeClass("x-resizable-over");
6366         }
6367     },
6368
6369     /**
6370      * Returns the element this component is bound to.
6371      * @return {Roo.Element}
6372      */
6373     getEl : function(){
6374         return this.el;
6375     },
6376
6377     /**
6378      * Returns the resizeChild element (or null).
6379      * @return {Roo.Element}
6380      */
6381     getResizeChild : function(){
6382         return this.resizeChild;
6383     },
6384
6385     /**
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
6389      */
6390     destroy : function(removeEl){
6391         this.proxy.remove();
6392         if(this.overlay){
6393             this.overlay.removeAllListeners();
6394             this.overlay.remove();
6395         }
6396         var ps = Roo.Resizable.positions;
6397         for(var k in ps){
6398             if(typeof ps[k] != "function" && this[ps[k]]){
6399                 var h = this[ps[k]];
6400                 h.el.removeAllListeners();
6401                 h.el.remove();
6402             }
6403         }
6404         if(removeEl){
6405             this.el.update("");
6406             this.el.remove();
6407         }
6408     }
6409 });
6410
6411 // private
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"
6415 };
6416
6417 // private
6418 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
6419     if(!this.tpl){
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}"}
6423         );
6424         tpl.compile();
6425         Roo.Resizable.Handle.prototype.tpl = tpl;
6426     }
6427     this.position = pos;
6428     this.rz = rz;
6429     this.el = this.tpl.append(rz.el.dom, [this.position], true);
6430     this.el.unselectable();
6431     if(transparent){
6432         this.el.setOpacity(0);
6433     }
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);
6438     }
6439 };
6440
6441 // private
6442 Roo.Resizable.Handle.prototype = {
6443     afterResize : function(rz){
6444         // do nothing
6445     },
6446     // private
6447     onMouseDown : function(e){
6448         this.rz.onMouseDown(this, e);
6449     },
6450     // private
6451     onMouseOver : function(e){
6452         this.rz.handleOver(this, e);
6453     },
6454     // private
6455     onMouseOut : function(e){
6456         this.rz.handleOut(this, e);
6457     }
6458 };/*
6459  * Based on:
6460  * Ext JS Library 1.1.1
6461  * Copyright(c) 2006-2007, Ext JS, LLC.
6462  *
6463  * Originally Released Under LGPL - original licence link has changed is not relivant.
6464  *
6465  * Fork - LGPL
6466  * <script type="text/javascript">
6467  */
6468
6469 /**
6470  * @class Roo.Editor
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.
6473  * @constructor
6474  * Create a new Editor
6475  * @param {Roo.form.Field} field The Field object (or descendant)
6476  * @param {Object} config The config object
6477  */
6478 Roo.Editor = function(field, config){
6479     Roo.Editor.superclass.constructor.call(this, config);
6480     this.field = field;
6481     this.addEvents({
6482         /**
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
6489              */
6490         "beforestartedit" : true,
6491         /**
6492              * @event startedit
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
6496              */
6497         "startedit" : true,
6498         /**
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
6507              */
6508         "beforecomplete" : true,
6509         /**
6510              * @event complete
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
6515              */
6516         "complete" : true,
6517         /**
6518          * @event specialkey
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
6523          */
6524         "specialkey" : true
6525     });
6526 };
6527
6528 Roo.extend(Roo.Editor, Roo.Component, {
6529     /**
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)
6533      */
6534     /**
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)
6538      */
6539     /**
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.
6544      */
6545     /**
6546      * @cfg {Boolean} hideEl
6547      * False to keep the bound element visible while the editor is displayed (defaults to true)
6548      */
6549     /**
6550      * @cfg {Mixed} value
6551      * The data value of the underlying field (defaults to "")
6552      */
6553     value : "",
6554     /**
6555      * @cfg {String} alignment
6556      * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
6557      */
6558     alignment: "c-c?",
6559     /**
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")
6562      */
6563     shadow : "frame",
6564     /**
6565      * @cfg {Boolean} constrain True to constrain the editor to the viewport
6566      */
6567     constrain : false,
6568     /**
6569      * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
6570      */
6571     completeOnEnter : false,
6572     /**
6573      * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
6574      */
6575     cancelOnEsc : false,
6576     /**
6577      * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
6578      */
6579     updateEl : false,
6580
6581     // private
6582     onRender : function(ct, position){
6583         this.el = new Roo.Layer({
6584             shadow: this.shadow,
6585             cls: "x-editor",
6586             parentEl : ct,
6587             shim : this.shim,
6588             shadowOffset:4,
6589             id: this.id,
6590             constrain: this.constrain
6591         });
6592         this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
6593         if(this.field.msgTarget != 'title'){
6594             this.field.msgTarget = 'qtip';
6595         }
6596         this.field.render(this.el);
6597         if(Roo.isGecko){
6598             this.field.el.dom.setAttribute('autocomplete', 'off');
6599         }
6600         this.field.on("specialkey", this.onSpecialKey, this);
6601         if(this.swallowKeys){
6602             this.field.el.swallowEvent(['keydown','keypress']);
6603         }
6604         this.field.show();
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});
6608         }
6609     },
6610
6611     onSpecialKey : function(field, e){
6612         if(this.completeOnEnter && e.getKey() == e.ENTER){
6613             e.stopEvent();
6614             this.completeEdit();
6615         }else if(this.cancelOnEsc && e.getKey() == e.ESC){
6616             this.cancelEdit();
6617         }else{
6618             this.fireEvent('specialkey', field, e);
6619         }
6620     },
6621
6622     /**
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.
6627      */
6628     startEdit : function(el, value){
6629         if(this.editing){
6630             this.completeEdit();
6631         }
6632         this.boundEl = Roo.get(el);
6633         var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
6634         if(!this.rendered){
6635             this.render(this.parentEl || document.body);
6636         }
6637         if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
6638             return;
6639         }
6640         this.startValue = v;
6641         this.field.setValue(v);
6642         if(this.autoSize){
6643             var sz = this.boundEl.getSize();
6644             switch(this.autoSize){
6645                 case "width":
6646                 this.setSize(sz.width,  "");
6647                 break;
6648                 case "height":
6649                 this.setSize("",  sz.height);
6650                 break;
6651                 default:
6652                 this.setSize(sz.width,  sz.height);
6653             }
6654         }
6655         this.el.alignTo(this.boundEl, this.alignment);
6656         this.editing = true;
6657         if(Roo.QuickTips){
6658             Roo.QuickTips.disable();
6659         }
6660         this.show();
6661     },
6662
6663     /**
6664      * Sets the height and width of this editor.
6665      * @param {Number} width The new width
6666      * @param {Number} height The new height
6667      */
6668     setSize : function(w, h){
6669         this.field.setSize(w, h);
6670         if(this.el){
6671             this.el.sync();
6672         }
6673     },
6674
6675     /**
6676      * Realigns the editor to the bound field based on the current alignment config value.
6677      */
6678     realign : function(){
6679         this.el.alignTo(this.boundEl, this.alignment);
6680     },
6681
6682     /**
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)
6685      */
6686     completeEdit : function(remainVisible){
6687         if(!this.editing){
6688             return;
6689         }
6690         var v = this.getValue();
6691         if(this.revertInvalid !== false && !this.field.isValid()){
6692             v = this.startValue;
6693             this.cancelEdit(true);
6694         }
6695         if(String(v) === String(this.startValue) && this.ignoreNoChange){
6696             this.editing = false;
6697             this.hide();
6698             return;
6699         }
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);
6704             }
6705             if(remainVisible !== true){
6706                 this.hide();
6707             }
6708             this.fireEvent("complete", this, v, this.startValue);
6709         }
6710     },
6711
6712     // private
6713     onShow : function(){
6714         this.el.show();
6715         if(this.hideEl !== false){
6716             this.boundEl.hide();
6717         }
6718         this.field.show();
6719         if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
6720             this.fixIEFocus = true;
6721             this.deferredFocus.defer(50, this);
6722         }else{
6723             this.field.focus();
6724         }
6725         this.fireEvent("startedit", this.boundEl, this.startValue);
6726     },
6727
6728     deferredFocus : function(){
6729         if(this.editing){
6730             this.field.focus();
6731         }
6732     },
6733
6734     /**
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)
6739      */
6740     cancelEdit : function(remainVisible){
6741         if(this.editing){
6742             this.setValue(this.startValue);
6743             if(remainVisible !== true){
6744                 this.hide();
6745             }
6746         }
6747     },
6748
6749     // private
6750     onBlur : function(){
6751         if(this.allowBlur !== true && this.editing){
6752             this.completeEdit();
6753         }
6754     },
6755
6756     // private
6757     onHide : function(){
6758         if(this.editing){
6759             this.completeEdit();
6760             return;
6761         }
6762         this.field.blur();
6763         if(this.field.collapse){
6764             this.field.collapse();
6765         }
6766         this.el.hide();
6767         if(this.hideEl !== false){
6768             this.boundEl.show();
6769         }
6770         if(Roo.QuickTips){
6771             Roo.QuickTips.enable();
6772         }
6773     },
6774
6775     /**
6776      * Sets the data value of the editor
6777      * @param {Mixed} value Any valid value supported by the underlying field
6778      */
6779     setValue : function(v){
6780         this.field.setValue(v);
6781     },
6782
6783     /**
6784      * Gets the data value of the editor
6785      * @return {Mixed} The data value
6786      */
6787     getValue : function(){
6788         return this.field.getValue();
6789     }
6790 });/*
6791  * Based on:
6792  * Ext JS Library 1.1.1
6793  * Copyright(c) 2006-2007, Ext JS, LLC.
6794  *
6795  * Originally Released Under LGPL - original licence link has changed is not relivant.
6796  *
6797  * Fork - LGPL
6798  * <script type="text/javascript">
6799  */
6800  
6801 /**
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:
6805  * <pre><code>
6806 var dlg = new Roo.BasicDialog("my-dlg", {
6807     height: 200,
6808     width: 300,
6809     minHeight: 100,
6810     minWidth: 150,
6811     modal: true,
6812     proxyDrag: true,
6813     shadow: true
6814 });
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);
6818 dlg.show();
6819 </code></pre>
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)
6853  * @constructor
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
6857  */
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;
6865             }
6866             this.el = dh.append(document.body,
6867                         config.autoCreate, true);
6868         }else{
6869             this.el = dh.append(document.body,
6870                         {tag: "div", id: el, style:'visibility:hidden;'}, true);
6871         }
6872     }
6873     el = this.el;
6874     el.setDisplayed(true);
6875     el.hide = this.hideAction;
6876     this.id = el.id;
6877     el.addClass("x-dlg");
6878
6879     Roo.apply(this, config);
6880
6881     this.proxy = el.createProxy("x-dlg-proxy");
6882     this.proxy.hide = this.hideAction;
6883     this.proxy.setOpacity(.5);
6884     this.proxy.hide();
6885
6886     if(config.width){
6887         el.setWidth(config.width);
6888     }
6889     if(config.height){
6890         el.setHeight(config.height);
6891     }
6892     this.size = el.getSize();
6893     if(typeof config.x != "undefined" && typeof config.y != "undefined"){
6894         this.xy = [config.x,config.y];
6895     }else{
6896         this.xy = el.getCenterXY(true);
6897     }
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");
6904
6905     if(!this.header){
6906         this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: "&#160;"}, this.body ? this.body.dom : null);
6907     }
6908     if(!this.body){
6909         this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
6910     }
6911
6912     this.header.unselectable();
6913     if(this.title){
6914         this.header.update(this.title);
6915     }
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);
6919
6920     this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
6921
6922     // wrap the body and footer for special rendering
6923     this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
6924     if(this.footer){
6925         this.bwrap.dom.appendChild(this.footer.dom);
6926     }
6927
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">&#160;</div></div></div>'
6931     });
6932     this.centerBg = this.bg.child("div.x-dlg-bg-center");
6933
6934
6935     if(this.autoScroll !== false && !this.autoTabs){
6936         this.body.setStyle("overflow", "auto");
6937     }
6938
6939     this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
6940
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");
6946     }
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);
6952     }
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",
6959             pinned: true
6960         });
6961         this.resizer.on("beforeresize", this.beforeResize, this);
6962         this.resizer.on("resize", this.onResize, this);
6963     }
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");
6968         }
6969         else {
6970             var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
6971         }
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);
6976         dd.scroll = false;
6977         this.dd = dd;
6978     }
6979     if(this.modal){
6980         this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
6981         this.mask.enableDisplayMode("block");
6982         this.mask.hide();
6983         this.el.addClass("x-dlg-modal");
6984     }
6985     if(this.shadow){
6986         this.shadow = new Roo.Shadow({
6987             mode : typeof this.shadow == "string" ? this.shadow : "sides",
6988             offset : this.shadowOffset
6989         });
6990     }else{
6991         this.shadowOffset = 0;
6992     }
6993     if(Roo.useShims && this.shim !== false){
6994         this.shim = this.el.createShim();
6995         this.shim.hide = this.hideAction;
6996         this.shim.hide();
6997     }else{
6998         this.shim = false;
6999     }
7000     if(this.autoTabs){
7001         this.initTabs();
7002     }
7003     if (this.buttons) { 
7004         var bts= this.buttons;
7005         this.buttons = [];
7006         Roo.each(bts, function(b) {
7007             this.addButton(b);
7008         }, this);
7009     }
7010     
7011     
7012     this.addEvents({
7013         /**
7014          * @event keydown
7015          * Fires when a key is pressed
7016          * @param {Roo.BasicDialog} this
7017          * @param {Roo.EventObject} e
7018          */
7019         "keydown" : true,
7020         /**
7021          * @event move
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
7026          */
7027         "move" : true,
7028         /**
7029          * @event resize
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
7034          */
7035         "resize" : true,
7036         /**
7037          * @event beforehide
7038          * Fires before this dialog is hidden.
7039          * @param {Roo.BasicDialog} this
7040          */
7041         "beforehide" : true,
7042         /**
7043          * @event hide
7044          * Fires when this dialog is hidden.
7045          * @param {Roo.BasicDialog} this
7046          */
7047         "hide" : true,
7048         /**
7049          * @event beforeshow
7050          * Fires before this dialog is shown.
7051          * @param {Roo.BasicDialog} this
7052          */
7053         "beforeshow" : true,
7054         /**
7055          * @event show
7056          * Fires when this dialog is shown.
7057          * @param {Roo.BasicDialog} this
7058          */
7059         "show" : true
7060     });
7061     el.on("keydown", this.onKeyDown, this);
7062     el.on("mousedown", this.toFront, this);
7063     Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
7064     this.el.hide();
7065     Roo.DialogManager.register(this);
7066     Roo.BasicDialog.superclass.constructor.call(this);
7067 };
7068
7069 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
7070     shadowOffset: Roo.isIE ? 6 : 5,
7071     minHeight: 80,
7072     minWidth: 200,
7073     minButtonWidth: 75,
7074     defaultButton: null,
7075     buttonAlign: "right",
7076     tabTag: 'div',
7077     firstShow: true,
7078
7079     /**
7080      * Sets the dialog title text
7081      * @param {String} text The title text to display
7082      * @return {Roo.BasicDialog} this
7083      */
7084     setTitle : function(text){
7085         this.header.update(text);
7086         return this;
7087     },
7088
7089     // private
7090     closeClick : function(){
7091         this.hide();
7092     },
7093
7094     // private
7095     collapseClick : function(){
7096         this[this.collapsed ? "expand" : "collapse"]();
7097     },
7098
7099     /**
7100      * Collapses the dialog to its minimized state (only the title bar is visible).
7101      * Equivalent to the user clicking the collapse dialog button.
7102      */
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());
7109         }
7110     },
7111
7112     /**
7113      * Expands a collapsed dialog back to its normal state.  Equivalent to the user
7114      * clicking the expand dialog button.
7115      */
7116     expand : function(){
7117         if(this.collapsed){
7118             this.collapsed = false;
7119             this.el.removeClass("x-dlg-collapsed");
7120             this.resizeTo(this.el.getWidth(), this.restoreHeight);
7121         }
7122     },
7123
7124     /**
7125      * Reinitializes the tabs component, clearing out old tabs and finding new ones.
7126      * @return {Roo.TabPanel} The tabs component
7127      */
7128     initTabs : function(){
7129         var tabs = this.getTabs();
7130         while(tabs.getTab(0)){
7131             tabs.removeTab(0);
7132         }
7133         this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
7134             var dom = el.dom;
7135             tabs.addTab(Roo.id(dom), dom.title);
7136             dom.title = "";
7137         });
7138         tabs.activate(0);
7139         return tabs;
7140     },
7141
7142     // private
7143     beforeResize : function(){
7144         this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
7145     },
7146
7147     // private
7148     onResize : function(){
7149         this.refreshSize();
7150         this.syncBodyHeight();
7151         this.adjustAssets();
7152         this.focus();
7153         this.fireEvent("resize", this, this.size.width, this.size.height);
7154     },
7155
7156     // private
7157     onKeyDown : function(e){
7158         if(this.isVisible()){
7159             this.fireEvent("keydown", this, e);
7160         }
7161     },
7162
7163     /**
7164      * Resizes the dialog.
7165      * @param {Number} width
7166      * @param {Number} height
7167      * @return {Roo.BasicDialog} this
7168      */
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){
7174             this.center();
7175         }
7176         if(this.isVisible()){
7177             this.constrainXY();
7178             this.adjustAssets();
7179         }
7180         this.fireEvent("resize", this, width, height);
7181         return this;
7182     },
7183
7184
7185     /**
7186      * Resizes the dialog to fit the specified content size.
7187      * @param {Number} width
7188      * @param {Number} height
7189      * @return {Roo.BasicDialog} this
7190      */
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");
7197         //}
7198         if(this.tabs){
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");
7201         }
7202         this.resizeTo(w, h);
7203         return this;
7204     },
7205
7206     /**
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
7214      */
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"];
7220             ctrl = key["ctrl"];
7221             alt = key["alt"];
7222         }else{
7223             keyCode = key;
7224         }
7225         var handler = function(dlg, e){
7226             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
7227                 var k = e.getKey();
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);
7232                           return;
7233                         }
7234                     }
7235                 }else{
7236                     if(k == keyCode){
7237                         fn.call(scope || window, dlg, k, e);
7238                     }
7239                 }
7240             }
7241         };
7242         this.on("keydown", handler);
7243         return this;
7244     },
7245
7246     /**
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
7251      */
7252     getTabs : function(){
7253         if(!this.tabs){
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");
7257         }
7258         return this.tabs;
7259     },
7260
7261     /**
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
7268      */
7269     addButton : function(config, handler, scope){
7270         var dh = Roo.DomHelper;
7271         if(!this.footer){
7272             this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
7273         }
7274         if(!this.btnContainer){
7275             var tb = this.footer.createChild({
7276
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>'
7279             }, null, true);
7280             this.btnContainer = tb.firstChild.firstChild.firstChild;
7281         }
7282         var bconfig = {
7283             handler: handler,
7284             scope: scope,
7285             minWidth: this.minButtonWidth,
7286             hideParent:true
7287         };
7288         if(typeof config == "string"){
7289             bconfig.text = config;
7290         }else{
7291             if(config.tag){
7292                 bconfig.dhconfig = config;
7293             }else{
7294                 Roo.apply(bconfig, config);
7295             }
7296         }
7297         var fc = false;
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];
7301         }
7302          
7303         var btn = new Roo.Button(
7304             fc ? 
7305                 this.btnContainer.insertBefore(document.createElement("td"),fc)
7306                 : this.btnContainer.appendChild(document.createElement("td")),
7307             //Roo.get(this.btnContainer).createChild( { tag: 'td'},  fc ),
7308             bconfig
7309         );
7310         this.syncBodyHeight();
7311         if(!this.buttons){
7312             /**
7313              * Array of all the buttons that have been added to this dialog via addButton
7314              * @type Array
7315              */
7316             this.buttons = [];
7317         }
7318         this.buttons.push(btn);
7319         return btn;
7320     },
7321
7322     /**
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
7326      */
7327     setDefaultButton : function(btn){
7328         this.defaultButton = btn;
7329         return this;
7330     },
7331
7332     // private
7333     getHeaderFooterHeight : function(safe){
7334         var height = 0;
7335         if(this.header){
7336            height += this.header.getHeight();
7337         }
7338         if(this.footer){
7339            var fm = this.footer.getMargins();
7340             height += (this.footer.getHeight()+fm.top+fm.bottom);
7341         }
7342         height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
7343         height += this.centerBg.getPadding("tb");
7344         return height;
7345     },
7346
7347     // private
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;
7354         cb.setHeight(h);
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));
7359         if(this.tabs){
7360             this.tabs.syncHeight();
7361             if(Roo.isIE){
7362                 this.tabs.el.repaint();
7363             }
7364         }
7365     },
7366
7367     /**
7368      * Restores the previous state of the dialog if Roo.state is configured.
7369      * @return {Roo.BasicDialog} this
7370      */
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);
7376         }
7377         return this;
7378     },
7379
7380     // private
7381     beforeShow : function(){
7382         this.expand();
7383         if(this.fixedcenter){
7384             this.xy = this.el.getCenterXY(true);
7385         }
7386         if(this.modal){
7387             Roo.get(document.body).addClass("x-body-masked");
7388             this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
7389             this.mask.show();
7390         }
7391         this.constrainXY();
7392     },
7393
7394     // private
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);
7399         this.proxy.show();
7400         this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
7401                     true, .35, this.showEl.createDelegate(this));
7402     },
7403
7404     /**
7405      * Shows the dialog.
7406      * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
7407      * @return {Roo.BasicDialog} this
7408      */
7409     show : function(animateTarget){
7410         if (this.fireEvent("beforeshow", this) === false){
7411             return;
7412         }
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
7418         }
7419         this.animateTarget = animateTarget || this.animateTarget;
7420         if(!this.el.isVisible()){
7421             this.beforeShow();
7422             if(this.animateTarget){
7423                 this.animShow();
7424             }else{
7425                 this.showEl();
7426             }
7427         }
7428         return this;
7429     },
7430
7431     // private
7432     showEl : function(){
7433         this.proxy.hide();
7434         this.el.setXY(this.xy);
7435         this.el.show();
7436         this.adjustAssets(true);
7437         this.toFront();
7438         this.focus();
7439         // IE peekaboo bug - fix found by Dave Fenwick
7440         if(Roo.isIE){
7441             this.el.repaint();
7442         }
7443         this.fireEvent("show", this);
7444     },
7445
7446     /**
7447      * Focuses the dialog.  If a defaultButton is set, it will receive focus, otherwise the
7448      * dialog itself will receive focus.
7449      */
7450     focus : function(){
7451         if(this.defaultButton){
7452             this.defaultButton.focus();
7453         }else{
7454             this.focusEl.focus();
7455         }
7456     },
7457
7458     // private
7459     constrainXY : function(){
7460         if(this.constraintoviewport !== false){
7461             if(!this.viewSize){
7462                 if(this.container){
7463                     var s = this.container.getSize();
7464                     this.viewSize = [s.width, s.height];
7465                 }else{
7466                     this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
7467                 }
7468             }
7469             var s = Roo.get(this.container||document).getScroll();
7470
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
7475             var moved = false;
7476             // first validate right/bottom
7477             if(x + w > vw+s.left){
7478                 x = vw - w;
7479                 moved = true;
7480             }
7481             if(y + h > vh+s.top){
7482                 y = vh - h;
7483                 moved = true;
7484             }
7485             // then make sure top/left isn't negative
7486             if(x < s.left){
7487                 x = s.left;
7488                 moved = true;
7489             }
7490             if(y < s.top){
7491                 y = s.top;
7492                 moved = true;
7493             }
7494             if(moved){
7495                 // cache xy
7496                 this.xy = [x, y];
7497                 if(this.isVisible()){
7498                     this.el.setLocation(x, y);
7499                     this.adjustAssets();
7500                 }
7501             }
7502         }
7503     },
7504
7505     // private
7506     onDrag : function(){
7507         if(!this.proxyDrag){
7508             this.xy = this.el.getXY();
7509             this.adjustAssets();
7510         }
7511     },
7512
7513     // private
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){
7518             if(this.shadow){
7519                 this.shadow.show(this.el);
7520             }
7521             if(this.shim){
7522                 this.shim.show();
7523             }
7524         }
7525         if(this.shadow && this.shadow.isVisible()){
7526             this.shadow.show(this.el);
7527         }
7528         if(this.shim && this.shim.isVisible()){
7529             this.shim.setBounds(x, y, w, h);
7530         }
7531     },
7532
7533     // private
7534     adjustViewport : function(w, h){
7535         if(!w || !h){
7536             w = Roo.lib.Dom.getViewWidth();
7537             h = Roo.lib.Dom.getViewHeight();
7538         }
7539         // cache the size
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));
7544         }
7545         if(this.isVisible()){
7546             this.constrainXY();
7547         }
7548     },
7549
7550     /**
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
7554      */
7555     destroy : function(removeEl){
7556         if(this.isVisible()){
7557             this.animateTarget = null;
7558             this.hide();
7559         }
7560         Roo.EventManager.removeResizeListener(this.adjustViewport, this);
7561         if(this.tabs){
7562             this.tabs.destroy(removeEl);
7563         }
7564         Roo.destroy(
7565              this.shim,
7566              this.proxy,
7567              this.resizer,
7568              this.close,
7569              this.mask
7570         );
7571         if(this.dd){
7572             this.dd.unreg();
7573         }
7574         if(this.buttons){
7575            for(var i = 0, len = this.buttons.length; i < len; i++){
7576                this.buttons[i].destroy();
7577            }
7578         }
7579         this.el.removeAllListeners();
7580         if(removeEl === true){
7581             this.el.update("");
7582             this.el.remove();
7583         }
7584         Roo.DialogManager.unregister(this);
7585     },
7586
7587     // private
7588     startMove : function(){
7589         if(this.proxyDrag){
7590             this.proxy.show();
7591         }
7592         if(this.constraintoviewport !== false){
7593             this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
7594         }
7595     },
7596
7597     // private
7598     endMove : function(){
7599         if(!this.proxyDrag){
7600             Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
7601         }else{
7602             Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
7603             this.proxy.hide();
7604         }
7605         this.refreshSize();
7606         this.adjustAssets();
7607         this.focus();
7608         this.fireEvent("move", this, this.xy[0], this.xy[1]);
7609     },
7610
7611     /**
7612      * Brings this dialog to the front of any other visible dialogs
7613      * @return {Roo.BasicDialog} this
7614      */
7615     toFront : function(){
7616         Roo.DialogManager.bringToFront(this);
7617         return this;
7618     },
7619
7620     /**
7621      * Sends this dialog to the back (under) of any other visible dialogs
7622      * @return {Roo.BasicDialog} this
7623      */
7624     toBack : function(){
7625         Roo.DialogManager.sendToBack(this);
7626         return this;
7627     },
7628
7629     /**
7630      * Centers this dialog in the viewport
7631      * @return {Roo.BasicDialog} this
7632      */
7633     center : function(){
7634         var xy = this.el.getCenterXY(true);
7635         this.moveTo(xy[0], xy[1]);
7636         return this;
7637     },
7638
7639     /**
7640      * Moves the dialog's top-left corner to the specified point
7641      * @param {Number} x
7642      * @param {Number} y
7643      * @return {Roo.BasicDialog} this
7644      */
7645     moveTo : function(x, y){
7646         this.xy = [x,y];
7647         if(this.isVisible()){
7648             this.el.setXY(this.xy);
7649             this.adjustAssets();
7650         }
7651         return this;
7652     },
7653
7654     /**
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
7660      */
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();
7666         }
7667         return this;
7668     },
7669
7670     /**
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
7678      */
7679     anchorTo : function(el, alignment, offsets, monitorScroll){
7680         var action = function(){
7681             this.alignTo(el, alignment, offsets);
7682         };
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});
7688         }
7689         action.call(this);
7690         return this;
7691     },
7692
7693     /**
7694      * Returns true if the dialog is visible
7695      * @return {Boolean}
7696      */
7697     isVisible : function(){
7698         return this.el.isVisible();
7699     },
7700
7701     // private
7702     animHide : function(callback){
7703         var b = Roo.get(this.animateTarget).getBox();
7704         this.proxy.show();
7705         this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
7706         this.el.hide();
7707         this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
7708                     this.hideEl.createDelegate(this, [callback]));
7709     },
7710
7711     /**
7712      * Hides the dialog.
7713      * @param {Function} callback (optional) Function to call when the dialog is hidden
7714      * @return {Roo.BasicDialog} this
7715      */
7716     hide : function(callback){
7717         if (this.fireEvent("beforehide", this) === false){
7718             return;
7719         }
7720         if(this.shadow){
7721             this.shadow.hide();
7722         }
7723         if(this.shim) {
7724           this.shim.hide();
7725         }
7726         if(this.animateTarget){
7727            this.animHide(callback);
7728         }else{
7729             this.el.hide();
7730             this.hideEl(callback);
7731         }
7732         return this;
7733     },
7734
7735     // private
7736     hideEl : function(callback){
7737         this.proxy.hide();
7738         if(this.modal){
7739             this.mask.hide();
7740             Roo.get(document.body).removeClass("x-body-masked");
7741         }
7742         this.fireEvent("hide", this);
7743         if(typeof callback == "function"){
7744             callback();
7745         }
7746     },
7747
7748     // private
7749     hideAction : function(){
7750         this.setLeft("-10000px");
7751         this.setTop("-10000px");
7752         this.setStyle("visibility", "hidden");
7753     },
7754
7755     // private
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());
7760     },
7761
7762     // private
7763     // z-index is managed by the DialogManager and may be overwritten at any time
7764     setZIndex : function(index){
7765         if(this.modal){
7766             this.mask.setStyle("z-index", index);
7767         }
7768         if(this.shim){
7769             this.shim.setStyle("z-index", ++index);
7770         }
7771         if(this.shadow){
7772             this.shadow.setZIndex(++index);
7773         }
7774         this.el.setStyle("z-index", ++index);
7775         if(this.proxy){
7776             this.proxy.setStyle("z-index", ++index);
7777         }
7778         if(this.resizer){
7779             this.resizer.proxy.setStyle("z-index", ++index);
7780         }
7781
7782         this.lastZIndex = index;
7783     },
7784
7785     /**
7786      * Returns the element for this dialog
7787      * @return {Roo.Element} The underlying dialog Element
7788      */
7789     getEl : function(){
7790         return this.el;
7791     }
7792 });
7793
7794 /**
7795  * @class Roo.DialogManager
7796  * Provides global access to BasicDialogs that have been created and
7797  * support for z-indexing (layering) multiple open dialogs.
7798  */
7799 Roo.DialogManager = function(){
7800     var list = {};
7801     var accessList = [];
7802     var front = null;
7803
7804     // private
7805     var sortDialogs = function(d1, d2){
7806         return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
7807     };
7808
7809     // private
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];
7815             if(dlg){
7816                 dlg.setZIndex(seed + (i*10));
7817             }
7818         }
7819     };
7820
7821     return {
7822         /**
7823          * The starting z-index for BasicDialogs (defaults to 9000)
7824          * @type Number The z-index value
7825          */
7826         zseed : 9000,
7827
7828         // private
7829         register : function(dlg){
7830             list[dlg.id] = dlg;
7831             accessList.push(dlg);
7832         },
7833
7834         // private
7835         unregister : function(dlg){
7836             delete list[dlg.id];
7837             var i=0;
7838             var len=0;
7839             if(!accessList.indexOf){
7840                 for(  i = 0, len = accessList.length; i < len; i++){
7841                     if(accessList[i] == dlg){
7842                         accessList.splice(i, 1);
7843                         return;
7844                     }
7845                 }
7846             }else{
7847                  i = accessList.indexOf(dlg);
7848                 if(i != -1){
7849                     accessList.splice(i, 1);
7850                 }
7851             }
7852         },
7853
7854         /**
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
7858          */
7859         get : function(id){
7860             return typeof id == "object" ? id : list[id];
7861         },
7862
7863         /**
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
7867          */
7868         bringToFront : function(dlg){
7869             dlg = this.get(dlg);
7870             if(dlg != front){
7871                 front = dlg;
7872                 dlg._lastAccess = new Date().getTime();
7873                 orderDialogs();
7874             }
7875             return dlg;
7876         },
7877
7878         /**
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
7882          */
7883         sendToBack : function(dlg){
7884             dlg = this.get(dlg);
7885             dlg._lastAccess = -(new Date().getTime());
7886             orderDialogs();
7887             return dlg;
7888         },
7889
7890         /**
7891          * Hides all dialogs
7892          */
7893         hideAll : function(){
7894             for(var id in list){
7895                 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
7896                     list[id].hide();
7897                 }
7898             }
7899         }
7900     };
7901 }();
7902
7903 /**
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):
7909  * <pre><code>
7910 if(!dialog){
7911     dialog = new Roo.LayoutDialog("download-dlg", {
7912         modal: true,
7913         width:600,
7914         height:450,
7915         shadow:true,
7916         minWidth:500,
7917         minHeight:350,
7918         autoTabs:true,
7919         proxyDrag:true,
7920         // layout config merges with the dialog config
7921         center:{
7922             tabPosition: "top",
7923             alwaysShowTabs: true
7924         }
7925     });
7926     dialog.addKeyListener(27, dialog.hide, dialog);
7927     dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
7928     dialog.addButton("Build It!", this.getDownload, this);
7929
7930     // we can even add nested layouts
7931     var innerLayout = new Roo.BorderLayout("dl-inner", {
7932         east: {
7933             initialSize: 200,
7934             autoScroll:true,
7935             split:true
7936         },
7937         center: {
7938             autoScroll:true
7939         }
7940     });
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);
7945
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);
7953     layout.endUpdate();
7954 }
7955 </code></pre>
7956     * @constructor
7957     * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
7958     * @param {Object} config configuration options
7959   */
7960 Roo.LayoutDialog = function(el, cfg){
7961     
7962     var config=  cfg;
7963     if (typeof(cfg) == 'undefined') {
7964         config = Roo.apply({}, el);
7965         el = Roo.get( document.documentElement || document.body).createChild();
7966         //config.autoCreate = true;
7967     }
7968     
7969     
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);
7979     if (config.items) {
7980         var xitems = config.items;
7981         delete config.items;
7982         Roo.each(xitems, this.addxtype, this);
7983     }
7984     
7985     
7986 };
7987 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
7988     /**
7989      * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
7990      * @deprecated
7991      */
7992     endUpdate : function(){
7993         this.layout.endUpdate();
7994     },
7995
7996     /**
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.
7998      *  @deprecated
7999      */
8000     beginUpdate : function(){
8001         this.layout.beginUpdate();
8002     },
8003
8004     /**
8005      * Get the BorderLayout for this dialog
8006      * @return {Roo.BorderLayout}
8007      */
8008     getLayout : function(){
8009         return this.layout;
8010     },
8011
8012     showEl : function(){
8013         Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
8014         if(Roo.isIE7){
8015             this.layout.layout();
8016         }
8017     },
8018
8019     // private
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();}
8024     },
8025     
8026       /**
8027      * Add an xtype element (actually adds to the layout.)
8028      * @return {Object} xdata xtype object data.
8029      */
8030     
8031     addxtype : function(c) {
8032         return this.layout.addxtype(c);
8033     }
8034 });/*
8035  * Based on:
8036  * Ext JS Library 1.1.1
8037  * Copyright(c) 2006-2007, Ext JS, LLC.
8038  *
8039  * Originally Released Under LGPL - original licence link has changed is not relivant.
8040  *
8041  * Fork - LGPL
8042  * <script type="text/javascript">
8043  */
8044  
8045 /**
8046  * @class Roo.MessageBox
8047  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
8048  * Example usage:
8049  *<pre><code>
8050 // Basic alert:
8051 Roo.Msg.alert('Status', 'Changes saved successfully.');
8052
8053 // Prompt for user data:
8054 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
8055     if (btn == 'ok'){
8056         // process text value...
8057     }
8058 });
8059
8060 // Show a dialog using config options:
8061 Roo.Msg.show({
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,
8065    fn: processResult,
8066    animEl: 'elId'
8067 });
8068 </code></pre>
8069  * @singleton
8070  */
8071 Roo.MessageBox = function(){
8072     var dlg, opt, mask, waitTimer;
8073     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
8074     var buttons, activeTextEl, bwidth;
8075
8076     // private
8077     var handleButton = function(button){
8078         dlg.hide();
8079         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
8080     };
8081
8082     // private
8083     var handleHide = function(){
8084         if(opt && opt.cls){
8085             dlg.el.removeClass(opt.cls);
8086         }
8087         if(waitTimer){
8088             Roo.TaskMgr.stop(waitTimer);
8089             waitTimer = null;
8090         }
8091     };
8092
8093     // private
8094     var updateButtons = function(b){
8095         var width = 0;
8096         if(!b){
8097             buttons["ok"].hide();
8098             buttons["cancel"].hide();
8099             buttons["yes"].hide();
8100             buttons["no"].hide();
8101             dlg.footer.dom.style.display = 'none';
8102             return width;
8103         }
8104         dlg.footer.dom.style.display = '';
8105         for(var k in buttons){
8106             if(typeof buttons[k] != "function"){
8107                 if(b[k]){
8108                     buttons[k].show();
8109                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
8110                     width += buttons[k].el.getWidth()+15;
8111                 }else{
8112                     buttons[k].hide();
8113                 }
8114             }
8115         }
8116         return width;
8117     };
8118
8119     // private
8120     var handleEsc = function(d, k, e){
8121         if(opt && opt.closable !== false){
8122             dlg.hide();
8123         }
8124         if(e){
8125             e.stopEvent();
8126         }
8127     };
8128
8129     return {
8130         /**
8131          * Returns a reference to the underlying {@link Roo.BasicDialog} element
8132          * @return {Roo.BasicDialog} The BasicDialog element
8133          */
8134         getDialog : function(){
8135            if(!dlg){
8136                 dlg = new Roo.BasicDialog("x-msg-box", {
8137                     autoCreate : true,
8138                     shadow: true,
8139                     draggable: true,
8140                     resizable:false,
8141                     constraintoviewport:false,
8142                     fixedcenter:true,
8143                     collapsible : false,
8144                     shim:true,
8145                     modal: true,
8146                     width:400, height:100,
8147                     buttonAlign:"center",
8148                     closeClick : function(){
8149                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
8150                             handleButton("no");
8151                         }else{
8152                             handleButton("cancel");
8153                         }
8154                     }
8155                 });
8156                 dlg.on("hide", handleHide);
8157                 mask = dlg.mask;
8158                 dlg.addKeyListener(27, handleEsc);
8159                 buttons = {};
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({
8166
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">&#160;</div></div></div>'
8168                 });
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){
8174                         if(opt.buttons.ok){
8175                             handleButton("ok");
8176                         }else if(opt.buttons.yes){
8177                             handleButton("yes");
8178                         }
8179                     }
8180                 });
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;
8186                 if (pf) {
8187                     pp = Roo.get(pf.firstChild);
8188                     pp.setHeight(pf.offsetHeight);
8189                 }
8190                 
8191             }
8192             return dlg;
8193         },
8194
8195         /**
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 '&amp;#160;')
8199          * @return {Roo.MessageBox} This message box
8200          */
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
8204             }
8205             msgEl.innerHTML = text || '&#160;';
8206             var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth), 
8207                         Math.max(opt.minWidth || this.minWidth, bwidth));
8208             if(opt.prompt){
8209                 activeTextEl.setWidth(w);
8210             }
8211             if(dlg.isVisible()){
8212                 dlg.fixedcenter = false;
8213             }
8214             dlg.setContentSize(w, bodyEl.getHeight());
8215             if(dlg.isVisible()){
8216                 dlg.fixedcenter = true;
8217             }
8218             return this;
8219         },
8220
8221         /**
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
8227          */
8228         updateProgress : function(value, text){
8229             if(text){
8230                 this.updateText(text);
8231             }
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));
8234             }
8235             return this;
8236         },        
8237
8238         /**
8239          * Returns true if the message box is currently displayed
8240          * @return {Boolean} True if the message box is visible, else false
8241          */
8242         isVisible : function(){
8243             return dlg && dlg.isVisible();  
8244         },
8245
8246         /**
8247          * Hides the message box if it is displayed
8248          */
8249         hide : function(){
8250             if(this.isVisible()){
8251                 dlg.hide();
8252             }  
8253         },
8254
8255         /**
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:
8259          * <pre>
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 '&#160;')
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
8295 </pre>
8296          *
8297          * Example usage:
8298          * <pre><code>
8299 Roo.Msg.show({
8300    title: 'Address',
8301    msg: 'Please enter your address:',
8302    width: 300,
8303    buttons: Roo.MessageBox.OKCANCEL,
8304    multiline: true,
8305    fn: saveAddress,
8306    animEl: 'addAddressBtn'
8307 });
8308 </code></pre>
8309          * @param {Object} config Configuration options
8310          * @return {Roo.MessageBox} This message box
8311          */
8312         show : function(options){
8313             if(this.isVisible()){
8314                 this.hide();
8315             }
8316             var d = this.getDialog();
8317             opt = options;
8318             d.setTitle(opt.title || "&#160;");
8319             d.close.setDisplayed(opt.closable !== false);
8320             activeTextEl = textboxEl;
8321             opt.prompt = opt.prompt || (opt.multiline ? true : false);
8322             if(opt.prompt){
8323                 if(opt.multiline){
8324                     textboxEl.hide();
8325                     textareaEl.show();
8326                     textareaEl.setHeight(typeof opt.multiline == "number" ?
8327                         opt.multiline : this.defaultTextHeight);
8328                     activeTextEl = textareaEl;
8329                 }else{
8330                     textboxEl.show();
8331                     textareaEl.hide();
8332                 }
8333             }else{
8334                 textboxEl.hide();
8335                 textareaEl.hide();
8336             }
8337             progressEl.setDisplayed(opt.progress === true);
8338             this.updateProgress(0);
8339             activeTextEl.dom.value = opt.value || "";
8340             if(opt.prompt){
8341                 dlg.setDefaultButton(activeTextEl);
8342             }else{
8343                 var bs = opt.buttons;
8344                 var db = null;
8345                 if(bs && bs.ok){
8346                     db = buttons["ok"];
8347                 }else if(bs && bs.yes){
8348                     db = buttons["yes"];
8349                 }
8350                 dlg.setDefaultButton(db);
8351             }
8352             bwidth = updateButtons(opt.buttons);
8353             this.updateText(opt.msg);
8354             if(opt.cls){
8355                 d.el.addClass(opt.cls);
8356             }
8357             d.proxyDrag = opt.proxyDrag === true;
8358             d.modal = opt.modal !== false;
8359             d.mask = opt.modal !== false ? mask : false;
8360             if(!d.isVisible()){
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);
8365             }
8366             return this;
8367         },
8368
8369         /**
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
8376          */
8377         progress : function(title, msg){
8378             this.show({
8379                 title : title,
8380                 msg : msg,
8381                 buttons: false,
8382                 progress:true,
8383                 closable:false,
8384                 minWidth: this.minProgressWidth,
8385                 modal : true
8386             });
8387             return this;
8388         },
8389
8390         /**
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
8400          */
8401         alert : function(title, msg, fn, scope){
8402             this.show({
8403                 title : title,
8404                 msg : msg,
8405                 buttons: this.OK,
8406                 fn: fn,
8407                 scope : scope,
8408                 modal : true
8409             });
8410             return this;
8411         },
8412
8413         /**
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
8420          */
8421         wait : function(msg, title){
8422             this.show({
8423                 title : title,
8424                 msg : msg,
8425                 buttons: false,
8426                 closable:false,
8427                 progress:true,
8428                 modal:true,
8429                 width:300,
8430                 wait:true
8431             });
8432             waitTimer = Roo.TaskMgr.start({
8433                 run: function(i){
8434                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
8435                 },
8436                 interval: 1000
8437             });
8438             return this;
8439         },
8440
8441         /**
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
8450          */
8451         confirm : function(title, msg, fn, scope){
8452             this.show({
8453                 title : title,
8454                 msg : msg,
8455                 buttons: this.YESNO,
8456                 fn: fn,
8457                 scope : scope,
8458                 modal : true
8459             });
8460             return this;
8461         },
8462
8463         /**
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
8476          */
8477         prompt : function(title, msg, fn, scope, multiline){
8478             this.show({
8479                 title : title,
8480                 msg : msg,
8481                 buttons: this.OKCANCEL,
8482                 fn: fn,
8483                 minWidth:250,
8484                 scope : scope,
8485                 prompt:true,
8486                 multiline: multiline,
8487                 modal : true
8488             });
8489             return this;
8490         },
8491
8492         /**
8493          * Button config that displays a single OK button
8494          * @type Object
8495          */
8496         OK : {ok:true},
8497         /**
8498          * Button config that displays Yes and No buttons
8499          * @type Object
8500          */
8501         YESNO : {yes:true, no:true},
8502         /**
8503          * Button config that displays OK and Cancel buttons
8504          * @type Object
8505          */
8506         OKCANCEL : {ok:true, cancel:true},
8507         /**
8508          * Button config that displays Yes, No and Cancel buttons
8509          * @type Object
8510          */
8511         YESNOCANCEL : {yes:true, no:true, cancel:true},
8512
8513         /**
8514          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
8515          * @type Number
8516          */
8517         defaultTextHeight : 75,
8518         /**
8519          * The maximum width in pixels of the message box (defaults to 600)
8520          * @type Number
8521          */
8522         maxWidth : 600,
8523         /**
8524          * The minimum width in pixels of the message box (defaults to 100)
8525          * @type Number
8526          */
8527         minWidth : 100,
8528         /**
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)
8531          * @type Number
8532          */
8533         minProgressWidth : 250,
8534         /**
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?";
8538          * @type Object
8539          */
8540         buttonText : {
8541             ok : "OK",
8542             cancel : "Cancel",
8543             yes : "Yes",
8544             no : "No"
8545         }
8546     };
8547 }();
8548
8549 /**
8550  * Shorthand for {@link Roo.MessageBox}
8551  */
8552 Roo.Msg = Roo.MessageBox;/*
8553  * Based on:
8554  * Ext JS Library 1.1.1
8555  * Copyright(c) 2006-2007, Ext JS, LLC.
8556  *
8557  * Originally Released Under LGPL - original licence link has changed is not relivant.
8558  *
8559  * Fork - LGPL
8560  * <script type="text/javascript">
8561  */
8562 /**
8563  * @class Roo.QuickTips
8564  * Provides attractive and customizable tooltips for any element.
8565  * @singleton
8566  */
8567 Roo.QuickTips = function(){
8568     var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
8569     var ce, bd, xy, dd;
8570     var visible = false, disabled = true, inited = false;
8571     var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
8572     
8573     var onOver = function(e){
8574         if(disabled){
8575             return;
8576         }
8577         var t = e.getTarget();
8578         if(!t || t.nodeType !== 1 || t == document || t == document.body){
8579             return;
8580         }
8581         if(ce && t == ce.el){
8582             clearTimeout(hideProc);
8583             return;
8584         }
8585         if(t && tagEls[t.id]){
8586             tagEls[t.id].el = t;
8587             showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
8588             return;
8589         }
8590         var ttp, et = Roo.fly(t);
8591         var ns = cfg.namespace;
8592         if(tm.interceptTitles && t.title){
8593             ttp = t.title;
8594             t.qtip = ttp;
8595             t.removeAttribute("title");
8596             e.preventDefault();
8597         }else{
8598             ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
8599         }
8600         if(ttp){
8601             showProc = show.defer(tm.showDelay, tm, [{
8602                 el: t, 
8603                 text: ttp, 
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)
8608             }]);
8609         }
8610     };
8611     
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);
8617         }
8618     };
8619     
8620     var onMove = function(e){
8621         if(disabled){
8622             return;
8623         }
8624         xy = e.getXY();
8625         xy[1] += 18;
8626         if(tm.trackMouse && ce){
8627             el.setXY(xy);
8628         }
8629     };
8630     
8631     var onDown = function(e){
8632         clearTimeout(showProc);
8633         clearTimeout(hideProc);
8634         if(!e.within(el)){
8635             if(tm.hideOnClick){
8636                 hide();
8637                 tm.disable();
8638                 tm.enable.defer(100, tm);
8639             }
8640         }
8641     };
8642     
8643     var getPad = function(){
8644         return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
8645     };
8646
8647     var show = function(o){
8648         if(disabled){
8649             return;
8650         }
8651         clearTimeout(dismissProc);
8652         ce = o;
8653         if(removeCls){ // in case manually hidden
8654             el.removeClass(removeCls);
8655             removeCls = null;
8656         }
8657         if(ce.cls){
8658             el.addClass(ce.cls);
8659             removeCls = ce.cls;
8660         }
8661         if(ce.title){
8662             tipTitle.update(ce.title);
8663             tipTitle.show();
8664         }else{
8665             tipTitle.update('');
8666             tipTitle.hide();
8667         }
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;
8672         if(!w){
8673             var td = tipBodyText.dom;
8674             var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
8675             if(aw > tm.maxWidth){
8676                 w = tm.maxWidth;
8677             }else if(aw < tm.minWidth){
8678                 w = tm.minWidth;
8679             }else{
8680                 w = aw;
8681             }
8682         }
8683         //tipBody.setWidth(w);
8684         el.setWidth(parseInt(w, 10) + p);
8685         if(ce.autoHide === false){
8686             close.setDisplayed(true);
8687             if(dd){
8688                 dd.unlock();
8689             }
8690         }else{
8691             close.setDisplayed(false);
8692             if(dd){
8693                 dd.lock();
8694             }
8695         }
8696         if(xy){
8697             el.avoidY = xy[1]-18;
8698             el.setXY(xy);
8699         }
8700         if(tm.animate){
8701             el.setOpacity(.1);
8702             el.setStyle("visibility", "visible");
8703             el.fadeIn({callback: afterShow});
8704         }else{
8705             afterShow();
8706         }
8707     };
8708     
8709     var afterShow = function(){
8710         if(ce){
8711             el.show();
8712             esc.enable();
8713             if(tm.autoDismiss && ce.autoHide !== false){
8714                 dismissProc = setTimeout(hide, tm.autoDismissDelay);
8715             }
8716         }
8717     };
8718     
8719     var hide = function(noanim){
8720         clearTimeout(dismissProc);
8721         clearTimeout(hideProc);
8722         ce = null;
8723         if(el.isVisible()){
8724             esc.disable();
8725             if(noanim !== true && tm.animate){
8726                 el.fadeOut({callback: afterHide});
8727             }else{
8728                 afterHide();
8729             } 
8730         }
8731     };
8732     
8733     var afterHide = function(){
8734         el.hide();
8735         if(removeCls){
8736             el.removeClass(removeCls);
8737             removeCls = null;
8738         }
8739     };
8740     
8741     return {
8742         /**
8743         * @cfg {Number} minWidth
8744         * The minimum width of the quick tip (defaults to 40)
8745         */
8746        minWidth : 40,
8747         /**
8748         * @cfg {Number} maxWidth
8749         * The maximum width of the quick tip (defaults to 300)
8750         */
8751        maxWidth : 300,
8752         /**
8753         * @cfg {Boolean} interceptTitles
8754         * True to automatically use the element's DOM title value if available (defaults to false)
8755         */
8756        interceptTitles : false,
8757         /**
8758         * @cfg {Boolean} trackMouse
8759         * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
8760         */
8761        trackMouse : false,
8762         /**
8763         * @cfg {Boolean} hideOnClick
8764         * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
8765         */
8766        hideOnClick : true,
8767         /**
8768         * @cfg {Number} showDelay
8769         * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
8770         */
8771        showDelay : 500,
8772         /**
8773         * @cfg {Number} hideDelay
8774         * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
8775         */
8776        hideDelay : 200,
8777         /**
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.
8781         */
8782        autoHide : true,
8783         /**
8784         * @cfg {Boolean}
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.
8787         */
8788        autoDismiss : true,
8789         /**
8790         * @cfg {Number}
8791         * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
8792         */
8793        autoDismissDelay : 5000,
8794        /**
8795         * @cfg {Boolean} animate
8796         * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
8797         */
8798        animate : false,
8799
8800        /**
8801         * @cfg {String} title
8802         * Title text to display (defaults to '').  This can be any valid HTML markup.
8803         */
8804         title: '',
8805        /**
8806         * @cfg {String} text
8807         * Body text to display (defaults to '').  This can be any valid HTML markup.
8808         */
8809         text : '',
8810        /**
8811         * @cfg {String} cls
8812         * A CSS class to apply to the base quick tip element (defaults to '').
8813         */
8814         cls : '',
8815        /**
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.
8819         */
8820         width : null,
8821
8822     /**
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.
8825      */
8826        init : function(){
8827           tm = Roo.QuickTips;
8828           cfg = tm.tagConfig;
8829           if(!inited){
8830               if(!Roo.isReady){ // allow calling of init() before onReady
8831                   Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
8832                   return;
8833               }
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);
8854               esc.disable();
8855               if(Roo.dd.DD){
8856                   dd = el.initDD("default", null, {
8857                       onDrag : function(){
8858                           el.sync();  
8859                       }
8860                   });
8861                   dd.setHandleElId(tipTitle.id);
8862                   dd.lock();
8863               }
8864               inited = true;
8865           }
8866           this.enable(); 
8867        },
8868
8869     /**
8870      * Configures a new quick tip instance and assigns it to a target element.  The following config options
8871      * are supported:
8872      * <pre>
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
8876      * </ul>
8877      * @param {Object} config The config object
8878      */
8879        register : function(config){
8880            var cs = config instanceof Array ? config : arguments;
8881            for(var i = 0, len = cs.length; i < len; i++) {
8882                var c = cs[i];
8883                var target = c.target;
8884                if(target){
8885                    if(target instanceof Array){
8886                        for(var j = 0, jlen = target.length; j < jlen; j++){
8887                            tagEls[target[j]] = c;
8888                        }
8889                    }else{
8890                        tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
8891                    }
8892                }
8893            }
8894        },
8895
8896     /**
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.
8899      */
8900        unregister : function(el){
8901            delete tagEls[Roo.id(el)];
8902        },
8903
8904     /**
8905      * Enable this quick tip.
8906      */
8907        enable : function(){
8908            if(inited && disabled){
8909                locks.pop();
8910                if(locks.length < 1){
8911                    disabled = false;
8912                }
8913            }
8914        },
8915
8916     /**
8917      * Disable this quick tip.
8918      */
8919        disable : function(){
8920           disabled = true;
8921           clearTimeout(showProc);
8922           clearTimeout(hideProc);
8923           clearTimeout(dismissProc);
8924           if(ce){
8925               hide(true);
8926           }
8927           locks.push(1);
8928        },
8929
8930     /**
8931      * Returns true if the quick tip is enabled, else false.
8932      */
8933        isEnabled : function(){
8934             return !disabled;
8935        },
8936
8937         // private
8938        tagConfig : {
8939            namespace : "ext",
8940            attribute : "qtip",
8941            width : "width",
8942            target : "target",
8943            title : "qtitle",
8944            hide : "hide",
8945            cls : "qclass"
8946        }
8947    };
8948 }();
8949
8950 // backwards compat
8951 Roo.QuickTips.tips = Roo.QuickTips.register;