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 /*
15  * These classes are derivatives of the similarly named classes in the YUI Library.
16  * The original license:
17  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18  * Code licensed under the BSD License:
19  * http://developer.yahoo.net/yui/license.txt
20  */
21
22 (function() {
23
24 var Event=Roo.EventManager;
25 var Dom=Roo.lib.Dom;
26
27 /**
28  * @class Roo.dd.DragDrop
29  * Defines the interface and base operation of items that that can be
30  * dragged or can be drop targets.  It was designed to be extended, overriding
31  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32  * Up to three html elements can be associated with a DragDrop instance:
33  * <ul>
34  * <li>linked element: the element that is passed into the constructor.
35  * This is the element which defines the boundaries for interaction with
36  * other DragDrop objects.</li>
37  * <li>handle element(s): The drag operation only occurs if the element that
38  * was clicked matches a handle element.  By default this is the linked
39  * element, but there are times that you will want only a portion of the
40  * linked element to initiate the drag operation, and the setHandleElId()
41  * method provides a way to define this.</li>
42  * <li>drag element: this represents the element that would be moved along
43  * with the cursor during a drag operation.  By default, this is the linked
44  * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
45  * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
46  * </li>
47  * </ul>
48  * This class should not be instantiated until the onload event to ensure that
49  * the associated elements are available.
50  * The following would define a DragDrop obj that would interact with any
51  * other DragDrop obj in the "group1" group:
52  * <pre>
53  *  dd = new Roo.dd.DragDrop("div1", "group1");
54  * </pre>
55  * Since none of the event handlers have been implemented, nothing would
56  * actually happen if you were to run the code above.  Normally you would
57  * override this class or one of the default implementations, but you can
58  * also override the methods you want on an instance of the class...
59  * <pre>
60  *  dd.onDragDrop = function(e, id) {
61  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
62  *  }
63  * </pre>
64  * @constructor
65  * @param {String} id of the element that is linked to this instance
66  * @param {String} sGroup the group of related DragDrop objects
67  * @param {object} config an object containing configurable attributes
68  *                Valid properties for DragDrop:
69  *                    padding, isTarget, maintainOffset, primaryButtonOnly
70  */
71 Roo.dd.DragDrop = function(id, sGroup, config) {
72     if (id) {
73         this.init(id, sGroup, config);
74     }
75     if (config.listeners || config.events) { 
76         Roo.BasicLayoutRegion.superclass.constructor.call(this,  { 
77             listeners : config.listeners || {}, 
78             events : config.events || {} 
79         });    
80     }
81 };
82
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
84
85     /**
86      * The id of the element associated with this object.  This is what we
87      * refer to as the "linked element" because the size and position of
88      * this element is used to determine when the drag and drop objects have
89      * interacted.
90      * @property id
91      * @type String
92      */
93     id: null,
94
95     /**
96      * Configuration attributes passed into the constructor
97      * @property config
98      * @type object
99      */
100     config: null,
101
102     /**
103      * The id of the element that will be dragged.  By default this is same
104      * as the linked element , but could be changed to another element. Ex:
105      * Roo.dd.DDProxy
106      * @property dragElId
107      * @type String
108      * @private
109      */
110     dragElId: null,
111
112     /**
113      * the id of the element that initiates the drag operation.  By default
114      * this is the linked element, but could be changed to be a child of this
115      * element.  This lets us do things like only starting the drag when the
116      * header element within the linked html element is clicked.
117      * @property handleElId
118      * @type String
119      * @private
120      */
121     handleElId: null,
122
123     /**
124      * An associative array of HTML tags that will be ignored if clicked.
125      * @property invalidHandleTypes
126      * @type {string: string}
127      */
128     invalidHandleTypes: null,
129
130     /**
131      * An associative array of ids for elements that will be ignored if clicked
132      * @property invalidHandleIds
133      * @type {string: string}
134      */
135     invalidHandleIds: null,
136
137     /**
138      * An indexted array of css class names for elements that will be ignored
139      * if clicked.
140      * @property invalidHandleClasses
141      * @type string[]
142      */
143     invalidHandleClasses: null,
144
145     /**
146      * The linked element's absolute X position at the time the drag was
147      * started
148      * @property startPageX
149      * @type int
150      * @private
151      */
152     startPageX: 0,
153
154     /**
155      * The linked element's absolute X position at the time the drag was
156      * started
157      * @property startPageY
158      * @type int
159      * @private
160      */
161     startPageY: 0,
162
163     /**
164      * The group defines a logical collection of DragDrop objects that are
165      * related.  Instances only get events when interacting with other
166      * DragDrop object in the same group.  This lets us define multiple
167      * groups using a single DragDrop subclass if we want.
168      * @property groups
169      * @type {string: string}
170      */
171     groups: null,
172
173     /**
174      * Individual drag/drop instances can be locked.  This will prevent
175      * onmousedown start drag.
176      * @property locked
177      * @type boolean
178      * @private
179      */
180     locked: false,
181
182     /**
183      * Lock this instance
184      * @method lock
185      */
186     lock: function() { this.locked = true; },
187
188     /**
189      * Unlock this instace
190      * @method unlock
191      */
192     unlock: function() { this.locked = false; },
193
194     /**
195      * By default, all insances can be a drop target.  This can be disabled by
196      * setting isTarget to false.
197      * @method isTarget
198      * @type boolean
199      */
200     isTarget: true,
201
202     /**
203      * The padding configured for this drag and drop object for calculating
204      * the drop zone intersection with this object.
205      * @method padding
206      * @type int[]
207      */
208     padding: null,
209
210     /**
211      * Cached reference to the linked element
212      * @property _domRef
213      * @private
214      */
215     _domRef: null,
216
217     /**
218      * Internal typeof flag
219      * @property __ygDragDrop
220      * @private
221      */
222     __ygDragDrop: true,
223
224     /**
225      * Set to true when horizontal contraints are applied
226      * @property constrainX
227      * @type boolean
228      * @private
229      */
230     constrainX: false,
231
232     /**
233      * Set to true when vertical contraints are applied
234      * @property constrainY
235      * @type boolean
236      * @private
237      */
238     constrainY: false,
239
240     /**
241      * The left constraint
242      * @property minX
243      * @type int
244      * @private
245      */
246     minX: 0,
247
248     /**
249      * The right constraint
250      * @property maxX
251      * @type int
252      * @private
253      */
254     maxX: 0,
255
256     /**
257      * The up constraint
258      * @property minY
259      * @type int
260      * @type int
261      * @private
262      */
263     minY: 0,
264
265     /**
266      * The down constraint
267      * @property maxY
268      * @type int
269      * @private
270      */
271     maxY: 0,
272
273     /**
274      * Maintain offsets when we resetconstraints.  Set to true when you want
275      * the position of the element relative to its parent to stay the same
276      * when the page changes
277      *
278      * @property maintainOffset
279      * @type boolean
280      */
281     maintainOffset: false,
282
283     /**
284      * Array of pixel locations the element will snap to if we specified a
285      * horizontal graduation/interval.  This array is generated automatically
286      * when you define a tick interval.
287      * @property xTicks
288      * @type int[]
289      */
290     xTicks: null,
291
292     /**
293      * Array of pixel locations the element will snap to if we specified a
294      * vertical graduation/interval.  This array is generated automatically
295      * when you define a tick interval.
296      * @property yTicks
297      * @type int[]
298      */
299     yTicks: null,
300
301     /**
302      * By default the drag and drop instance will only respond to the primary
303      * button click (left button for a right-handed mouse).  Set to true to
304      * allow drag and drop to start with any mouse click that is propogated
305      * by the browser
306      * @property primaryButtonOnly
307      * @type boolean
308      */
309     primaryButtonOnly: true,
310
311     /**
312      * The availabe property is false until the linked dom element is accessible.
313      * @property available
314      * @type boolean
315      */
316     available: false,
317
318     /**
319      * By default, drags can only be initiated if the mousedown occurs in the
320      * region the linked element is.  This is done in part to work around a
321      * bug in some browsers that mis-report the mousedown if the previous
322      * mouseup happened outside of the window.  This property is set to true
323      * if outer handles are defined.
324      *
325      * @property hasOuterHandles
326      * @type boolean
327      * @default false
328      */
329     hasOuterHandles: false,
330
331     /**
332      * Code that executes immediately before the startDrag event
333      * @method b4StartDrag
334      * @private
335      */
336     b4StartDrag: function(x, y) { },
337
338     /**
339      * Abstract method called after a drag/drop object is clicked
340      * and the drag or mousedown time thresholds have beeen met.
341      * @method startDrag
342      * @param {int} X click location
343      * @param {int} Y click location
344      */
345     startDrag: function(x, y) { /* override this */ },
346
347     /**
348      * Code that executes immediately before the onDrag event
349      * @method b4Drag
350      * @private
351      */
352     b4Drag: function(e) { },
353
354     /**
355      * Abstract method called during the onMouseMove event while dragging an
356      * object.
357      * @method onDrag
358      * @param {Event} e the mousemove event
359      */
360     onDrag: function(e) { /* override this */ },
361
362     /**
363      * Abstract method called when this element fist begins hovering over
364      * another DragDrop obj
365      * @method onDragEnter
366      * @param {Event} e the mousemove event
367      * @param {String|DragDrop[]} id In POINT mode, the element
368      * id this is hovering over.  In INTERSECT mode, an array of one or more
369      * dragdrop items being hovered over.
370      */
371     onDragEnter: function(e, id) { /* override this */ },
372
373     /**
374      * Code that executes immediately before the onDragOver event
375      * @method b4DragOver
376      * @private
377      */
378     b4DragOver: function(e) { },
379
380     /**
381      * Abstract method called when this element is hovering over another
382      * DragDrop obj
383      * @method onDragOver
384      * @param {Event} e the mousemove event
385      * @param {String|DragDrop[]} id In POINT mode, the element
386      * id this is hovering over.  In INTERSECT mode, an array of dd items
387      * being hovered over.
388      */
389     onDragOver: function(e, id) { /* override this */ },
390
391     /**
392      * Code that executes immediately before the onDragOut event
393      * @method b4DragOut
394      * @private
395      */
396     b4DragOut: function(e) { },
397
398     /**
399      * Abstract method called when we are no longer hovering over an element
400      * @method onDragOut
401      * @param {Event} e the mousemove event
402      * @param {String|DragDrop[]} id In POINT mode, the element
403      * id this was hovering over.  In INTERSECT mode, an array of dd items
404      * that the mouse is no longer over.
405      */
406     onDragOut: function(e, id) { /* override this */ },
407
408     /**
409      * Code that executes immediately before the onDragDrop event
410      * @method b4DragDrop
411      * @private
412      */
413     b4DragDrop: function(e) { },
414
415     /**
416      * Abstract method called when this item is dropped on another DragDrop
417      * obj
418      * @method onDragDrop
419      * @param {Event} e the mouseup event
420      * @param {String|DragDrop[]} id In POINT mode, the element
421      * id this was dropped on.  In INTERSECT mode, an array of dd items this
422      * was dropped on.
423      */
424     onDragDrop: function(e, id) { /* override this */ },
425
426     /**
427      * Abstract method called when this item is dropped on an area with no
428      * drop target
429      * @method onInvalidDrop
430      * @param {Event} e the mouseup event
431      */
432     onInvalidDrop: function(e) { /* override this */ },
433
434     /**
435      * Code that executes immediately before the endDrag event
436      * @method b4EndDrag
437      * @private
438      */
439     b4EndDrag: function(e) { },
440
441     /**
442      * Fired when we are done dragging the object
443      * @method endDrag
444      * @param {Event} e the mouseup event
445      */
446     endDrag: function(e) { /* override this */ },
447
448     /**
449      * Code executed immediately before the onMouseDown event
450      * @method b4MouseDown
451      * @param {Event} e the mousedown event
452      * @private
453      */
454     b4MouseDown: function(e) {  },
455
456     /**
457      * Event handler that fires when a drag/drop obj gets a mousedown
458      * @method onMouseDown
459      * @param {Event} e the mousedown event
460      */
461     onMouseDown: function(e) { /* override this */ },
462
463     /**
464      * Event handler that fires when a drag/drop obj gets a mouseup
465      * @method onMouseUp
466      * @param {Event} e the mouseup event
467      */
468     onMouseUp: function(e) { /* override this */ },
469
470     /**
471      * Override the onAvailable method to do what is needed after the initial
472      * position was determined.
473      * @method onAvailable
474      */
475     onAvailable: function () {
476     },
477
478     /*
479      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
480      * @type Object
481      */
482     defaultPadding : {left:0, right:0, top:0, bottom:0},
483
484     /*
485      * Initializes the drag drop object's constraints to restrict movement to a certain element.
486  *
487  * Usage:
488  <pre><code>
489  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490                 { dragElId: "existingProxyDiv" });
491  dd.startDrag = function(){
492      this.constrainTo("parent-id");
493  };
494  </code></pre>
495  * Or you can initalize it using the {@link Roo.Element} object:
496  <pre><code>
497  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498      startDrag : function(){
499          this.constrainTo("parent-id");
500      }
501  });
502  </code></pre>
503      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506      * an object containing the sides to pad. For example: {right:10, bottom:10}
507      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
508      */
509     constrainTo : function(constrainTo, pad, inContent){
510         if(typeof pad == "number"){
511             pad = {left: pad, right:pad, top:pad, bottom:pad};
512         }
513         pad = pad || this.defaultPadding;
514         var b = Roo.get(this.getEl()).getBox();
515         var ce = Roo.get(constrainTo);
516         var s = ce.getScroll();
517         var c, cd = ce.dom;
518         if(cd == document.body){
519             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
520         }else{
521             xy = ce.getXY();
522             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
523         }
524
525
526         var topSpace = b.y - c.y;
527         var leftSpace = b.x - c.x;
528
529         this.resetConstraints();
530         this.setXConstraint(leftSpace - (pad.left||0), // left
531                 c.width - leftSpace - b.width - (pad.right||0) //right
532         );
533         this.setYConstraint(topSpace - (pad.top||0), //top
534                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
535         );
536     },
537
538     /**
539      * Returns a reference to the linked element
540      * @method getEl
541      * @return {HTMLElement} the html element
542      */
543     getEl: function() {
544         if (!this._domRef) {
545             this._domRef = Roo.getDom(this.id);
546         }
547
548         return this._domRef;
549     },
550
551     /**
552      * Returns a reference to the actual element to drag.  By default this is
553      * the same as the html element, but it can be assigned to another
554      * element. An example of this can be found in Roo.dd.DDProxy
555      * @method getDragEl
556      * @return {HTMLElement} the html element
557      */
558     getDragEl: function() {
559         return Roo.getDom(this.dragElId);
560     },
561
562     /**
563      * Sets up the DragDrop object.  Must be called in the constructor of any
564      * Roo.dd.DragDrop subclass
565      * @method init
566      * @param id the id of the linked element
567      * @param {String} sGroup the group of related items
568      * @param {object} config configuration attributes
569      */
570     init: function(id, sGroup, config) {
571         this.initTarget(id, sGroup, config);
572         Event.on(this.id, "mousedown", this.handleMouseDown, this);
573         // Event.on(this.id, "selectstart", Event.preventDefault);
574     },
575
576     /**
577      * Initializes Targeting functionality only... the object does not
578      * get a mousedown handler.
579      * @method initTarget
580      * @param id the id of the linked element
581      * @param {String} sGroup the group of related items
582      * @param {object} config configuration attributes
583      */
584     initTarget: function(id, sGroup, config) {
585
586         // configuration attributes
587         this.config = config || {};
588
589         // create a local reference to the drag and drop manager
590         this.DDM = Roo.dd.DDM;
591         // initialize the groups array
592         this.groups = {};
593
594         // assume that we have an element reference instead of an id if the
595         // parameter is not a string
596         if (typeof id !== "string") {
597             id = Roo.id(id);
598         }
599
600         // set the id
601         this.id = id;
602
603         // add to an interaction group
604         this.addToGroup((sGroup) ? sGroup : "default");
605
606         // We don't want to register this as the handle with the manager
607         // so we just set the id rather than calling the setter.
608         this.handleElId = id;
609
610         // the linked element is the element that gets dragged by default
611         this.setDragElId(id);
612
613         // by default, clicked anchors will not start drag operations.
614         this.invalidHandleTypes = { A: "A" };
615         this.invalidHandleIds = {};
616         this.invalidHandleClasses = [];
617
618         this.applyConfig();
619
620         this.handleOnAvailable();
621     },
622
623     /**
624      * Applies the configuration parameters that were passed into the constructor.
625      * This is supposed to happen at each level through the inheritance chain.  So
626      * a DDProxy implentation will execute apply config on DDProxy, DD, and
627      * DragDrop in order to get all of the parameters that are available in
628      * each object.
629      * @method applyConfig
630      */
631     applyConfig: function() {
632
633         // configurable properties:
634         //    padding, isTarget, maintainOffset, primaryButtonOnly
635         this.padding           = this.config.padding || [0, 0, 0, 0];
636         this.isTarget          = (this.config.isTarget !== false);
637         this.maintainOffset    = (this.config.maintainOffset);
638         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
639
640     },
641
642     /**
643      * Executed when the linked element is available
644      * @method handleOnAvailable
645      * @private
646      */
647     handleOnAvailable: function() {
648         this.available = true;
649         this.resetConstraints();
650         this.onAvailable();
651     },
652
653      /**
654      * Configures the padding for the target zone in px.  Effectively expands
655      * (or reduces) the virtual object size for targeting calculations.
656      * Supports css-style shorthand; if only one parameter is passed, all sides
657      * will have that padding, and if only two are passed, the top and bottom
658      * will have the first param, the left and right the second.
659      * @method setPadding
660      * @param {int} iTop    Top pad
661      * @param {int} iRight  Right pad
662      * @param {int} iBot    Bot pad
663      * @param {int} iLeft   Left pad
664      */
665     setPadding: function(iTop, iRight, iBot, iLeft) {
666         // this.padding = [iLeft, iRight, iTop, iBot];
667         if (!iRight && 0 !== iRight) {
668             this.padding = [iTop, iTop, iTop, iTop];
669         } else if (!iBot && 0 !== iBot) {
670             this.padding = [iTop, iRight, iTop, iRight];
671         } else {
672             this.padding = [iTop, iRight, iBot, iLeft];
673         }
674     },
675
676     /**
677      * Stores the initial placement of the linked element.
678      * @method setInitialPosition
679      * @param {int} diffX   the X offset, default 0
680      * @param {int} diffY   the Y offset, default 0
681      */
682     setInitPosition: function(diffX, diffY) {
683         var el = this.getEl();
684
685         if (!this.DDM.verifyEl(el)) {
686             return;
687         }
688
689         var dx = diffX || 0;
690         var dy = diffY || 0;
691
692         var p = Dom.getXY( el );
693
694         this.initPageX = p[0] - dx;
695         this.initPageY = p[1] - dy;
696
697         this.lastPageX = p[0];
698         this.lastPageY = p[1];
699
700
701         this.setStartPosition(p);
702     },
703
704     /**
705      * Sets the start position of the element.  This is set when the obj
706      * is initialized, the reset when a drag is started.
707      * @method setStartPosition
708      * @param pos current position (from previous lookup)
709      * @private
710      */
711     setStartPosition: function(pos) {
712         var p = pos || Dom.getXY( this.getEl() );
713         this.deltaSetXY = null;
714
715         this.startPageX = p[0];
716         this.startPageY = p[1];
717     },
718
719     /**
720      * Add this instance to a group of related drag/drop objects.  All
721      * instances belong to at least one group, and can belong to as many
722      * groups as needed.
723      * @method addToGroup
724      * @param sGroup {string} the name of the group
725      */
726     addToGroup: function(sGroup) {
727         this.groups[sGroup] = true;
728         this.DDM.regDragDrop(this, sGroup);
729     },
730
731     /**
732      * Remove's this instance from the supplied interaction group
733      * @method removeFromGroup
734      * @param {string}  sGroup  The group to drop
735      */
736     removeFromGroup: function(sGroup) {
737         if (this.groups[sGroup]) {
738             delete this.groups[sGroup];
739         }
740
741         this.DDM.removeDDFromGroup(this, sGroup);
742     },
743
744     /**
745      * Allows you to specify that an element other than the linked element
746      * will be moved with the cursor during a drag
747      * @method setDragElId
748      * @param id {string} the id of the element that will be used to initiate the drag
749      */
750     setDragElId: function(id) {
751         this.dragElId = id;
752     },
753
754     /**
755      * Allows you to specify a child of the linked element that should be
756      * used to initiate the drag operation.  An example of this would be if
757      * you have a content div with text and links.  Clicking anywhere in the
758      * content area would normally start the drag operation.  Use this method
759      * to specify that an element inside of the content div is the element
760      * that starts the drag operation.
761      * @method setHandleElId
762      * @param id {string} the id of the element that will be used to
763      * initiate the drag.
764      */
765     setHandleElId: function(id) {
766         if (typeof id !== "string") {
767             id = Roo.id(id);
768         }
769         this.handleElId = id;
770         this.DDM.regHandle(this.id, id);
771     },
772
773     /**
774      * Allows you to set an element outside of the linked element as a drag
775      * handle
776      * @method setOuterHandleElId
777      * @param id the id of the element that will be used to initiate the drag
778      */
779     setOuterHandleElId: function(id) {
780         if (typeof id !== "string") {
781             id = Roo.id(id);
782         }
783         Event.on(id, "mousedown",
784                 this.handleMouseDown, this);
785         this.setHandleElId(id);
786
787         this.hasOuterHandles = true;
788     },
789
790     /**
791      * Remove all drag and drop hooks for this element
792      * @method unreg
793      */
794     unreg: function() {
795         Event.un(this.id, "mousedown",
796                 this.handleMouseDown);
797         this._domRef = null;
798         this.DDM._remove(this);
799     },
800
801     destroy : function(){
802         this.unreg();
803     },
804
805     /**
806      * Returns true if this instance is locked, or the drag drop mgr is locked
807      * (meaning that all drag/drop is disabled on the page.)
808      * @method isLocked
809      * @return {boolean} true if this obj or all drag/drop is locked, else
810      * false
811      */
812     isLocked: function() {
813         return (this.DDM.isLocked() || this.locked);
814     },
815
816     /**
817      * Fired when this object is clicked
818      * @method handleMouseDown
819      * @param {Event} e
820      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
821      * @private
822      */
823     handleMouseDown: function(e, oDD){
824         if (this.primaryButtonOnly && e.button != 0) {
825             return;
826         }
827
828         if (this.isLocked()) {
829             return;
830         }
831
832         this.DDM.refreshCache(this.groups);
833
834         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
836         } else {
837             if (this.clickValidator(e)) {
838
839                 // set the initial element position
840                 this.setStartPosition();
841
842
843                 this.b4MouseDown(e);
844                 this.onMouseDown(e);
845
846                 this.DDM.handleMouseDown(e, this);
847
848                 this.DDM.stopEvent(e);
849             } else {
850
851
852             }
853         }
854     },
855
856     clickValidator: function(e) {
857         var target = e.getTarget();
858         return ( this.isValidHandleChild(target) &&
859                     (this.id == this.handleElId ||
860                         this.DDM.handleWasClicked(target, this.id)) );
861     },
862
863     /**
864      * Allows you to specify a tag name that should not start a drag operation
865      * when clicked.  This is designed to facilitate embedding links within a
866      * drag handle that do something other than start the drag.
867      * @method addInvalidHandleType
868      * @param {string} tagName the type of element to exclude
869      */
870     addInvalidHandleType: function(tagName) {
871         var type = tagName.toUpperCase();
872         this.invalidHandleTypes[type] = type;
873     },
874
875     /**
876      * Lets you to specify an element id for a child of a drag handle
877      * that should not initiate a drag
878      * @method addInvalidHandleId
879      * @param {string} id the element id of the element you wish to ignore
880      */
881     addInvalidHandleId: function(id) {
882         if (typeof id !== "string") {
883             id = Roo.id(id);
884         }
885         this.invalidHandleIds[id] = id;
886     },
887
888     /**
889      * Lets you specify a css class of elements that will not initiate a drag
890      * @method addInvalidHandleClass
891      * @param {string} cssClass the class of the elements you wish to ignore
892      */
893     addInvalidHandleClass: function(cssClass) {
894         this.invalidHandleClasses.push(cssClass);
895     },
896
897     /**
898      * Unsets an excluded tag name set by addInvalidHandleType
899      * @method removeInvalidHandleType
900      * @param {string} tagName the type of element to unexclude
901      */
902     removeInvalidHandleType: function(tagName) {
903         var type = tagName.toUpperCase();
904         // this.invalidHandleTypes[type] = null;
905         delete this.invalidHandleTypes[type];
906     },
907
908     /**
909      * Unsets an invalid handle id
910      * @method removeInvalidHandleId
911      * @param {string} id the id of the element to re-enable
912      */
913     removeInvalidHandleId: function(id) {
914         if (typeof id !== "string") {
915             id = Roo.id(id);
916         }
917         delete this.invalidHandleIds[id];
918     },
919
920     /**
921      * Unsets an invalid css class
922      * @method removeInvalidHandleClass
923      * @param {string} cssClass the class of the element(s) you wish to
924      * re-enable
925      */
926     removeInvalidHandleClass: function(cssClass) {
927         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928             if (this.invalidHandleClasses[i] == cssClass) {
929                 delete this.invalidHandleClasses[i];
930             }
931         }
932     },
933
934     /**
935      * Checks the tag exclusion list to see if this click should be ignored
936      * @method isValidHandleChild
937      * @param {HTMLElement} node the HTMLElement to evaluate
938      * @return {boolean} true if this is a valid tag type, false if not
939      */
940     isValidHandleChild: function(node) {
941
942         var valid = true;
943         // var n = (node.nodeName == "#text") ? node.parentNode : node;
944         var nodeName;
945         try {
946             nodeName = node.nodeName.toUpperCase();
947         } catch(e) {
948             nodeName = node.nodeName;
949         }
950         valid = valid && !this.invalidHandleTypes[nodeName];
951         valid = valid && !this.invalidHandleIds[node.id];
952
953         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
955         }
956
957
958         return valid;
959
960     },
961
962     /**
963      * Create the array of horizontal tick marks if an interval was specified
964      * in setXConstraint().
965      * @method setXTicks
966      * @private
967      */
968     setXTicks: function(iStartX, iTickSize) {
969         this.xTicks = [];
970         this.xTickSize = iTickSize;
971
972         var tickMap = {};
973
974         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
975             if (!tickMap[i]) {
976                 this.xTicks[this.xTicks.length] = i;
977                 tickMap[i] = true;
978             }
979         }
980
981         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
982             if (!tickMap[i]) {
983                 this.xTicks[this.xTicks.length] = i;
984                 tickMap[i] = true;
985             }
986         }
987
988         this.xTicks.sort(this.DDM.numericSort) ;
989     },
990
991     /**
992      * Create the array of vertical tick marks if an interval was specified in
993      * setYConstraint().
994      * @method setYTicks
995      * @private
996      */
997     setYTicks: function(iStartY, iTickSize) {
998         this.yTicks = [];
999         this.yTickSize = iTickSize;
1000
1001         var tickMap = {};
1002
1003         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1004             if (!tickMap[i]) {
1005                 this.yTicks[this.yTicks.length] = i;
1006                 tickMap[i] = true;
1007             }
1008         }
1009
1010         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1011             if (!tickMap[i]) {
1012                 this.yTicks[this.yTicks.length] = i;
1013                 tickMap[i] = true;
1014             }
1015         }
1016
1017         this.yTicks.sort(this.DDM.numericSort) ;
1018     },
1019
1020     /**
1021      * By default, the element can be dragged any place on the screen.  Use
1022      * this method to limit the horizontal travel of the element.  Pass in
1023      * 0,0 for the parameters if you want to lock the drag to the y axis.
1024      * @method setXConstraint
1025      * @param {int} iLeft the number of pixels the element can move to the left
1026      * @param {int} iRight the number of pixels the element can move to the
1027      * right
1028      * @param {int} iTickSize optional parameter for specifying that the
1029      * element
1030      * should move iTickSize pixels at a time.
1031      */
1032     setXConstraint: function(iLeft, iRight, iTickSize) {
1033         this.leftConstraint = iLeft;
1034         this.rightConstraint = iRight;
1035
1036         this.minX = this.initPageX - iLeft;
1037         this.maxX = this.initPageX + iRight;
1038         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1039
1040         this.constrainX = true;
1041     },
1042
1043     /**
1044      * Clears any constraints applied to this instance.  Also clears ticks
1045      * since they can't exist independent of a constraint at this time.
1046      * @method clearConstraints
1047      */
1048     clearConstraints: function() {
1049         this.constrainX = false;
1050         this.constrainY = false;
1051         this.clearTicks();
1052     },
1053
1054     /**
1055      * Clears any tick interval defined for this instance
1056      * @method clearTicks
1057      */
1058     clearTicks: function() {
1059         this.xTicks = null;
1060         this.yTicks = null;
1061         this.xTickSize = 0;
1062         this.yTickSize = 0;
1063     },
1064
1065     /**
1066      * By default, the element can be dragged any place on the screen.  Set
1067      * this to limit the vertical travel of the element.  Pass in 0,0 for the
1068      * parameters if you want to lock the drag to the x axis.
1069      * @method setYConstraint
1070      * @param {int} iUp the number of pixels the element can move up
1071      * @param {int} iDown the number of pixels the element can move down
1072      * @param {int} iTickSize optional parameter for specifying that the
1073      * element should move iTickSize pixels at a time.
1074      */
1075     setYConstraint: function(iUp, iDown, iTickSize) {
1076         this.topConstraint = iUp;
1077         this.bottomConstraint = iDown;
1078
1079         this.minY = this.initPageY - iUp;
1080         this.maxY = this.initPageY + iDown;
1081         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1082
1083         this.constrainY = true;
1084
1085     },
1086
1087     /**
1088      * resetConstraints must be called if you manually reposition a dd element.
1089      * @method resetConstraints
1090      * @param {boolean} maintainOffset
1091      */
1092     resetConstraints: function() {
1093
1094
1095         // Maintain offsets if necessary
1096         if (this.initPageX || this.initPageX === 0) {
1097             // figure out how much this thing has moved
1098             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1100
1101             this.setInitPosition(dx, dy);
1102
1103         // This is the first time we have detected the element's position
1104         } else {
1105             this.setInitPosition();
1106         }
1107
1108         if (this.constrainX) {
1109             this.setXConstraint( this.leftConstraint,
1110                                  this.rightConstraint,
1111                                  this.xTickSize        );
1112         }
1113
1114         if (this.constrainY) {
1115             this.setYConstraint( this.topConstraint,
1116                                  this.bottomConstraint,
1117                                  this.yTickSize         );
1118         }
1119     },
1120
1121     /**
1122      * Normally the drag element is moved pixel by pixel, but we can specify
1123      * that it move a number of pixels at a time.  This method resolves the
1124      * location when we have it set up like this.
1125      * @method getTick
1126      * @param {int} val where we want to place the object
1127      * @param {int[]} tickArray sorted array of valid points
1128      * @return {int} the closest tick
1129      * @private
1130      */
1131     getTick: function(val, tickArray) {
1132
1133         if (!tickArray) {
1134             // If tick interval is not defined, it is effectively 1 pixel,
1135             // so we return the value passed to us.
1136             return val;
1137         } else if (tickArray[0] >= val) {
1138             // The value is lower than the first tick, so we return the first
1139             // tick.
1140             return tickArray[0];
1141         } else {
1142             for (var i=0, len=tickArray.length; i<len; ++i) {
1143                 var next = i + 1;
1144                 if (tickArray[next] && tickArray[next] >= val) {
1145                     var diff1 = val - tickArray[i];
1146                     var diff2 = tickArray[next] - val;
1147                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1148                 }
1149             }
1150
1151             // The value is larger than the last tick, so we return the last
1152             // tick.
1153             return tickArray[tickArray.length - 1];
1154         }
1155     },
1156
1157     /**
1158      * toString method
1159      * @method toString
1160      * @return {string} string representation of the dd obj
1161      */
1162     toString: function() {
1163         return ("DragDrop " + this.id);
1164     }
1165
1166 });
1167
1168 })();
1169 /*
1170  * Based on:
1171  * Ext JS Library 1.1.1
1172  * Copyright(c) 2006-2007, Ext JS, LLC.
1173  *
1174  * Originally Released Under LGPL - original licence link has changed is not relivant.
1175  *
1176  * Fork - LGPL
1177  * <script type="text/javascript">
1178  */
1179
1180
1181 /**
1182  * The drag and drop utility provides a framework for building drag and drop
1183  * applications.  In addition to enabling drag and drop for specific elements,
1184  * the drag and drop elements are tracked by the manager class, and the
1185  * interactions between the various elements are tracked during the drag and
1186  * the implementing code is notified about these important moments.
1187  */
1188
1189 // Only load the library once.  Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1192
1193 /**
1194  * @class Roo.dd.DragDropMgr
1195  * DragDropMgr is a singleton that tracks the element interaction for
1196  * all DragDrop items in the window.  Generally, you will not call
1197  * this class directly, but it does have helper methods that could
1198  * be useful in your DragDrop implementations.
1199  * @singleton
1200  */
1201 Roo.dd.DragDropMgr = function() {
1202
1203     var Event = Roo.EventManager;
1204
1205     return {
1206
1207         /**
1208          * Two dimensional Array of registered DragDrop objects.  The first
1209          * dimension is the DragDrop item group, the second the DragDrop
1210          * object.
1211          * @property ids
1212          * @type {string: string}
1213          * @private
1214          * @static
1215          */
1216         ids: {},
1217
1218         /**
1219          * Array of element ids defined as drag handles.  Used to determine
1220          * if the element that generated the mousedown event is actually the
1221          * handle and not the html element itself.
1222          * @property handleIds
1223          * @type {string: string}
1224          * @private
1225          * @static
1226          */
1227         handleIds: {},
1228
1229         /**
1230          * the DragDrop object that is currently being dragged
1231          * @property dragCurrent
1232          * @type DragDrop
1233          * @private
1234          * @static
1235          **/
1236         dragCurrent: null,
1237
1238         /**
1239          * the DragDrop object(s) that are being hovered over
1240          * @property dragOvers
1241          * @type Array
1242          * @private
1243          * @static
1244          */
1245         dragOvers: {},
1246
1247         /**
1248          * the X distance between the cursor and the object being dragged
1249          * @property deltaX
1250          * @type int
1251          * @private
1252          * @static
1253          */
1254         deltaX: 0,
1255
1256         /**
1257          * the Y distance between the cursor and the object being dragged
1258          * @property deltaY
1259          * @type int
1260          * @private
1261          * @static
1262          */
1263         deltaY: 0,
1264
1265         /**
1266          * Flag to determine if we should prevent the default behavior of the
1267          * events we define. By default this is true, but this can be set to
1268          * false if you need the default behavior (not recommended)
1269          * @property preventDefault
1270          * @type boolean
1271          * @static
1272          */
1273         preventDefault: true,
1274
1275         /**
1276          * Flag to determine if we should stop the propagation of the events
1277          * we generate. This is true by default but you may want to set it to
1278          * false if the html element contains other features that require the
1279          * mouse click.
1280          * @property stopPropagation
1281          * @type boolean
1282          * @static
1283          */
1284         stopPropagation: true,
1285
1286         /**
1287          * Internal flag that is set to true when drag and drop has been
1288          * intialized
1289          * @property initialized
1290          * @private
1291          * @static
1292          */
1293         initalized: false,
1294
1295         /**
1296          * All drag and drop can be disabled.
1297          * @property locked
1298          * @private
1299          * @static
1300          */
1301         locked: false,
1302
1303         /**
1304          * Called the first time an element is registered.
1305          * @method init
1306          * @private
1307          * @static
1308          */
1309         init: function() {
1310             this.initialized = true;
1311         },
1312
1313         /**
1314          * In point mode, drag and drop interaction is defined by the
1315          * location of the cursor during the drag/drop
1316          * @property POINT
1317          * @type int
1318          * @static
1319          */
1320         POINT: 0,
1321
1322         /**
1323          * In intersect mode, drag and drop interactio nis defined by the
1324          * overlap of two or more drag and drop objects.
1325          * @property INTERSECT
1326          * @type int
1327          * @static
1328          */
1329         INTERSECT: 1,
1330
1331         /**
1332          * The current drag and drop mode.  Default: POINT
1333          * @property mode
1334          * @type int
1335          * @static
1336          */
1337         mode: 0,
1338
1339         /**
1340          * Runs method on all drag and drop objects
1341          * @method _execOnAll
1342          * @private
1343          * @static
1344          */
1345         _execOnAll: function(sMethod, args) {
1346             for (var i in this.ids) {
1347                 for (var j in this.ids[i]) {
1348                     var oDD = this.ids[i][j];
1349                     if (! this.isTypeOfDD(oDD)) {
1350                         continue;
1351                     }
1352                     oDD[sMethod].apply(oDD, args);
1353                 }
1354             }
1355         },
1356
1357         /**
1358          * Drag and drop initialization.  Sets up the global event handlers
1359          * @method _onLoad
1360          * @private
1361          * @static
1362          */
1363         _onLoad: function() {
1364
1365             this.init();
1366
1367
1368             Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1369             Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370             Event.on(window,   "unload",    this._onUnload, this, true);
1371             Event.on(window,   "resize",    this._onResize, this, true);
1372             // Event.on(window,   "mouseout",    this._test);
1373
1374         },
1375
1376         /**
1377          * Reset constraints on all drag and drop objs
1378          * @method _onResize
1379          * @private
1380          * @static
1381          */
1382         _onResize: function(e) {
1383             this._execOnAll("resetConstraints", []);
1384         },
1385
1386         /**
1387          * Lock all drag and drop functionality
1388          * @method lock
1389          * @static
1390          */
1391         lock: function() { this.locked = true; },
1392
1393         /**
1394          * Unlock all drag and drop functionality
1395          * @method unlock
1396          * @static
1397          */
1398         unlock: function() { this.locked = false; },
1399
1400         /**
1401          * Is drag and drop locked?
1402          * @method isLocked
1403          * @return {boolean} True if drag and drop is locked, false otherwise.
1404          * @static
1405          */
1406         isLocked: function() { return this.locked; },
1407
1408         /**
1409          * Location cache that is set for all drag drop objects when a drag is
1410          * initiated, cleared when the drag is finished.
1411          * @property locationCache
1412          * @private
1413          * @static
1414          */
1415         locationCache: {},
1416
1417         /**
1418          * Set useCache to false if you want to force object the lookup of each
1419          * drag and drop linked element constantly during a drag.
1420          * @property useCache
1421          * @type boolean
1422          * @static
1423          */
1424         useCache: true,
1425
1426         /**
1427          * The number of pixels that the mouse needs to move after the
1428          * mousedown before the drag is initiated.  Default=3;
1429          * @property clickPixelThresh
1430          * @type int
1431          * @static
1432          */
1433         clickPixelThresh: 3,
1434
1435         /**
1436          * The number of milliseconds after the mousedown event to initiate the
1437          * drag if we don't get a mouseup event. Default=1000
1438          * @property clickTimeThresh
1439          * @type int
1440          * @static
1441          */
1442         clickTimeThresh: 350,
1443
1444         /**
1445          * Flag that indicates that either the drag pixel threshold or the
1446          * mousdown time threshold has been met
1447          * @property dragThreshMet
1448          * @type boolean
1449          * @private
1450          * @static
1451          */
1452         dragThreshMet: false,
1453
1454         /**
1455          * Timeout used for the click time threshold
1456          * @property clickTimeout
1457          * @type Object
1458          * @private
1459          * @static
1460          */
1461         clickTimeout: null,
1462
1463         /**
1464          * The X position of the mousedown event stored for later use when a
1465          * drag threshold is met.
1466          * @property startX
1467          * @type int
1468          * @private
1469          * @static
1470          */
1471         startX: 0,
1472
1473         /**
1474          * The Y position of the mousedown event stored for later use when a
1475          * drag threshold is met.
1476          * @property startY
1477          * @type int
1478          * @private
1479          * @static
1480          */
1481         startY: 0,
1482
1483         /**
1484          * Each DragDrop instance must be registered with the DragDropMgr.
1485          * This is executed in DragDrop.init()
1486          * @method regDragDrop
1487          * @param {DragDrop} oDD the DragDrop object to register
1488          * @param {String} sGroup the name of the group this element belongs to
1489          * @static
1490          */
1491         regDragDrop: function(oDD, sGroup) {
1492             if (!this.initialized) { this.init(); }
1493
1494             if (!this.ids[sGroup]) {
1495                 this.ids[sGroup] = {};
1496             }
1497             this.ids[sGroup][oDD.id] = oDD;
1498         },
1499
1500         /**
1501          * Removes the supplied dd instance from the supplied group. Executed
1502          * by DragDrop.removeFromGroup, so don't call this function directly.
1503          * @method removeDDFromGroup
1504          * @private
1505          * @static
1506          */
1507         removeDDFromGroup: function(oDD, sGroup) {
1508             if (!this.ids[sGroup]) {
1509                 this.ids[sGroup] = {};
1510             }
1511
1512             var obj = this.ids[sGroup];
1513             if (obj && obj[oDD.id]) {
1514                 delete obj[oDD.id];
1515             }
1516         },
1517
1518         /**
1519          * Unregisters a drag and drop item.  This is executed in
1520          * DragDrop.unreg, use that method instead of calling this directly.
1521          * @method _remove
1522          * @private
1523          * @static
1524          */
1525         _remove: function(oDD) {
1526             for (var g in oDD.groups) {
1527                 if (g && this.ids[g][oDD.id]) {
1528                     delete this.ids[g][oDD.id];
1529                 }
1530             }
1531             delete this.handleIds[oDD.id];
1532         },
1533
1534         /**
1535          * Each DragDrop handle element must be registered.  This is done
1536          * automatically when executing DragDrop.setHandleElId()
1537          * @method regHandle
1538          * @param {String} sDDId the DragDrop id this element is a handle for
1539          * @param {String} sHandleId the id of the element that is the drag
1540          * handle
1541          * @static
1542          */
1543         regHandle: function(sDDId, sHandleId) {
1544             if (!this.handleIds[sDDId]) {
1545                 this.handleIds[sDDId] = {};
1546             }
1547             this.handleIds[sDDId][sHandleId] = sHandleId;
1548         },
1549
1550         /**
1551          * Utility function to determine if a given element has been
1552          * registered as a drag drop item.
1553          * @method isDragDrop
1554          * @param {String} id the element id to check
1555          * @return {boolean} true if this element is a DragDrop item,
1556          * false otherwise
1557          * @static
1558          */
1559         isDragDrop: function(id) {
1560             return ( this.getDDById(id) ) ? true : false;
1561         },
1562
1563         /**
1564          * Returns the drag and drop instances that are in all groups the
1565          * passed in instance belongs to.
1566          * @method getRelated
1567          * @param {DragDrop} p_oDD the obj to get related data for
1568          * @param {boolean} bTargetsOnly if true, only return targetable objs
1569          * @return {DragDrop[]} the related instances
1570          * @static
1571          */
1572         getRelated: function(p_oDD, bTargetsOnly) {
1573             var oDDs = [];
1574             for (var i in p_oDD.groups) {
1575                 for (j in this.ids[i]) {
1576                     var dd = this.ids[i][j];
1577                     if (! this.isTypeOfDD(dd)) {
1578                         continue;
1579                     }
1580                     if (!bTargetsOnly || dd.isTarget) {
1581                         oDDs[oDDs.length] = dd;
1582                     }
1583                 }
1584             }
1585
1586             return oDDs;
1587         },
1588
1589         /**
1590          * Returns true if the specified dd target is a legal target for
1591          * the specifice drag obj
1592          * @method isLegalTarget
1593          * @param {DragDrop} the drag obj
1594          * @param {DragDrop} the target
1595          * @return {boolean} true if the target is a legal target for the
1596          * dd obj
1597          * @static
1598          */
1599         isLegalTarget: function (oDD, oTargetDD) {
1600             var targets = this.getRelated(oDD, true);
1601             for (var i=0, len=targets.length;i<len;++i) {
1602                 if (targets[i].id == oTargetDD.id) {
1603                     return true;
1604                 }
1605             }
1606
1607             return false;
1608         },
1609
1610         /**
1611          * My goal is to be able to transparently determine if an object is
1612          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1613          * returns "object", oDD.constructor.toString() always returns
1614          * "DragDrop" and not the name of the subclass.  So for now it just
1615          * evaluates a well-known variable in DragDrop.
1616          * @method isTypeOfDD
1617          * @param {Object} the object to evaluate
1618          * @return {boolean} true if typeof oDD = DragDrop
1619          * @static
1620          */
1621         isTypeOfDD: function (oDD) {
1622             return (oDD && oDD.__ygDragDrop);
1623         },
1624
1625         /**
1626          * Utility function to determine if a given element has been
1627          * registered as a drag drop handle for the given Drag Drop object.
1628          * @method isHandle
1629          * @param {String} id the element id to check
1630          * @return {boolean} true if this element is a DragDrop handle, false
1631          * otherwise
1632          * @static
1633          */
1634         isHandle: function(sDDId, sHandleId) {
1635             return ( this.handleIds[sDDId] &&
1636                             this.handleIds[sDDId][sHandleId] );
1637         },
1638
1639         /**
1640          * Returns the DragDrop instance for a given id
1641          * @method getDDById
1642          * @param {String} id the id of the DragDrop object
1643          * @return {DragDrop} the drag drop object, null if it is not found
1644          * @static
1645          */
1646         getDDById: function(id) {
1647             for (var i in this.ids) {
1648                 if (this.ids[i][id]) {
1649                     return this.ids[i][id];
1650                 }
1651             }
1652             return null;
1653         },
1654
1655         /**
1656          * Fired after a registered DragDrop object gets the mousedown event.
1657          * Sets up the events required to track the object being dragged
1658          * @method handleMouseDown
1659          * @param {Event} e the event
1660          * @param oDD the DragDrop object being dragged
1661          * @private
1662          * @static
1663          */
1664         handleMouseDown: function(e, oDD) {
1665             if(Roo.QuickTips){
1666                 Roo.QuickTips.disable();
1667             }
1668             this.currentTarget = e.getTarget();
1669
1670             this.dragCurrent = oDD;
1671
1672             var el = oDD.getEl();
1673
1674             // track start position
1675             this.startX = e.getPageX();
1676             this.startY = e.getPageY();
1677
1678             this.deltaX = this.startX - el.offsetLeft;
1679             this.deltaY = this.startY - el.offsetTop;
1680
1681             this.dragThreshMet = false;
1682
1683             this.clickTimeout = setTimeout(
1684                     function() {
1685                         var DDM = Roo.dd.DDM;
1686                         DDM.startDrag(DDM.startX, DDM.startY);
1687                     },
1688                     this.clickTimeThresh );
1689         },
1690
1691         /**
1692          * Fired when either the drag pixel threshol or the mousedown hold
1693          * time threshold has been met.
1694          * @method startDrag
1695          * @param x {int} the X position of the original mousedown
1696          * @param y {int} the Y position of the original mousedown
1697          * @static
1698          */
1699         startDrag: function(x, y) {
1700             clearTimeout(this.clickTimeout);
1701             if (this.dragCurrent) {
1702                 this.dragCurrent.b4StartDrag(x, y);
1703                 this.dragCurrent.startDrag(x, y);
1704             }
1705             this.dragThreshMet = true;
1706         },
1707
1708         /**
1709          * Internal function to handle the mouseup event.  Will be invoked
1710          * from the context of the document.
1711          * @method handleMouseUp
1712          * @param {Event} e the event
1713          * @private
1714          * @static
1715          */
1716         handleMouseUp: function(e) {
1717
1718             if(Roo.QuickTips){
1719                 Roo.QuickTips.enable();
1720             }
1721             if (! this.dragCurrent) {
1722                 return;
1723             }
1724
1725             clearTimeout(this.clickTimeout);
1726
1727             if (this.dragThreshMet) {
1728                 this.fireEvents(e, true);
1729             } else {
1730             }
1731
1732             this.stopDrag(e);
1733
1734             this.stopEvent(e);
1735         },
1736
1737         /**
1738          * Utility to stop event propagation and event default, if these
1739          * features are turned on.
1740          * @method stopEvent
1741          * @param {Event} e the event as returned by this.getEvent()
1742          * @static
1743          */
1744         stopEvent: function(e){
1745             if(this.stopPropagation) {
1746                 e.stopPropagation();
1747             }
1748
1749             if (this.preventDefault) {
1750                 e.preventDefault();
1751             }
1752         },
1753
1754         /**
1755          * Internal function to clean up event handlers after the drag
1756          * operation is complete
1757          * @method stopDrag
1758          * @param {Event} e the event
1759          * @private
1760          * @static
1761          */
1762         stopDrag: function(e) {
1763             // Fire the drag end event for the item that was dragged
1764             if (this.dragCurrent) {
1765                 if (this.dragThreshMet) {
1766                     this.dragCurrent.b4EndDrag(e);
1767                     this.dragCurrent.endDrag(e);
1768                 }
1769
1770                 this.dragCurrent.onMouseUp(e);
1771             }
1772
1773             this.dragCurrent = null;
1774             this.dragOvers = {};
1775         },
1776
1777         /**
1778          * Internal function to handle the mousemove event.  Will be invoked
1779          * from the context of the html element.
1780          *
1781          * @TODO figure out what we can do about mouse events lost when the
1782          * user drags objects beyond the window boundary.  Currently we can
1783          * detect this in internet explorer by verifying that the mouse is
1784          * down during the mousemove event.  Firefox doesn't give us the
1785          * button state on the mousemove event.
1786          * @method handleMouseMove
1787          * @param {Event} e the event
1788          * @private
1789          * @static
1790          */
1791         handleMouseMove: function(e) {
1792             if (! this.dragCurrent) {
1793                 return true;
1794             }
1795
1796             // var button = e.which || e.button;
1797
1798             // check for IE mouseup outside of page boundary
1799             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1800                 this.stopEvent(e);
1801                 return this.handleMouseUp(e);
1802             }
1803
1804             if (!this.dragThreshMet) {
1805                 var diffX = Math.abs(this.startX - e.getPageX());
1806                 var diffY = Math.abs(this.startY - e.getPageY());
1807                 if (diffX > this.clickPixelThresh ||
1808                             diffY > this.clickPixelThresh) {
1809                     this.startDrag(this.startX, this.startY);
1810                 }
1811             }
1812
1813             if (this.dragThreshMet) {
1814                 this.dragCurrent.b4Drag(e);
1815                 this.dragCurrent.onDrag(e);
1816                 if(!this.dragCurrent.moveOnly){
1817                     this.fireEvents(e, false);
1818                 }
1819             }
1820
1821             this.stopEvent(e);
1822
1823             return true;
1824         },
1825
1826         /**
1827          * Iterates over all of the DragDrop elements to find ones we are
1828          * hovering over or dropping on
1829          * @method fireEvents
1830          * @param {Event} e the event
1831          * @param {boolean} isDrop is this a drop op or a mouseover op?
1832          * @private
1833          * @static
1834          */
1835         fireEvents: function(e, isDrop) {
1836             var dc = this.dragCurrent;
1837
1838             // If the user did the mouse up outside of the window, we could
1839             // get here even though we have ended the drag.
1840             if (!dc || dc.isLocked()) {
1841                 return;
1842             }
1843
1844             var pt = e.getPoint();
1845
1846             // cache the previous dragOver array
1847             var oldOvers = [];
1848
1849             var outEvts   = [];
1850             var overEvts  = [];
1851             var dropEvts  = [];
1852             var enterEvts = [];
1853
1854             // Check to see if the object(s) we were hovering over is no longer
1855             // being hovered over so we can fire the onDragOut event
1856             for (var i in this.dragOvers) {
1857
1858                 var ddo = this.dragOvers[i];
1859
1860                 if (! this.isTypeOfDD(ddo)) {
1861                     continue;
1862                 }
1863
1864                 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865                     outEvts.push( ddo );
1866                 }
1867
1868                 oldOvers[i] = true;
1869                 delete this.dragOvers[i];
1870             }
1871
1872             for (var sGroup in dc.groups) {
1873
1874                 if ("string" != typeof sGroup) {
1875                     continue;
1876                 }
1877
1878                 for (i in this.ids[sGroup]) {
1879                     var oDD = this.ids[sGroup][i];
1880                     if (! this.isTypeOfDD(oDD)) {
1881                         continue;
1882                     }
1883
1884                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885                         if (this.isOverTarget(pt, oDD, this.mode)) {
1886                             // look for drop interactions
1887                             if (isDrop) {
1888                                 dropEvts.push( oDD );
1889                             // look for drag enter and drag over interactions
1890                             } else {
1891
1892                                 // initial drag over: dragEnter fires
1893                                 if (!oldOvers[oDD.id]) {
1894                                     enterEvts.push( oDD );
1895                                 // subsequent drag overs: dragOver fires
1896                                 } else {
1897                                     overEvts.push( oDD );
1898                                 }
1899
1900                                 this.dragOvers[oDD.id] = oDD;
1901                             }
1902                         }
1903                     }
1904                 }
1905             }
1906
1907             if (this.mode) {
1908                 if (outEvts.length) {
1909                     dc.b4DragOut(e, outEvts);
1910                     dc.onDragOut(e, outEvts);
1911                 }
1912
1913                 if (enterEvts.length) {
1914                     dc.onDragEnter(e, enterEvts);
1915                 }
1916
1917                 if (overEvts.length) {
1918                     dc.b4DragOver(e, overEvts);
1919                     dc.onDragOver(e, overEvts);
1920                 }
1921
1922                 if (dropEvts.length) {
1923                     dc.b4DragDrop(e, dropEvts);
1924                     dc.onDragDrop(e, dropEvts);
1925                 }
1926
1927             } else {
1928                 // fire dragout events
1929                 var len = 0;
1930                 for (i=0, len=outEvts.length; i<len; ++i) {
1931                     dc.b4DragOut(e, outEvts[i].id);
1932                     dc.onDragOut(e, outEvts[i].id);
1933                 }
1934
1935                 // fire enter events
1936                 for (i=0,len=enterEvts.length; i<len; ++i) {
1937                     // dc.b4DragEnter(e, oDD.id);
1938                     dc.onDragEnter(e, enterEvts[i].id);
1939                 }
1940
1941                 // fire over events
1942                 for (i=0,len=overEvts.length; i<len; ++i) {
1943                     dc.b4DragOver(e, overEvts[i].id);
1944                     dc.onDragOver(e, overEvts[i].id);
1945                 }
1946
1947                 // fire drop events
1948                 for (i=0, len=dropEvts.length; i<len; ++i) {
1949                     dc.b4DragDrop(e, dropEvts[i].id);
1950                     dc.onDragDrop(e, dropEvts[i].id);
1951                 }
1952
1953             }
1954
1955             // notify about a drop that did not find a target
1956             if (isDrop && !dropEvts.length) {
1957                 dc.onInvalidDrop(e);
1958             }
1959
1960         },
1961
1962         /**
1963          * Helper function for getting the best match from the list of drag
1964          * and drop objects returned by the drag and drop events when we are
1965          * in INTERSECT mode.  It returns either the first object that the
1966          * cursor is over, or the object that has the greatest overlap with
1967          * the dragged element.
1968          * @method getBestMatch
1969          * @param  {DragDrop[]} dds The array of drag and drop objects
1970          * targeted
1971          * @return {DragDrop}       The best single match
1972          * @static
1973          */
1974         getBestMatch: function(dds) {
1975             var winner = null;
1976             // Return null if the input is not what we expect
1977             //if (!dds || !dds.length || dds.length == 0) {
1978                // winner = null;
1979             // If there is only one item, it wins
1980             //} else if (dds.length == 1) {
1981
1982             var len = dds.length;
1983
1984             if (len == 1) {
1985                 winner = dds[0];
1986             } else {
1987                 // Loop through the targeted items
1988                 for (var i=0; i<len; ++i) {
1989                     var dd = dds[i];
1990                     // If the cursor is over the object, it wins.  If the
1991                     // cursor is over multiple matches, the first one we come
1992                     // to wins.
1993                     if (dd.cursorIsOver) {
1994                         winner = dd;
1995                         break;
1996                     // Otherwise the object with the most overlap wins
1997                     } else {
1998                         if (!winner ||
1999                             winner.overlap.getArea() < dd.overlap.getArea()) {
2000                             winner = dd;
2001                         }
2002                     }
2003                 }
2004             }
2005
2006             return winner;
2007         },
2008
2009         /**
2010          * Refreshes the cache of the top-left and bottom-right points of the
2011          * drag and drop objects in the specified group(s).  This is in the
2012          * format that is stored in the drag and drop instance, so typical
2013          * usage is:
2014          * <code>
2015          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2016          * </code>
2017          * Alternatively:
2018          * <code>
2019          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2020          * </code>
2021          * @TODO this really should be an indexed array.  Alternatively this
2022          * method could accept both.
2023          * @method refreshCache
2024          * @param {Object} groups an associative array of groups to refresh
2025          * @static
2026          */
2027         refreshCache: function(groups) {
2028             for (var sGroup in groups) {
2029                 if ("string" != typeof sGroup) {
2030                     continue;
2031                 }
2032                 for (var i in this.ids[sGroup]) {
2033                     var oDD = this.ids[sGroup][i];
2034
2035                     if (this.isTypeOfDD(oDD)) {
2036                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037                         var loc = this.getLocation(oDD);
2038                         if (loc) {
2039                             this.locationCache[oDD.id] = loc;
2040                         } else {
2041                             delete this.locationCache[oDD.id];
2042                             // this will unregister the drag and drop object if
2043                             // the element is not in a usable state
2044                             // oDD.unreg();
2045                         }
2046                     }
2047                 }
2048             }
2049         },
2050
2051         /**
2052          * This checks to make sure an element exists and is in the DOM.  The
2053          * main purpose is to handle cases where innerHTML is used to remove
2054          * drag and drop objects from the DOM.  IE provides an 'unspecified
2055          * error' when trying to access the offsetParent of such an element
2056          * @method verifyEl
2057          * @param {HTMLElement} el the element to check
2058          * @return {boolean} true if the element looks usable
2059          * @static
2060          */
2061         verifyEl: function(el) {
2062             if (el) {
2063                 var parent;
2064                 if(Roo.isIE){
2065                     try{
2066                         parent = el.offsetParent;
2067                     }catch(e){}
2068                 }else{
2069                     parent = el.offsetParent;
2070                 }
2071                 if (parent) {
2072                     return true;
2073                 }
2074             }
2075
2076             return false;
2077         },
2078
2079         /**
2080          * Returns a Region object containing the drag and drop element's position
2081          * and size, including the padding configured for it
2082          * @method getLocation
2083          * @param {DragDrop} oDD the drag and drop object to get the
2084          *                       location for
2085          * @return {Roo.lib.Region} a Region object representing the total area
2086          *                             the element occupies, including any padding
2087          *                             the instance is configured for.
2088          * @static
2089          */
2090         getLocation: function(oDD) {
2091             if (! this.isTypeOfDD(oDD)) {
2092                 return null;
2093             }
2094
2095             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2096
2097             try {
2098                 pos= Roo.lib.Dom.getXY(el);
2099             } catch (e) { }
2100
2101             if (!pos) {
2102                 return null;
2103             }
2104
2105             x1 = pos[0];
2106             x2 = x1 + el.offsetWidth;
2107             y1 = pos[1];
2108             y2 = y1 + el.offsetHeight;
2109
2110             t = y1 - oDD.padding[0];
2111             r = x2 + oDD.padding[1];
2112             b = y2 + oDD.padding[2];
2113             l = x1 - oDD.padding[3];
2114
2115             return new Roo.lib.Region( t, r, b, l );
2116         },
2117
2118         /**
2119          * Checks the cursor location to see if it over the target
2120          * @method isOverTarget
2121          * @param {Roo.lib.Point} pt The point to evaluate
2122          * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123          * @return {boolean} true if the mouse is over the target
2124          * @private
2125          * @static
2126          */
2127         isOverTarget: function(pt, oTarget, intersect) {
2128             // use cache if available
2129             var loc = this.locationCache[oTarget.id];
2130             if (!loc || !this.useCache) {
2131                 loc = this.getLocation(oTarget);
2132                 this.locationCache[oTarget.id] = loc;
2133
2134             }
2135
2136             if (!loc) {
2137                 return false;
2138             }
2139
2140             oTarget.cursorIsOver = loc.contains( pt );
2141
2142             // DragDrop is using this as a sanity check for the initial mousedown
2143             // in this case we are done.  In POINT mode, if the drag obj has no
2144             // contraints, we are also done. Otherwise we need to evaluate the
2145             // location of the target as related to the actual location of the
2146             // dragged element.
2147             var dc = this.dragCurrent;
2148             if (!dc || !dc.getTargetCoord ||
2149                     (!intersect && !dc.constrainX && !dc.constrainY)) {
2150                 return oTarget.cursorIsOver;
2151             }
2152
2153             oTarget.overlap = null;
2154
2155             // Get the current location of the drag element, this is the
2156             // location of the mouse event less the delta that represents
2157             // where the original mousedown happened on the element.  We
2158             // need to consider constraints and ticks as well.
2159             var pos = dc.getTargetCoord(pt.x, pt.y);
2160
2161             var el = dc.getDragEl();
2162             var curRegion = new Roo.lib.Region( pos.y,
2163                                                    pos.x + el.offsetWidth,
2164                                                    pos.y + el.offsetHeight,
2165                                                    pos.x );
2166
2167             var overlap = curRegion.intersect(loc);
2168
2169             if (overlap) {
2170                 oTarget.overlap = overlap;
2171                 return (intersect) ? true : oTarget.cursorIsOver;
2172             } else {
2173                 return false;
2174             }
2175         },
2176
2177         /**
2178          * unload event handler
2179          * @method _onUnload
2180          * @private
2181          * @static
2182          */
2183         _onUnload: function(e, me) {
2184             Roo.dd.DragDropMgr.unregAll();
2185         },
2186
2187         /**
2188          * Cleans up the drag and drop events and objects.
2189          * @method unregAll
2190          * @private
2191          * @static
2192          */
2193         unregAll: function() {
2194
2195             if (this.dragCurrent) {
2196                 this.stopDrag();
2197                 this.dragCurrent = null;
2198             }
2199
2200             this._execOnAll("unreg", []);
2201
2202             for (i in this.elementCache) {
2203                 delete this.elementCache[i];
2204             }
2205
2206             this.elementCache = {};
2207             this.ids = {};
2208         },
2209
2210         /**
2211          * A cache of DOM elements
2212          * @property elementCache
2213          * @private
2214          * @static
2215          */
2216         elementCache: {},
2217
2218         /**
2219          * Get the wrapper for the DOM element specified
2220          * @method getElWrapper
2221          * @param {String} id the id of the element to get
2222          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2223          * @private
2224          * @deprecated This wrapper isn't that useful
2225          * @static
2226          */
2227         getElWrapper: function(id) {
2228             var oWrapper = this.elementCache[id];
2229             if (!oWrapper || !oWrapper.el) {
2230                 oWrapper = this.elementCache[id] =
2231                     new this.ElementWrapper(Roo.getDom(id));
2232             }
2233             return oWrapper;
2234         },
2235
2236         /**
2237          * Returns the actual DOM element
2238          * @method getElement
2239          * @param {String} id the id of the elment to get
2240          * @return {Object} The element
2241          * @deprecated use Roo.getDom instead
2242          * @static
2243          */
2244         getElement: function(id) {
2245             return Roo.getDom(id);
2246         },
2247
2248         /**
2249          * Returns the style property for the DOM element (i.e.,
2250          * document.getElById(id).style)
2251          * @method getCss
2252          * @param {String} id the id of the elment to get
2253          * @return {Object} The style property of the element
2254          * @deprecated use Roo.getDom instead
2255          * @static
2256          */
2257         getCss: function(id) {
2258             var el = Roo.getDom(id);
2259             return (el) ? el.style : null;
2260         },
2261
2262         /**
2263          * Inner class for cached elements
2264          * @class DragDropMgr.ElementWrapper
2265          * @for DragDropMgr
2266          * @private
2267          * @deprecated
2268          */
2269         ElementWrapper: function(el) {
2270                 /**
2271                  * The element
2272                  * @property el
2273                  */
2274                 this.el = el || null;
2275                 /**
2276                  * The element id
2277                  * @property id
2278                  */
2279                 this.id = this.el && el.id;
2280                 /**
2281                  * A reference to the style property
2282                  * @property css
2283                  */
2284                 this.css = this.el && el.style;
2285             },
2286
2287         /**
2288          * Returns the X position of an html element
2289          * @method getPosX
2290          * @param el the element for which to get the position
2291          * @return {int} the X coordinate
2292          * @for DragDropMgr
2293          * @deprecated use Roo.lib.Dom.getX instead
2294          * @static
2295          */
2296         getPosX: function(el) {
2297             return Roo.lib.Dom.getX(el);
2298         },
2299
2300         /**
2301          * Returns the Y position of an html element
2302          * @method getPosY
2303          * @param el the element for which to get the position
2304          * @return {int} the Y coordinate
2305          * @deprecated use Roo.lib.Dom.getY instead
2306          * @static
2307          */
2308         getPosY: function(el) {
2309             return Roo.lib.Dom.getY(el);
2310         },
2311
2312         /**
2313          * Swap two nodes.  In IE, we use the native method, for others we
2314          * emulate the IE behavior
2315          * @method swapNode
2316          * @param n1 the first node to swap
2317          * @param n2 the other node to swap
2318          * @static
2319          */
2320         swapNode: function(n1, n2) {
2321             if (n1.swapNode) {
2322                 n1.swapNode(n2);
2323             } else {
2324                 var p = n2.parentNode;
2325                 var s = n2.nextSibling;
2326
2327                 if (s == n1) {
2328                     p.insertBefore(n1, n2);
2329                 } else if (n2 == n1.nextSibling) {
2330                     p.insertBefore(n2, n1);
2331                 } else {
2332                     n1.parentNode.replaceChild(n2, n1);
2333                     p.insertBefore(n1, s);
2334                 }
2335             }
2336         },
2337
2338         /**
2339          * Returns the current scroll position
2340          * @method getScroll
2341          * @private
2342          * @static
2343          */
2344         getScroll: function () {
2345             var t, l, dde=document.documentElement, db=document.body;
2346             if (dde && (dde.scrollTop || dde.scrollLeft)) {
2347                 t = dde.scrollTop;
2348                 l = dde.scrollLeft;
2349             } else if (db) {
2350                 t = db.scrollTop;
2351                 l = db.scrollLeft;
2352             } else {
2353
2354             }
2355             return { top: t, left: l };
2356         },
2357
2358         /**
2359          * Returns the specified element style property
2360          * @method getStyle
2361          * @param {HTMLElement} el          the element
2362          * @param {string}      styleProp   the style property
2363          * @return {string} The value of the style property
2364          * @deprecated use Roo.lib.Dom.getStyle
2365          * @static
2366          */
2367         getStyle: function(el, styleProp) {
2368             return Roo.fly(el).getStyle(styleProp);
2369         },
2370
2371         /**
2372          * Gets the scrollTop
2373          * @method getScrollTop
2374          * @return {int} the document's scrollTop
2375          * @static
2376          */
2377         getScrollTop: function () { return this.getScroll().top; },
2378
2379         /**
2380          * Gets the scrollLeft
2381          * @method getScrollLeft
2382          * @return {int} the document's scrollTop
2383          * @static
2384          */
2385         getScrollLeft: function () { return this.getScroll().left; },
2386
2387         /**
2388          * Sets the x/y position of an element to the location of the
2389          * target element.
2390          * @method moveToEl
2391          * @param {HTMLElement} moveEl      The element to move
2392          * @param {HTMLElement} targetEl    The position reference element
2393          * @static
2394          */
2395         moveToEl: function (moveEl, targetEl) {
2396             var aCoord = Roo.lib.Dom.getXY(targetEl);
2397             Roo.lib.Dom.setXY(moveEl, aCoord);
2398         },
2399
2400         /**
2401          * Numeric array sort function
2402          * @method numericSort
2403          * @static
2404          */
2405         numericSort: function(a, b) { return (a - b); },
2406
2407         /**
2408          * Internal counter
2409          * @property _timeoutCount
2410          * @private
2411          * @static
2412          */
2413         _timeoutCount: 0,
2414
2415         /**
2416          * Trying to make the load order less important.  Without this we get
2417          * an error if this file is loaded before the Event Utility.
2418          * @method _addListeners
2419          * @private
2420          * @static
2421          */
2422         _addListeners: function() {
2423             var DDM = Roo.dd.DDM;
2424             if ( Roo.lib.Event && document ) {
2425                 DDM._onLoad();
2426             } else {
2427                 if (DDM._timeoutCount > 2000) {
2428                 } else {
2429                     setTimeout(DDM._addListeners, 10);
2430                     if (document && document.body) {
2431                         DDM._timeoutCount += 1;
2432                     }
2433                 }
2434             }
2435         },
2436
2437         /**
2438          * Recursively searches the immediate parent and all child nodes for
2439          * the handle element in order to determine wheter or not it was
2440          * clicked.
2441          * @method handleWasClicked
2442          * @param node the html element to inspect
2443          * @static
2444          */
2445         handleWasClicked: function(node, id) {
2446             if (this.isHandle(id, node.id)) {
2447                 return true;
2448             } else {
2449                 // check to see if this is a text node child of the one we want
2450                 var p = node.parentNode;
2451
2452                 while (p) {
2453                     if (this.isHandle(id, p.id)) {
2454                         return true;
2455                     } else {
2456                         p = p.parentNode;
2457                     }
2458                 }
2459             }
2460
2461             return false;
2462         }
2463
2464     };
2465
2466 }();
2467
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2471
2472 }/*
2473  * Based on:
2474  * Ext JS Library 1.1.1
2475  * Copyright(c) 2006-2007, Ext JS, LLC.
2476  *
2477  * Originally Released Under LGPL - original licence link has changed is not relivant.
2478  *
2479  * Fork - LGPL
2480  * <script type="text/javascript">
2481  */
2482
2483 /**
2484  * @class Roo.dd.DD
2485  * A DragDrop implementation where the linked element follows the
2486  * mouse cursor during a drag.
2487  * @extends Roo.dd.DragDrop
2488  * @constructor
2489  * @param {String} id the id of the linked element
2490  * @param {String} sGroup the group of related DragDrop items
2491  * @param {object} config an object containing configurable attributes
2492  *                Valid properties for DD:
2493  *                    scroll
2494  */
2495 Roo.dd.DD = function(id, sGroup, config) {
2496     if (id) {
2497         this.init(id, sGroup, config);
2498     }
2499 };
2500
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2502
2503     /**
2504      * When set to true, the utility automatically tries to scroll the browser
2505      * window wehn a drag and drop element is dragged near the viewport boundary.
2506      * Defaults to true.
2507      * @property scroll
2508      * @type boolean
2509      */
2510     scroll: true,
2511
2512     /**
2513      * Sets the pointer offset to the distance between the linked element's top
2514      * left corner and the location the element was clicked
2515      * @method autoOffset
2516      * @param {int} iPageX the X coordinate of the click
2517      * @param {int} iPageY the Y coordinate of the click
2518      */
2519     autoOffset: function(iPageX, iPageY) {
2520         var x = iPageX - this.startPageX;
2521         var y = iPageY - this.startPageY;
2522         this.setDelta(x, y);
2523     },
2524
2525     /**
2526      * Sets the pointer offset.  You can call this directly to force the
2527      * offset to be in a particular location (e.g., pass in 0,0 to set it
2528      * to the center of the object)
2529      * @method setDelta
2530      * @param {int} iDeltaX the distance from the left
2531      * @param {int} iDeltaY the distance from the top
2532      */
2533     setDelta: function(iDeltaX, iDeltaY) {
2534         this.deltaX = iDeltaX;
2535         this.deltaY = iDeltaY;
2536     },
2537
2538     /**
2539      * Sets the drag element to the location of the mousedown or click event,
2540      * maintaining the cursor location relative to the location on the element
2541      * that was clicked.  Override this if you want to place the element in a
2542      * location other than where the cursor is.
2543      * @method setDragElPos
2544      * @param {int} iPageX the X coordinate of the mousedown or drag event
2545      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2546      */
2547     setDragElPos: function(iPageX, iPageY) {
2548         // the first time we do this, we are going to check to make sure
2549         // the element has css positioning
2550
2551         var el = this.getDragEl();
2552         this.alignElWithMouse(el, iPageX, iPageY);
2553     },
2554
2555     /**
2556      * Sets the element to the location of the mousedown or click event,
2557      * maintaining the cursor location relative to the location on the element
2558      * that was clicked.  Override this if you want to place the element in a
2559      * location other than where the cursor is.
2560      * @method alignElWithMouse
2561      * @param {HTMLElement} el the element to move
2562      * @param {int} iPageX the X coordinate of the mousedown or drag event
2563      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2564      */
2565     alignElWithMouse: function(el, iPageX, iPageY) {
2566         var oCoord = this.getTargetCoord(iPageX, iPageY);
2567         var fly = el.dom ? el : Roo.fly(el);
2568         if (!this.deltaSetXY) {
2569             var aCoord = [oCoord.x, oCoord.y];
2570             fly.setXY(aCoord);
2571             var newLeft = fly.getLeft(true);
2572             var newTop  = fly.getTop(true);
2573             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2574         } else {
2575             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2576         }
2577
2578         this.cachePosition(oCoord.x, oCoord.y);
2579         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2580         return oCoord;
2581     },
2582
2583     /**
2584      * Saves the most recent position so that we can reset the constraints and
2585      * tick marks on-demand.  We need to know this so that we can calculate the
2586      * number of pixels the element is offset from its original position.
2587      * @method cachePosition
2588      * @param iPageX the current x position (optional, this just makes it so we
2589      * don't have to look it up again)
2590      * @param iPageY the current y position (optional, this just makes it so we
2591      * don't have to look it up again)
2592      */
2593     cachePosition: function(iPageX, iPageY) {
2594         if (iPageX) {
2595             this.lastPageX = iPageX;
2596             this.lastPageY = iPageY;
2597         } else {
2598             var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599             this.lastPageX = aCoord[0];
2600             this.lastPageY = aCoord[1];
2601         }
2602     },
2603
2604     /**
2605      * Auto-scroll the window if the dragged object has been moved beyond the
2606      * visible window boundary.
2607      * @method autoScroll
2608      * @param {int} x the drag element's x position
2609      * @param {int} y the drag element's y position
2610      * @param {int} h the height of the drag element
2611      * @param {int} w the width of the drag element
2612      * @private
2613      */
2614     autoScroll: function(x, y, h, w) {
2615
2616         if (this.scroll) {
2617             // The client height
2618             var clientH = Roo.lib.Dom.getViewWidth();
2619
2620             // The client width
2621             var clientW = Roo.lib.Dom.getViewHeight();
2622
2623             // The amt scrolled down
2624             var st = this.DDM.getScrollTop();
2625
2626             // The amt scrolled right
2627             var sl = this.DDM.getScrollLeft();
2628
2629             // Location of the bottom of the element
2630             var bot = h + y;
2631
2632             // Location of the right of the element
2633             var right = w + x;
2634
2635             // The distance from the cursor to the bottom of the visible area,
2636             // adjusted so that we don't scroll if the cursor is beyond the
2637             // element drag constraints
2638             var toBot = (clientH + st - y - this.deltaY);
2639
2640             // The distance from the cursor to the right of the visible area
2641             var toRight = (clientW + sl - x - this.deltaX);
2642
2643
2644             // How close to the edge the cursor must be before we scroll
2645             // var thresh = (document.all) ? 100 : 40;
2646             var thresh = 40;
2647
2648             // How many pixels to scroll per autoscroll op.  This helps to reduce
2649             // clunky scrolling. IE is more sensitive about this ... it needs this
2650             // value to be higher.
2651             var scrAmt = (document.all) ? 80 : 30;
2652
2653             // Scroll down if we are near the bottom of the visible page and the
2654             // obj extends below the crease
2655             if ( bot > clientH && toBot < thresh ) {
2656                 window.scrollTo(sl, st + scrAmt);
2657             }
2658
2659             // Scroll up if the window is scrolled down and the top of the object
2660             // goes above the top border
2661             if ( y < st && st > 0 && y - st < thresh ) {
2662                 window.scrollTo(sl, st - scrAmt);
2663             }
2664
2665             // Scroll right if the obj is beyond the right border and the cursor is
2666             // near the border.
2667             if ( right > clientW && toRight < thresh ) {
2668                 window.scrollTo(sl + scrAmt, st);
2669             }
2670
2671             // Scroll left if the window has been scrolled to the right and the obj
2672             // extends past the left border
2673             if ( x < sl && sl > 0 && x - sl < thresh ) {
2674                 window.scrollTo(sl - scrAmt, st);
2675             }
2676         }
2677     },
2678
2679     /**
2680      * Finds the location the element should be placed if we want to move
2681      * it to where the mouse location less the click offset would place us.
2682      * @method getTargetCoord
2683      * @param {int} iPageX the X coordinate of the click
2684      * @param {int} iPageY the Y coordinate of the click
2685      * @return an object that contains the coordinates (Object.x and Object.y)
2686      * @private
2687      */
2688     getTargetCoord: function(iPageX, iPageY) {
2689
2690
2691         var x = iPageX - this.deltaX;
2692         var y = iPageY - this.deltaY;
2693
2694         if (this.constrainX) {
2695             if (x < this.minX) { x = this.minX; }
2696             if (x > this.maxX) { x = this.maxX; }
2697         }
2698
2699         if (this.constrainY) {
2700             if (y < this.minY) { y = this.minY; }
2701             if (y > this.maxY) { y = this.maxY; }
2702         }
2703
2704         x = this.getTick(x, this.xTicks);
2705         y = this.getTick(y, this.yTicks);
2706
2707
2708         return {x:x, y:y};
2709     },
2710
2711     /*
2712      * Sets up config options specific to this class. Overrides
2713      * Roo.dd.DragDrop, but all versions of this method through the
2714      * inheritance chain are called
2715      */
2716     applyConfig: function() {
2717         Roo.dd.DD.superclass.applyConfig.call(this);
2718         this.scroll = (this.config.scroll !== false);
2719     },
2720
2721     /*
2722      * Event that fires prior to the onMouseDown event.  Overrides
2723      * Roo.dd.DragDrop.
2724      */
2725     b4MouseDown: function(e) {
2726         // this.resetConstraints();
2727         this.autoOffset(e.getPageX(),
2728                             e.getPageY());
2729     },
2730
2731     /*
2732      * Event that fires prior to the onDrag event.  Overrides
2733      * Roo.dd.DragDrop.
2734      */
2735     b4Drag: function(e) {
2736         this.setDragElPos(e.getPageX(),
2737                             e.getPageY());
2738     },
2739
2740     toString: function() {
2741         return ("DD " + this.id);
2742     }
2743
2744     //////////////////////////////////////////////////////////////////////////
2745     // Debugging ygDragDrop events that can be overridden
2746     //////////////////////////////////////////////////////////////////////////
2747     /*
2748     startDrag: function(x, y) {
2749     },
2750
2751     onDrag: function(e) {
2752     },
2753
2754     onDragEnter: function(e, id) {
2755     },
2756
2757     onDragOver: function(e, id) {
2758     },
2759
2760     onDragOut: function(e, id) {
2761     },
2762
2763     onDragDrop: function(e, id) {
2764     },
2765
2766     endDrag: function(e) {
2767     }
2768
2769     */
2770
2771 });/*
2772  * Based on:
2773  * Ext JS Library 1.1.1
2774  * Copyright(c) 2006-2007, Ext JS, LLC.
2775  *
2776  * Originally Released Under LGPL - original licence link has changed is not relivant.
2777  *
2778  * Fork - LGPL
2779  * <script type="text/javascript">
2780  */
2781
2782 /**
2783  * @class Roo.dd.DDProxy
2784  * A DragDrop implementation that inserts an empty, bordered div into
2785  * the document that follows the cursor during drag operations.  At the time of
2786  * the click, the frame div is resized to the dimensions of the linked html
2787  * element, and moved to the exact location of the linked element.
2788  *
2789  * References to the "frame" element refer to the single proxy element that
2790  * was created to be dragged in place of all DDProxy elements on the
2791  * page.
2792  *
2793  * @extends Roo.dd.DD
2794  * @constructor
2795  * @param {String} id the id of the linked html element
2796  * @param {String} sGroup the group of related DragDrop objects
2797  * @param {object} config an object containing configurable attributes
2798  *                Valid properties for DDProxy in addition to those in DragDrop:
2799  *                   resizeFrame, centerFrame, dragElId
2800  */
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2802     if (id) {
2803         this.init(id, sGroup, config);
2804         this.initFrame();
2805     }
2806 };
2807
2808 /**
2809  * The default drag frame div id
2810  * @property Roo.dd.DDProxy.dragElId
2811  * @type String
2812  * @static
2813  */
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2815
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2817
2818     /**
2819      * By default we resize the drag frame to be the same size as the element
2820      * we want to drag (this is to get the frame effect).  We can turn it off
2821      * if we want a different behavior.
2822      * @property resizeFrame
2823      * @type boolean
2824      */
2825     resizeFrame: true,
2826
2827     /**
2828      * By default the frame is positioned exactly where the drag element is, so
2829      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
2830      * you do not have constraints on the obj is to have the drag frame centered
2831      * around the cursor.  Set centerFrame to true for this effect.
2832      * @property centerFrame
2833      * @type boolean
2834      */
2835     centerFrame: false,
2836
2837     /**
2838      * Creates the proxy element if it does not yet exist
2839      * @method createFrame
2840      */
2841     createFrame: function() {
2842         var self = this;
2843         var body = document.body;
2844
2845         if (!body || !body.firstChild) {
2846             setTimeout( function() { self.createFrame(); }, 50 );
2847             return;
2848         }
2849
2850         var div = this.getDragEl();
2851
2852         if (!div) {
2853             div    = document.createElement("div");
2854             div.id = this.dragElId;
2855             var s  = div.style;
2856
2857             s.position   = "absolute";
2858             s.visibility = "hidden";
2859             s.cursor     = "move";
2860             s.border     = "2px solid #aaa";
2861             s.zIndex     = 999;
2862
2863             // appendChild can blow up IE if invoked prior to the window load event
2864             // while rendering a table.  It is possible there are other scenarios
2865             // that would cause this to happen as well.
2866             body.insertBefore(div, body.firstChild);
2867         }
2868     },
2869
2870     /**
2871      * Initialization for the drag frame element.  Must be called in the
2872      * constructor of all subclasses
2873      * @method initFrame
2874      */
2875     initFrame: function() {
2876         this.createFrame();
2877     },
2878
2879     applyConfig: function() {
2880         Roo.dd.DDProxy.superclass.applyConfig.call(this);
2881
2882         this.resizeFrame = (this.config.resizeFrame !== false);
2883         this.centerFrame = (this.config.centerFrame);
2884         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2885     },
2886
2887     /**
2888      * Resizes the drag frame to the dimensions of the clicked object, positions
2889      * it over the object, and finally displays it
2890      * @method showFrame
2891      * @param {int} iPageX X click position
2892      * @param {int} iPageY Y click position
2893      * @private
2894      */
2895     showFrame: function(iPageX, iPageY) {
2896         var el = this.getEl();
2897         var dragEl = this.getDragEl();
2898         var s = dragEl.style;
2899
2900         this._resizeProxy();
2901
2902         if (this.centerFrame) {
2903             this.setDelta( Math.round(parseInt(s.width,  10)/2),
2904                            Math.round(parseInt(s.height, 10)/2) );
2905         }
2906
2907         this.setDragElPos(iPageX, iPageY);
2908
2909         Roo.fly(dragEl).show();
2910     },
2911
2912     /**
2913      * The proxy is automatically resized to the dimensions of the linked
2914      * element when a drag is initiated, unless resizeFrame is set to false
2915      * @method _resizeProxy
2916      * @private
2917      */
2918     _resizeProxy: function() {
2919         if (this.resizeFrame) {
2920             var el = this.getEl();
2921             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2922         }
2923     },
2924
2925     // overrides Roo.dd.DragDrop
2926     b4MouseDown: function(e) {
2927         var x = e.getPageX();
2928         var y = e.getPageY();
2929         this.autoOffset(x, y);
2930         this.setDragElPos(x, y);
2931     },
2932
2933     // overrides Roo.dd.DragDrop
2934     b4StartDrag: function(x, y) {
2935         // show the drag frame
2936         this.showFrame(x, y);
2937     },
2938
2939     // overrides Roo.dd.DragDrop
2940     b4EndDrag: function(e) {
2941         Roo.fly(this.getDragEl()).hide();
2942     },
2943
2944     // overrides Roo.dd.DragDrop
2945     // By default we try to move the element to the last location of the frame.
2946     // This is so that the default behavior mirrors that of Roo.dd.DD.
2947     endDrag: function(e) {
2948
2949         var lel = this.getEl();
2950         var del = this.getDragEl();
2951
2952         // Show the drag frame briefly so we can get its position
2953         del.style.visibility = "";
2954
2955         this.beforeMove();
2956         // Hide the linked element before the move to get around a Safari
2957         // rendering bug.
2958         lel.style.visibility = "hidden";
2959         Roo.dd.DDM.moveToEl(lel, del);
2960         del.style.visibility = "hidden";
2961         lel.style.visibility = "";
2962
2963         this.afterDrag();
2964     },
2965
2966     beforeMove : function(){
2967
2968     },
2969
2970     afterDrag : function(){
2971
2972     },
2973
2974     toString: function() {
2975         return ("DDProxy " + this.id);
2976     }
2977
2978 });
2979 /*
2980  * Based on:
2981  * Ext JS Library 1.1.1
2982  * Copyright(c) 2006-2007, Ext JS, LLC.
2983  *
2984  * Originally Released Under LGPL - original licence link has changed is not relivant.
2985  *
2986  * Fork - LGPL
2987  * <script type="text/javascript">
2988  */
2989
2990  /**
2991  * @class Roo.dd.DDTarget
2992  * A DragDrop implementation that does not move, but can be a drop
2993  * target.  You would get the same result by simply omitting implementation
2994  * for the event callbacks, but this way we reduce the processing cost of the
2995  * event listener and the callbacks.
2996  * @extends Roo.dd.DragDrop
2997  * @constructor
2998  * @param {String} id the id of the element that is a drop target
2999  * @param {String} sGroup the group of related DragDrop objects
3000  * @param {object} config an object containing configurable attributes
3001  *                 Valid properties for DDTarget in addition to those in
3002  *                 DragDrop:
3003  *                    none
3004  */
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3006     if (id) {
3007         this.initTarget(id, sGroup, config);
3008     }
3009 };
3010
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013     toString: function() {
3014         return ("DDTarget " + this.id);
3015     }
3016 });
3017 /*
3018  * Based on:
3019  * Ext JS Library 1.1.1
3020  * Copyright(c) 2006-2007, Ext JS, LLC.
3021  *
3022  * Originally Released Under LGPL - original licence link has changed is not relivant.
3023  *
3024  * Fork - LGPL
3025  * <script type="text/javascript">
3026  */
3027  
3028
3029 /**
3030  * @class Roo.dd.ScrollManager
3031  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3033  * @singleton
3034  */
3035 Roo.dd.ScrollManager = function(){
3036     var ddm = Roo.dd.DragDropMgr;
3037     var els = {};
3038     var dragEl = null;
3039     var proc = {};
3040     
3041     var onStop = function(e){
3042         dragEl = null;
3043         clearProc();
3044     };
3045     
3046     var triggerRefresh = function(){
3047         if(ddm.dragCurrent){
3048              ddm.refreshCache(ddm.dragCurrent.groups);
3049         }
3050     };
3051     
3052     var doScroll = function(){
3053         if(ddm.dragCurrent){
3054             var dds = Roo.dd.ScrollManager;
3055             if(!dds.animate){
3056                 if(proc.el.scroll(proc.dir, dds.increment)){
3057                     triggerRefresh();
3058                 }
3059             }else{
3060                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3061             }
3062         }
3063     };
3064     
3065     var clearProc = function(){
3066         if(proc.id){
3067             clearInterval(proc.id);
3068         }
3069         proc.id = 0;
3070         proc.el = null;
3071         proc.dir = "";
3072     };
3073     
3074     var startProc = function(el, dir){
3075         clearProc();
3076         proc.el = el;
3077         proc.dir = dir;
3078         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3079     };
3080     
3081     var onFire = function(e, isDrop){
3082         if(isDrop || !ddm.dragCurrent){ return; }
3083         var dds = Roo.dd.ScrollManager;
3084         if(!dragEl || dragEl != ddm.dragCurrent){
3085             dragEl = ddm.dragCurrent;
3086             // refresh regions on drag start
3087             dds.refreshCache();
3088         }
3089         
3090         var xy = Roo.lib.Event.getXY(e);
3091         var pt = new Roo.lib.Point(xy[0], xy[1]);
3092         for(var id in els){
3093             var el = els[id], r = el._region;
3094             if(r && r.contains(pt) && el.isScrollable()){
3095                 if(r.bottom - pt.y <= dds.thresh){
3096                     if(proc.el != el){
3097                         startProc(el, "down");
3098                     }
3099                     return;
3100                 }else if(r.right - pt.x <= dds.thresh){
3101                     if(proc.el != el){
3102                         startProc(el, "left");
3103                     }
3104                     return;
3105                 }else if(pt.y - r.top <= dds.thresh){
3106                     if(proc.el != el){
3107                         startProc(el, "up");
3108                     }
3109                     return;
3110                 }else if(pt.x - r.left <= dds.thresh){
3111                     if(proc.el != el){
3112                         startProc(el, "right");
3113                     }
3114                     return;
3115                 }
3116             }
3117         }
3118         clearProc();
3119     };
3120     
3121     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3123     
3124     return {
3125         /**
3126          * Registers new overflow element(s) to auto scroll
3127          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3128          */
3129         register : function(el){
3130             if(el instanceof Array){
3131                 for(var i = 0, len = el.length; i < len; i++) {
3132                         this.register(el[i]);
3133                 }
3134             }else{
3135                 el = Roo.get(el);
3136                 els[el.id] = el;
3137             }
3138         },
3139         
3140         /**
3141          * Unregisters overflow element(s) so they are no longer scrolled
3142          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3143          */
3144         unregister : function(el){
3145             if(el instanceof Array){
3146                 for(var i = 0, len = el.length; i < len; i++) {
3147                         this.unregister(el[i]);
3148                 }
3149             }else{
3150                 el = Roo.get(el);
3151                 delete els[el.id];
3152             }
3153         },
3154         
3155         /**
3156          * The number of pixels from the edge of a container the pointer needs to be to 
3157          * trigger scrolling (defaults to 25)
3158          * @type Number
3159          */
3160         thresh : 25,
3161         
3162         /**
3163          * The number of pixels to scroll in each scroll increment (defaults to 50)
3164          * @type Number
3165          */
3166         increment : 100,
3167         
3168         /**
3169          * The frequency of scrolls in milliseconds (defaults to 500)
3170          * @type Number
3171          */
3172         frequency : 500,
3173         
3174         /**
3175          * True to animate the scroll (defaults to true)
3176          * @type Boolean
3177          */
3178         animate: true,
3179         
3180         /**
3181          * The animation duration in seconds - 
3182          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3183          * @type Number
3184          */
3185         animDuration: .4,
3186         
3187         /**
3188          * Manually trigger a cache refresh.
3189          */
3190         refreshCache : function(){
3191             for(var id in els){
3192                 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193                     els[id]._region = els[id].getRegion();
3194                 }
3195             }
3196         }
3197     };
3198 }();/*
3199  * Based on:
3200  * Ext JS Library 1.1.1
3201  * Copyright(c) 2006-2007, Ext JS, LLC.
3202  *
3203  * Originally Released Under LGPL - original licence link has changed is not relivant.
3204  *
3205  * Fork - LGPL
3206  * <script type="text/javascript">
3207  */
3208  
3209
3210 /**
3211  * @class Roo.dd.Registry
3212  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
3213  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3214  * @singleton
3215  */
3216 Roo.dd.Registry = function(){
3217     var elements = {}; 
3218     var handles = {}; 
3219     var autoIdSeed = 0;
3220
3221     var getId = function(el, autogen){
3222         if(typeof el == "string"){
3223             return el;
3224         }
3225         var id = el.id;
3226         if(!id && autogen !== false){
3227             id = "roodd-" + (++autoIdSeed);
3228             el.id = id;
3229         }
3230         return id;
3231     };
3232     
3233     return {
3234     /**
3235      * Register a drag drop element
3236      * @param {String|HTMLElement} element The id or DOM node to register
3237      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
3239      * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240      * populated in the data object (if applicable):
3241      * <pre>
3242 Value      Description<br />
3243 ---------  ------------------------------------------<br />
3244 handles    Array of DOM nodes that trigger dragging<br />
3245            for the element being registered<br />
3246 isHandle   True if the element passed in triggers<br />
3247            dragging itself, else false
3248 </pre>
3249      */
3250         register : function(el, data){
3251             data = data || {};
3252             if(typeof el == "string"){
3253                 el = document.getElementById(el);
3254             }
3255             data.ddel = el;
3256             elements[getId(el)] = data;
3257             if(data.isHandle !== false){
3258                 handles[data.ddel.id] = data;
3259             }
3260             if(data.handles){
3261                 var hs = data.handles;
3262                 for(var i = 0, len = hs.length; i < len; i++){
3263                         handles[getId(hs[i])] = data;
3264                 }
3265             }
3266         },
3267
3268     /**
3269      * Unregister a drag drop element
3270      * @param {String|HTMLElement}  element The id or DOM node to unregister
3271      */
3272         unregister : function(el){
3273             var id = getId(el, false);
3274             var data = elements[id];
3275             if(data){
3276                 delete elements[id];
3277                 if(data.handles){
3278                     var hs = data.handles;
3279                     for(var i = 0, len = hs.length; i < len; i++){
3280                         delete handles[getId(hs[i], false)];
3281                     }
3282                 }
3283             }
3284         },
3285
3286     /**
3287      * Returns the handle registered for a DOM Node by id
3288      * @param {String|HTMLElement} id The DOM node or id to look up
3289      * @return {Object} handle The custom handle data
3290      */
3291         getHandle : function(id){
3292             if(typeof id != "string"){ // must be element?
3293                 id = id.id;
3294             }
3295             return handles[id];
3296         },
3297
3298     /**
3299      * Returns the handle that is registered for the DOM node that is the target of the event
3300      * @param {Event} e The event
3301      * @return {Object} handle The custom handle data
3302      */
3303         getHandleFromEvent : function(e){
3304             var t = Roo.lib.Event.getTarget(e);
3305             return t ? handles[t.id] : null;
3306         },
3307
3308     /**
3309      * Returns a custom data object that is registered for a DOM node by id
3310      * @param {String|HTMLElement} id The DOM node or id to look up
3311      * @return {Object} data The custom data
3312      */
3313         getTarget : function(id){
3314             if(typeof id != "string"){ // must be element?
3315                 id = id.id;
3316             }
3317             return elements[id];
3318         },
3319
3320     /**
3321      * Returns a custom data object that is registered for the DOM node that is the target of the event
3322      * @param {Event} e The event
3323      * @return {Object} data The custom data
3324      */
3325         getTargetFromEvent : function(e){
3326             var t = Roo.lib.Event.getTarget(e);
3327             return t ? elements[t.id] || handles[t.id] : null;
3328         }
3329     };
3330 }();/*
3331  * Based on:
3332  * Ext JS Library 1.1.1
3333  * Copyright(c) 2006-2007, Ext JS, LLC.
3334  *
3335  * Originally Released Under LGPL - original licence link has changed is not relivant.
3336  *
3337  * Fork - LGPL
3338  * <script type="text/javascript">
3339  */
3340  
3341
3342 /**
3343  * @class Roo.dd.StatusProxy
3344  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
3345  * default drag proxy used by all Roo.dd components.
3346  * @constructor
3347  * @param {Object} config
3348  */
3349 Roo.dd.StatusProxy = function(config){
3350     Roo.apply(this, config);
3351     this.id = this.id || Roo.id();
3352     this.el = new Roo.Layer({
3353         dh: {
3354             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355                 {tag: "div", cls: "x-dd-drop-icon"},
3356                 {tag: "div", cls: "x-dd-drag-ghost"}
3357             ]
3358         }, 
3359         shadow: !config || config.shadow !== false
3360     });
3361     this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362     this.dropStatus = this.dropNotAllowed;
3363 };
3364
3365 Roo.dd.StatusProxy.prototype = {
3366     /**
3367      * @cfg {String} dropAllowed
3368      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3369      */
3370     dropAllowed : "x-dd-drop-ok",
3371     /**
3372      * @cfg {String} dropNotAllowed
3373      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3374      */
3375     dropNotAllowed : "x-dd-drop-nodrop",
3376
3377     /**
3378      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379      * over the current target element.
3380      * @param {String} cssClass The css class for the new drop status indicator image
3381      */
3382     setStatus : function(cssClass){
3383         cssClass = cssClass || this.dropNotAllowed;
3384         if(this.dropStatus != cssClass){
3385             this.el.replaceClass(this.dropStatus, cssClass);
3386             this.dropStatus = cssClass;
3387         }
3388     },
3389
3390     /**
3391      * Resets the status indicator to the default dropNotAllowed value
3392      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3393      */
3394     reset : function(clearGhost){
3395         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396         this.dropStatus = this.dropNotAllowed;
3397         if(clearGhost){
3398             this.ghost.update("");
3399         }
3400     },
3401
3402     /**
3403      * Updates the contents of the ghost element
3404      * @param {String} html The html that will replace the current innerHTML of the ghost element
3405      */
3406     update : function(html){
3407         if(typeof html == "string"){
3408             this.ghost.update(html);
3409         }else{
3410             this.ghost.update("");
3411             html.style.margin = "0";
3412             this.ghost.dom.appendChild(html);
3413         }
3414         // ensure float = none set?? cant remember why though.
3415         var el = this.ghost.dom.firstChild;
3416                 if(el){
3417                         Roo.fly(el).setStyle('float', 'none');
3418                 }
3419     },
3420     
3421     /**
3422      * Returns the underlying proxy {@link Roo.Layer}
3423      * @return {Roo.Layer} el
3424     */
3425     getEl : function(){
3426         return this.el;
3427     },
3428
3429     /**
3430      * Returns the ghost element
3431      * @return {Roo.Element} el
3432      */
3433     getGhost : function(){
3434         return this.ghost;
3435     },
3436
3437     /**
3438      * Hides the proxy
3439      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3440      */
3441     hide : function(clear){
3442         this.el.hide();
3443         if(clear){
3444             this.reset(true);
3445         }
3446     },
3447
3448     /**
3449      * Stops the repair animation if it's currently running
3450      */
3451     stop : function(){
3452         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3453             this.anim.stop();
3454         }
3455     },
3456
3457     /**
3458      * Displays this proxy
3459      */
3460     show : function(){
3461         this.el.show();
3462     },
3463
3464     /**
3465      * Force the Layer to sync its shadow and shim positions to the element
3466      */
3467     sync : function(){
3468         this.el.sync();
3469     },
3470
3471     /**
3472      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
3473      * invalid drop operation by the item being dragged.
3474      * @param {Array} xy The XY position of the element ([x, y])
3475      * @param {Function} callback The function to call after the repair is complete
3476      * @param {Object} scope The scope in which to execute the callback
3477      */
3478     repair : function(xy, callback, scope){
3479         this.callback = callback;
3480         this.scope = scope;
3481         if(xy && this.animRepair !== false){
3482             this.el.addClass("x-dd-drag-repair");
3483             this.el.hideUnders(true);
3484             this.anim = this.el.shift({
3485                 duration: this.repairDuration || .5,
3486                 easing: 'easeOut',
3487                 xy: xy,
3488                 stopFx: true,
3489                 callback: this.afterRepair,
3490                 scope: this
3491             });
3492         }else{
3493             this.afterRepair();
3494         }
3495     },
3496
3497     // private
3498     afterRepair : function(){
3499         this.hide(true);
3500         if(typeof this.callback == "function"){
3501             this.callback.call(this.scope || this);
3502         }
3503         this.callback = null;
3504         this.scope = null;
3505     }
3506 };/*
3507  * Based on:
3508  * Ext JS Library 1.1.1
3509  * Copyright(c) 2006-2007, Ext JS, LLC.
3510  *
3511  * Originally Released Under LGPL - original licence link has changed is not relivant.
3512  *
3513  * Fork - LGPL
3514  * <script type="text/javascript">
3515  */
3516
3517 /**
3518  * @class Roo.dd.DragSource
3519  * @extends Roo.dd.DDProxy
3520  * A simple class that provides the basic implementation needed to make any element draggable.
3521  * @constructor
3522  * @param {String/HTMLElement/Element} el The container element
3523  * @param {Object} config
3524  */
3525 Roo.dd.DragSource = function(el, config){
3526     this.el = Roo.get(el);
3527     this.dragData = {};
3528     
3529     Roo.apply(this, config);
3530     
3531     if(!this.proxy){
3532         this.proxy = new Roo.dd.StatusProxy();
3533     }
3534
3535     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3537     
3538     this.dragging = false;
3539 };
3540
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3542     /**
3543      * @cfg {String} dropAllowed
3544      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3545      */
3546     dropAllowed : "x-dd-drop-ok",
3547     /**
3548      * @cfg {String} dropNotAllowed
3549      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3550      */
3551     dropNotAllowed : "x-dd-drop-nodrop",
3552
3553     /**
3554      * Returns the data object associated with this drag source
3555      * @return {Object} data An object containing arbitrary data
3556      */
3557     getDragData : function(e){
3558         return this.dragData;
3559     },
3560
3561     // private
3562     onDragEnter : function(e, id){
3563         var target = Roo.dd.DragDropMgr.getDDById(id);
3564         this.cachedTarget = target;
3565         if(this.beforeDragEnter(target, e, id) !== false){
3566             if(target.isNotifyTarget){
3567                 var status = target.notifyEnter(this, e, this.dragData);
3568                 this.proxy.setStatus(status);
3569             }else{
3570                 this.proxy.setStatus(this.dropAllowed);
3571             }
3572             
3573             if(this.afterDragEnter){
3574                 /**
3575                  * An empty function by default, but provided so that you can perform a custom action
3576                  * when the dragged item enters the drop target by providing an implementation.
3577                  * @param {Roo.dd.DragDrop} target The drop target
3578                  * @param {Event} e The event object
3579                  * @param {String} id The id of the dragged element
3580                  * @method afterDragEnter
3581                  */
3582                 this.afterDragEnter(target, e, id);
3583             }
3584         }
3585     },
3586
3587     /**
3588      * An empty function by default, but provided so that you can perform a custom action
3589      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590      * @param {Roo.dd.DragDrop} target The drop target
3591      * @param {Event} e The event object
3592      * @param {String} id The id of the dragged element
3593      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3594      */
3595     beforeDragEnter : function(target, e, id){
3596         return true;
3597     },
3598
3599     // private
3600     alignElWithMouse: function() {
3601         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3602         this.proxy.sync();
3603     },
3604
3605     // private
3606     onDragOver : function(e, id){
3607         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608         if(this.beforeDragOver(target, e, id) !== false){
3609             if(target.isNotifyTarget){
3610                 var status = target.notifyOver(this, e, this.dragData);
3611                 this.proxy.setStatus(status);
3612             }
3613
3614             if(this.afterDragOver){
3615                 /**
3616                  * An empty function by default, but provided so that you can perform a custom action
3617                  * while the dragged item is over the drop target by providing an implementation.
3618                  * @param {Roo.dd.DragDrop} target The drop target
3619                  * @param {Event} e The event object
3620                  * @param {String} id The id of the dragged element
3621                  * @method afterDragOver
3622                  */
3623                 this.afterDragOver(target, e, id);
3624             }
3625         }
3626     },
3627
3628     /**
3629      * An empty function by default, but provided so that you can perform a custom action
3630      * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631      * @param {Roo.dd.DragDrop} target The drop target
3632      * @param {Event} e The event object
3633      * @param {String} id The id of the dragged element
3634      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3635      */
3636     beforeDragOver : function(target, e, id){
3637         return true;
3638     },
3639
3640     // private
3641     onDragOut : function(e, id){
3642         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643         if(this.beforeDragOut(target, e, id) !== false){
3644             if(target.isNotifyTarget){
3645                 target.notifyOut(this, e, this.dragData);
3646             }
3647             this.proxy.reset();
3648             if(this.afterDragOut){
3649                 /**
3650                  * An empty function by default, but provided so that you can perform a custom action
3651                  * after the dragged item is dragged out of the target without dropping.
3652                  * @param {Roo.dd.DragDrop} target The drop target
3653                  * @param {Event} e The event object
3654                  * @param {String} id The id of the dragged element
3655                  * @method afterDragOut
3656                  */
3657                 this.afterDragOut(target, e, id);
3658             }
3659         }
3660         this.cachedTarget = null;
3661     },
3662
3663     /**
3664      * An empty function by default, but provided so that you can perform a custom action before the dragged
3665      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666      * @param {Roo.dd.DragDrop} target The drop target
3667      * @param {Event} e The event object
3668      * @param {String} id The id of the dragged element
3669      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3670      */
3671     beforeDragOut : function(target, e, id){
3672         return true;
3673     },
3674     
3675     // private
3676     onDragDrop : function(e, id){
3677         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678         if(this.beforeDragDrop(target, e, id) !== false){
3679             if(target.isNotifyTarget){
3680                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681                     this.onValidDrop(target, e, id);
3682                 }else{
3683                     this.onInvalidDrop(target, e, id);
3684                 }
3685             }else{
3686                 this.onValidDrop(target, e, id);
3687             }
3688             
3689             if(this.afterDragDrop){
3690                 /**
3691                  * An empty function by default, but provided so that you can perform a custom action
3692                  * after a valid drag drop has occurred by providing an implementation.
3693                  * @param {Roo.dd.DragDrop} target The drop target
3694                  * @param {Event} e The event object
3695                  * @param {String} id The id of the dropped element
3696                  * @method afterDragDrop
3697                  */
3698                 this.afterDragDrop(target, e, id);
3699             }
3700         }
3701         delete this.cachedTarget;
3702     },
3703
3704     /**
3705      * An empty function by default, but provided so that you can perform a custom action before the dragged
3706      * item is dropped onto the target and optionally cancel the onDragDrop.
3707      * @param {Roo.dd.DragDrop} target The drop target
3708      * @param {Event} e The event object
3709      * @param {String} id The id of the dragged element
3710      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3711      */
3712     beforeDragDrop : function(target, e, id){
3713         return true;
3714     },
3715
3716     // private
3717     onValidDrop : function(target, e, id){
3718         this.hideProxy();
3719         if(this.afterValidDrop){
3720             /**
3721              * An empty function by default, but provided so that you can perform a custom action
3722              * after a valid drop has occurred by providing an implementation.
3723              * @param {Object} target The target DD 
3724              * @param {Event} e The event object
3725              * @param {String} id The id of the dropped element
3726              * @method afterInvalidDrop
3727              */
3728             this.afterValidDrop(target, e, id);
3729         }
3730     },
3731
3732     // private
3733     getRepairXY : function(e, data){
3734         return this.el.getXY();  
3735     },
3736
3737     // private
3738     onInvalidDrop : function(target, e, id){
3739         this.beforeInvalidDrop(target, e, id);
3740         if(this.cachedTarget){
3741             if(this.cachedTarget.isNotifyTarget){
3742                 this.cachedTarget.notifyOut(this, e, this.dragData);
3743             }
3744             this.cacheTarget = null;
3745         }
3746         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3747
3748         if(this.afterInvalidDrop){
3749             /**
3750              * An empty function by default, but provided so that you can perform a custom action
3751              * after an invalid drop has occurred by providing an implementation.
3752              * @param {Event} e The event object
3753              * @param {String} id The id of the dropped element
3754              * @method afterInvalidDrop
3755              */
3756             this.afterInvalidDrop(e, id);
3757         }
3758     },
3759
3760     // private
3761     afterRepair : function(){
3762         if(Roo.enableFx){
3763             this.el.highlight(this.hlColor || "c3daf9");
3764         }
3765         this.dragging = false;
3766     },
3767
3768     /**
3769      * An empty function by default, but provided so that you can perform a custom action after an invalid
3770      * drop has occurred.
3771      * @param {Roo.dd.DragDrop} target The drop target
3772      * @param {Event} e The event object
3773      * @param {String} id The id of the dragged element
3774      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3775      */
3776     beforeInvalidDrop : function(target, e, id){
3777         return true;
3778     },
3779
3780     // private
3781     handleMouseDown : function(e){
3782         if(this.dragging) {
3783             return;
3784         }
3785         var data = this.getDragData(e);
3786         if(data && this.onBeforeDrag(data, e) !== false){
3787             this.dragData = data;
3788             this.proxy.stop();
3789             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3790         } 
3791     },
3792
3793     /**
3794      * An empty function by default, but provided so that you can perform a custom action before the initial
3795      * drag event begins and optionally cancel it.
3796      * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797      * @param {Event} e The event object
3798      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3799      */
3800     onBeforeDrag : function(data, e){
3801         return true;
3802     },
3803
3804     /**
3805      * An empty function by default, but provided so that you can perform a custom action once the initial
3806      * drag event has begun.  The drag cannot be canceled from this function.
3807      * @param {Number} x The x position of the click on the dragged object
3808      * @param {Number} y The y position of the click on the dragged object
3809      */
3810     onStartDrag : Roo.emptyFn,
3811
3812     // private - YUI override
3813     startDrag : function(x, y){
3814         this.proxy.reset();
3815         this.dragging = true;
3816         this.proxy.update("");
3817         this.onInitDrag(x, y);
3818         this.proxy.show();
3819     },
3820
3821     // private
3822     onInitDrag : function(x, y){
3823         var clone = this.el.dom.cloneNode(true);
3824         clone.id = Roo.id(); // prevent duplicate ids
3825         this.proxy.update(clone);
3826         this.onStartDrag(x, y);
3827         return true;
3828     },
3829
3830     /**
3831      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3833      */
3834     getProxy : function(){
3835         return this.proxy;  
3836     },
3837
3838     /**
3839      * Hides the drag source's {@link Roo.dd.StatusProxy}
3840      */
3841     hideProxy : function(){
3842         this.proxy.hide();  
3843         this.proxy.reset(true);
3844         this.dragging = false;
3845     },
3846
3847     // private
3848     triggerCacheRefresh : function(){
3849         Roo.dd.DDM.refreshCache(this.groups);
3850     },
3851
3852     // private - override to prevent hiding
3853     b4EndDrag: function(e) {
3854     },
3855
3856     // private - override to prevent moving
3857     endDrag : function(e){
3858         this.onEndDrag(this.dragData, e);
3859     },
3860
3861     // private
3862     onEndDrag : function(data, e){
3863     },
3864     
3865     // private - pin to cursor
3866     autoOffset : function(x, y) {
3867         this.setDelta(-12, -20);
3868     }    
3869 });/*
3870  * Based on:
3871  * Ext JS Library 1.1.1
3872  * Copyright(c) 2006-2007, Ext JS, LLC.
3873  *
3874  * Originally Released Under LGPL - original licence link has changed is not relivant.
3875  *
3876  * Fork - LGPL
3877  * <script type="text/javascript">
3878  */
3879
3880
3881 /**
3882  * @class Roo.dd.DropTarget
3883  * @extends Roo.dd.DDTarget
3884  * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
3886  * @constructor
3887  * @param {String/HTMLElement/Element} el The container element
3888  * @param {Object} config
3889  */
3890 Roo.dd.DropTarget = function(el, config){
3891     this.el = Roo.get(el);
3892     
3893     Roo.apply(this, config);
3894     
3895     if(this.containerScroll){
3896         Roo.dd.ScrollManager.register(this.el);
3897     }
3898     this.addEvents( {
3899          /**
3900          * @scope Roo.dd.DropTarget
3901          */
3902          
3903          /**
3904          * @event enter
3905          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3906          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
3907          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
3908          * 
3909          * IMPORTANT : it should set this.overClass and this.dropAllowed
3910          * 
3911          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3912          * @param {Event} e The event
3913          * @param {Object} data An object containing arbitrary data supplied by the drag source
3914          */
3915         "enter" : true,
3916         
3917          /**
3918          * @event over
3919          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3920          * This method will be called on every mouse movement while the drag source is over the drop target.
3921          * This default implementation simply returns the dropAllowed config value.
3922          * 
3923          * IMPORTANT : it should set this.dropAllowed
3924          * 
3925          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3926          * @param {Event} e The event
3927          * @param {Object} data An object containing arbitrary data supplied by the drag source
3928          
3929          */
3930         "over" : true,
3931         /**
3932          * @event out
3933          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3934          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
3935          * overClass (if any) from the drop element.
3936          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3937          * @param {Event} e The event
3938          * @param {Object} data An object containing arbitrary data supplied by the drag source
3939          */
3940          "out" : true,
3941          
3942         /**
3943          * @event drop
3944          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3945          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
3946          * implementation that does something to process the drop event and returns true so that the drag source's
3947          * repair action does not run.
3948          * 
3949          * IMPORTANT : it should set this.success
3950          * 
3951          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3952          * @param {Event} e The event
3953          * @param {Object} data An object containing arbitrary data supplied by the drag source
3954         */
3955          "drop" : true
3956     });
3957             
3958      
3959     Roo.dd.DropTarget.superclass.constructor.call(  this, 
3960         this.el.dom, 
3961         this.ddGroup || this.group,
3962         {
3963             isTarget: true,
3964             listeners : config.listeners || {} 
3965            
3966         
3967         }
3968     );
3969
3970 };
3971
3972 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3973     /**
3974      * @cfg {String} overClass
3975      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3976      */
3977      /**
3978      * @cfg {String} ddGroup
3979      * The drag drop group to handle drop events for
3980      */
3981      
3982     /**
3983      * @cfg {String} dropAllowed
3984      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3985      */
3986     dropAllowed : "x-dd-drop-ok",
3987     /**
3988      * @cfg {String} dropNotAllowed
3989      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3990      */
3991     dropNotAllowed : "x-dd-drop-nodrop",
3992     /**
3993      * @cfg {boolean} success
3994      * set this after drop listener.. 
3995      */
3996     success : false,
3997     /**
3998      * @cfg {boolean} valid
3999      * if the drop point is valid for over/enter..
4000      */
4001     valid : false,
4002     // private
4003     isTarget : true,
4004
4005     // private
4006     isNotifyTarget : true,
4007     
4008     /**
4009      * @hide
4010      */
4011     notifyEnter : function(dd, e, data){
4012         this.valid = true;
4013         this.fireEvent('enter', this, dd, e, data);
4014         if(this.overClass){
4015             this.el.addClass(this.overClass);
4016         }
4017         return this.valid ? this.dropAllowed : this.dropNotAllowed;
4018     },
4019
4020     /**
4021      * @hide
4022      */
4023     notifyOver : function(dd, e, data){
4024         this.valid = true;
4025         this.fireEvent('over', this, dd, e, data);
4026         return this.valid ? this.dropAllowed : this.dropNotAllowed;
4027     },
4028
4029     /**
4030      * @hide
4031      */
4032     notifyOut : function(dd, e, data){
4033         this.fireEvent('out', this, dd, e, data);
4034         if(this.overClass){
4035             this.el.removeClass(this.overClass);
4036         }
4037     },
4038
4039     /**
4040      * @hide
4041      */
4042     notifyDrop : function(dd, e, data){
4043         this.success = false;
4044         this.fireEvent('drop', this, dd, e, data);
4045         return this.success;
4046     }
4047 });/*
4048  * Based on:
4049  * Ext JS Library 1.1.1
4050  * Copyright(c) 2006-2007, Ext JS, LLC.
4051  *
4052  * Originally Released Under LGPL - original licence link has changed is not relivant.
4053  *
4054  * Fork - LGPL
4055  * <script type="text/javascript">
4056  */
4057
4058
4059 /**
4060  * @class Roo.dd.DragZone
4061  * @extends Roo.dd.DragSource
4062  * This class provides a container DD instance that proxies for multiple child node sources.<br />
4063  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4064  * @constructor
4065  * @param {String/HTMLElement/Element} el The container element
4066  * @param {Object} config
4067  */
4068 Roo.dd.DragZone = function(el, config){
4069     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4070     if(this.containerScroll){
4071         Roo.dd.ScrollManager.register(this.el);
4072     }
4073 };
4074
4075 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4076     /**
4077      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4078      * for auto scrolling during drag operations.
4079      */
4080     /**
4081      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4082      * method after a failed drop (defaults to "c3daf9" - light blue)
4083      */
4084
4085     /**
4086      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4087      * for a valid target to drag based on the mouse down. Override this method
4088      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4089      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4090      * @param {EventObject} e The mouse down event
4091      * @return {Object} The dragData
4092      */
4093     getDragData : function(e){
4094         return Roo.dd.Registry.getHandleFromEvent(e);
4095     },
4096     
4097     /**
4098      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4099      * this.dragData.ddel
4100      * @param {Number} x The x position of the click on the dragged object
4101      * @param {Number} y The y position of the click on the dragged object
4102      * @return {Boolean} true to continue the drag, false to cancel
4103      */
4104     onInitDrag : function(x, y){
4105         this.proxy.update(this.dragData.ddel.cloneNode(true));
4106         this.onStartDrag(x, y);
4107         return true;
4108     },
4109     
4110     /**
4111      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
4112      */
4113     afterRepair : function(){
4114         if(Roo.enableFx){
4115             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4116         }
4117         this.dragging = false;
4118     },
4119
4120     /**
4121      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4122      * the XY of this.dragData.ddel
4123      * @param {EventObject} e The mouse up event
4124      * @return {Array} The xy location (e.g. [100, 200])
4125      */
4126     getRepairXY : function(e){
4127         return Roo.Element.fly(this.dragData.ddel).getXY();  
4128     }
4129 });/*
4130  * Based on:
4131  * Ext JS Library 1.1.1
4132  * Copyright(c) 2006-2007, Ext JS, LLC.
4133  *
4134  * Originally Released Under LGPL - original licence link has changed is not relivant.
4135  *
4136  * Fork - LGPL
4137  * <script type="text/javascript">
4138  */
4139 /**
4140  * @class Roo.dd.DropZone
4141  * @extends Roo.dd.DropTarget
4142  * This class provides a container DD instance that proxies for multiple child node targets.<br />
4143  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4144  * @constructor
4145  * @param {String/HTMLElement/Element} el The container element
4146  * @param {Object} config
4147  */
4148 Roo.dd.DropZone = function(el, config){
4149     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4150 };
4151
4152 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4153     /**
4154      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
4155      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4156      * provide your own custom lookup.
4157      * @param {Event} e The event
4158      * @return {Object} data The custom data
4159      */
4160     getTargetFromEvent : function(e){
4161         return Roo.dd.Registry.getTargetFromEvent(e);
4162     },
4163
4164     /**
4165      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4166      * that it has registered.  This method has no default implementation and should be overridden to provide
4167      * node-specific processing if necessary.
4168      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
4169      * {@link #getTargetFromEvent} for this node)
4170      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4171      * @param {Event} e The event
4172      * @param {Object} data An object containing arbitrary data supplied by the drag source
4173      */
4174     onNodeEnter : function(n, dd, e, data){
4175         
4176     },
4177
4178     /**
4179      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4180      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
4181      * overridden to provide the proper feedback.
4182      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4183      * {@link #getTargetFromEvent} for this node)
4184      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4185      * @param {Event} e The event
4186      * @param {Object} data An object containing arbitrary data supplied by the drag source
4187      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4188      * underlying {@link Roo.dd.StatusProxy} can be updated
4189      */
4190     onNodeOver : function(n, dd, e, data){
4191         return this.dropAllowed;
4192     },
4193
4194     /**
4195      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4196      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
4197      * node-specific processing if necessary.
4198      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4199      * {@link #getTargetFromEvent} for this node)
4200      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4201      * @param {Event} e The event
4202      * @param {Object} data An object containing arbitrary data supplied by the drag source
4203      */
4204     onNodeOut : function(n, dd, e, data){
4205         
4206     },
4207
4208     /**
4209      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4210      * the drop node.  The default implementation returns false, so it should be overridden to provide the
4211      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4212      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4213      * {@link #getTargetFromEvent} for this node)
4214      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4215      * @param {Event} e The event
4216      * @param {Object} data An object containing arbitrary data supplied by the drag source
4217      * @return {Boolean} True if the drop was valid, else false
4218      */
4219     onNodeDrop : function(n, dd, e, data){
4220         return false;
4221     },
4222
4223     /**
4224      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4225      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
4226      * it should be overridden to provide the proper feedback if necessary.
4227      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4228      * @param {Event} e The event
4229      * @param {Object} data An object containing arbitrary data supplied by the drag source
4230      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4231      * underlying {@link Roo.dd.StatusProxy} can be updated
4232      */
4233     onContainerOver : function(dd, e, data){
4234         return this.dropNotAllowed;
4235     },
4236
4237     /**
4238      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4239      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
4240      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4241      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
4242      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4243      * @param {Event} e The event
4244      * @param {Object} data An object containing arbitrary data supplied by the drag source
4245      * @return {Boolean} True if the drop was valid, else false
4246      */
4247     onContainerDrop : function(dd, e, data){
4248         return false;
4249     },
4250
4251     /**
4252      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4253      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
4254      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4255      * you should override this method and provide a custom implementation.
4256      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4257      * @param {Event} e The event
4258      * @param {Object} data An object containing arbitrary data supplied by the drag source
4259      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4260      * underlying {@link Roo.dd.StatusProxy} can be updated
4261      */
4262     notifyEnter : function(dd, e, data){
4263         return this.dropNotAllowed;
4264     },
4265
4266     /**
4267      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4268      * This method will be called on every mouse movement while the drag source is over the drop zone.
4269      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4270      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4271      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4272      * registered node, it will call {@link #onContainerOver}.
4273      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4274      * @param {Event} e The event
4275      * @param {Object} data An object containing arbitrary data supplied by the drag source
4276      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4277      * underlying {@link Roo.dd.StatusProxy} can be updated
4278      */
4279     notifyOver : function(dd, e, data){
4280         var n = this.getTargetFromEvent(e);
4281         if(!n){ // not over valid drop target
4282             if(this.lastOverNode){
4283                 this.onNodeOut(this.lastOverNode, dd, e, data);
4284                 this.lastOverNode = null;
4285             }
4286             return this.onContainerOver(dd, e, data);
4287         }
4288         if(this.lastOverNode != n){
4289             if(this.lastOverNode){
4290                 this.onNodeOut(this.lastOverNode, dd, e, data);
4291             }
4292             this.onNodeEnter(n, dd, e, data);
4293             this.lastOverNode = n;
4294         }
4295         return this.onNodeOver(n, dd, e, data);
4296     },
4297
4298     /**
4299      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4300      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
4301      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4302      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4303      * @param {Event} e The event
4304      * @param {Object} data An object containing arbitrary data supplied by the drag zone
4305      */
4306     notifyOut : function(dd, e, data){
4307         if(this.lastOverNode){
4308             this.onNodeOut(this.lastOverNode, dd, e, data);
4309             this.lastOverNode = null;
4310         }
4311     },
4312
4313     /**
4314      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4315      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
4316      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4317      * otherwise it will call {@link #onContainerDrop}.
4318      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4319      * @param {Event} e The event
4320      * @param {Object} data An object containing arbitrary data supplied by the drag source
4321      * @return {Boolean} True if the drop was valid, else false
4322      */
4323     notifyDrop : function(dd, e, data){
4324         if(this.lastOverNode){
4325             this.onNodeOut(this.lastOverNode, dd, e, data);
4326             this.lastOverNode = null;
4327         }
4328         var n = this.getTargetFromEvent(e);
4329         return n ?
4330             this.onNodeDrop(n, dd, e, data) :
4331             this.onContainerDrop(dd, e, data);
4332     },
4333
4334     // private
4335     triggerCacheRefresh : function(){
4336         Roo.dd.DDM.refreshCache(this.groups);
4337     }  
4338 });/*
4339  * Based on:
4340  * Ext JS Library 1.1.1
4341  * Copyright(c) 2006-2007, Ext JS, LLC.
4342  *
4343  * Originally Released Under LGPL - original licence link has changed is not relivant.
4344  *
4345  * Fork - LGPL
4346  * <script type="text/javascript">
4347  */
4348
4349
4350 /**
4351  * @class Roo.data.SortTypes
4352  * @singleton
4353  * Defines the default sorting (casting?) comparison functions used when sorting data.
4354  */
4355 Roo.data.SortTypes = {
4356     /**
4357      * Default sort that does nothing
4358      * @param {Mixed} s The value being converted
4359      * @return {Mixed} The comparison value
4360      */
4361     none : function(s){
4362         return s;
4363     },
4364     
4365     /**
4366      * The regular expression used to strip tags
4367      * @type {RegExp}
4368      * @property
4369      */
4370     stripTagsRE : /<\/?[^>]+>/gi,
4371     
4372     /**
4373      * Strips all HTML tags to sort on text only
4374      * @param {Mixed} s The value being converted
4375      * @return {String} The comparison value
4376      */
4377     asText : function(s){
4378         return String(s).replace(this.stripTagsRE, "");
4379     },
4380     
4381     /**
4382      * Strips all HTML tags to sort on text only - Case insensitive
4383      * @param {Mixed} s The value being converted
4384      * @return {String} The comparison value
4385      */
4386     asUCText : function(s){
4387         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4388     },
4389     
4390     /**
4391      * Case insensitive string
4392      * @param {Mixed} s The value being converted
4393      * @return {String} The comparison value
4394      */
4395     asUCString : function(s) {
4396         return String(s).toUpperCase();
4397     },
4398     
4399     /**
4400      * Date sorting
4401      * @param {Mixed} s The value being converted
4402      * @return {Number} The comparison value
4403      */
4404     asDate : function(s) {
4405         if(!s){
4406             return 0;
4407         }
4408         if(s instanceof Date){
4409             return s.getTime();
4410         }
4411         return Date.parse(String(s));
4412     },
4413     
4414     /**
4415      * Float sorting
4416      * @param {Mixed} s The value being converted
4417      * @return {Float} The comparison value
4418      */
4419     asFloat : function(s) {
4420         var val = parseFloat(String(s).replace(/,/g, ""));
4421         if(isNaN(val)) val = 0;
4422         return val;
4423     },
4424     
4425     /**
4426      * Integer sorting
4427      * @param {Mixed} s The value being converted
4428      * @return {Number} The comparison value
4429      */
4430     asInt : function(s) {
4431         var val = parseInt(String(s).replace(/,/g, ""));
4432         if(isNaN(val)) val = 0;
4433         return val;
4434     }
4435 };/*
4436  * Based on:
4437  * Ext JS Library 1.1.1
4438  * Copyright(c) 2006-2007, Ext JS, LLC.
4439  *
4440  * Originally Released Under LGPL - original licence link has changed is not relivant.
4441  *
4442  * Fork - LGPL
4443  * <script type="text/javascript">
4444  */
4445
4446 /**
4447 * @class Roo.data.Record
4448  * Instances of this class encapsulate both record <em>definition</em> information, and record
4449  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4450  * to access Records cached in an {@link Roo.data.Store} object.<br>
4451  * <p>
4452  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4453  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4454  * objects.<br>
4455  * <p>
4456  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4457  * @constructor
4458  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4459  * {@link #create}. The parameters are the same.
4460  * @param {Array} data An associative Array of data values keyed by the field name.
4461  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4462  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4463  * not specified an integer id is generated.
4464  */
4465 Roo.data.Record = function(data, id){
4466     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4467     this.data = data;
4468 };
4469
4470 /**
4471  * Generate a constructor for a specific record layout.
4472  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4473  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4474  * Each field definition object may contain the following properties: <ul>
4475  * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4476  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4477  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4478  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4479  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4480  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4481  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4482  * this may be omitted.</p></li>
4483  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4484  * <ul><li>auto (Default, implies no conversion)</li>
4485  * <li>string</li>
4486  * <li>int</li>
4487  * <li>float</li>
4488  * <li>boolean</li>
4489  * <li>date</li></ul></p></li>
4490  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4491  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4492  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4493  * by the Reader into an object that will be stored in the Record. It is passed the
4494  * following parameters:<ul>
4495  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4496  * </ul></p></li>
4497  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4498  * </ul>
4499  * <br>usage:<br><pre><code>
4500 var TopicRecord = Roo.data.Record.create(
4501     {name: 'title', mapping: 'topic_title'},
4502     {name: 'author', mapping: 'username'},
4503     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4504     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4505     {name: 'lastPoster', mapping: 'user2'},
4506     {name: 'excerpt', mapping: 'post_text'}
4507 );
4508
4509 var myNewRecord = new TopicRecord({
4510     title: 'Do my job please',
4511     author: 'noobie',
4512     totalPosts: 1,
4513     lastPost: new Date(),
4514     lastPoster: 'Animal',
4515     excerpt: 'No way dude!'
4516 });
4517 myStore.add(myNewRecord);
4518 </code></pre>
4519  * @method create
4520  * @static
4521  */
4522 Roo.data.Record.create = function(o){
4523     var f = function(){
4524         f.superclass.constructor.apply(this, arguments);
4525     };
4526     Roo.extend(f, Roo.data.Record);
4527     var p = f.prototype;
4528     p.fields = new Roo.util.MixedCollection(false, function(field){
4529         return field.name;
4530     });
4531     for(var i = 0, len = o.length; i < len; i++){
4532         p.fields.add(new Roo.data.Field(o[i]));
4533     }
4534     f.getField = function(name){
4535         return p.fields.get(name);  
4536     };
4537     return f;
4538 };
4539
4540 Roo.data.Record.AUTO_ID = 1000;
4541 Roo.data.Record.EDIT = 'edit';
4542 Roo.data.Record.REJECT = 'reject';
4543 Roo.data.Record.COMMIT = 'commit';
4544
4545 Roo.data.Record.prototype = {
4546     /**
4547      * Readonly flag - true if this record has been modified.
4548      * @type Boolean
4549      */
4550     dirty : false,
4551     editing : false,
4552     error: null,
4553     modified: null,
4554
4555     // private
4556     join : function(store){
4557         this.store = store;
4558     },
4559
4560     /**
4561      * Set the named field to the specified value.
4562      * @param {String} name The name of the field to set.
4563      * @param {Object} value The value to set the field to.
4564      */
4565     set : function(name, value){
4566         if(this.data[name] == value){
4567             return;
4568         }
4569         this.dirty = true;
4570         if(!this.modified){
4571             this.modified = {};
4572         }
4573         if(typeof this.modified[name] == 'undefined'){
4574             this.modified[name] = this.data[name];
4575         }
4576         this.data[name] = value;
4577         if(!this.editing){
4578             this.store.afterEdit(this);
4579         }       
4580     },
4581
4582     /**
4583      * Get the value of the named field.
4584      * @param {String} name The name of the field to get the value of.
4585      * @return {Object} The value of the field.
4586      */
4587     get : function(name){
4588         return this.data[name]; 
4589     },
4590
4591     // private
4592     beginEdit : function(){
4593         this.editing = true;
4594         this.modified = {}; 
4595     },
4596
4597     // private
4598     cancelEdit : function(){
4599         this.editing = false;
4600         delete this.modified;
4601     },
4602
4603     // private
4604     endEdit : function(){
4605         this.editing = false;
4606         if(this.dirty && this.store){
4607             this.store.afterEdit(this);
4608         }
4609     },
4610
4611     /**
4612      * Usually called by the {@link Roo.data.Store} which owns the Record.
4613      * Rejects all changes made to the Record since either creation, or the last commit operation.
4614      * Modified fields are reverted to their original values.
4615      * <p>
4616      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4617      * of reject operations.
4618      */
4619     reject : function(){
4620         var m = this.modified;
4621         for(var n in m){
4622             if(typeof m[n] != "function"){
4623                 this.data[n] = m[n];
4624             }
4625         }
4626         this.dirty = false;
4627         delete this.modified;
4628         this.editing = false;
4629         if(this.store){
4630             this.store.afterReject(this);
4631         }
4632     },
4633
4634     /**
4635      * Usually called by the {@link Roo.data.Store} which owns the Record.
4636      * Commits all changes made to the Record since either creation, or the last commit operation.
4637      * <p>
4638      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4639      * of commit operations.
4640      */
4641     commit : function(){
4642         this.dirty = false;
4643         delete this.modified;
4644         this.editing = false;
4645         if(this.store){
4646             this.store.afterCommit(this);
4647         }
4648     },
4649
4650     // private
4651     hasError : function(){
4652         return this.error != null;
4653     },
4654
4655     // private
4656     clearError : function(){
4657         this.error = null;
4658     },
4659
4660     /**
4661      * Creates a copy of this record.
4662      * @param {String} id (optional) A new record id if you don't want to use this record's id
4663      * @return {Record}
4664      */
4665     copy : function(newId) {
4666         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4667     }
4668 };/*
4669  * Based on:
4670  * Ext JS Library 1.1.1
4671  * Copyright(c) 2006-2007, Ext JS, LLC.
4672  *
4673  * Originally Released Under LGPL - original licence link has changed is not relivant.
4674  *
4675  * Fork - LGPL
4676  * <script type="text/javascript">
4677  */
4678
4679
4680
4681 /**
4682  * @class Roo.data.Store
4683  * @extends Roo.util.Observable
4684  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4685  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4686  * <p>
4687  * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4688  * has no knowledge of the format of the data returned by the Proxy.<br>
4689  * <p>
4690  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4691  * instances from the data object. These records are cached and made available through accessor functions.
4692  * @constructor
4693  * Creates a new Store.
4694  * @param {Object} config A config object containing the objects needed for the Store to access data,
4695  * and read the data into Records.
4696  */
4697 Roo.data.Store = function(config){
4698     this.data = new Roo.util.MixedCollection(false);
4699     this.data.getKey = function(o){
4700         return o.id;
4701     };
4702     this.baseParams = {};
4703     // private
4704     this.paramNames = {
4705         "start" : "start",
4706         "limit" : "limit",
4707         "sort" : "sort",
4708         "dir" : "dir"
4709     };
4710
4711     if(config && config.data){
4712         this.inlineData = config.data;
4713         delete config.data;
4714     }
4715
4716     Roo.apply(this, config);
4717     
4718     if(this.reader){ // reader passed
4719         this.reader = Roo.factory(this.reader, Roo.data);
4720         this.reader.xmodule = this.xmodule || false;
4721         if(!this.recordType){
4722             this.recordType = this.reader.recordType;
4723         }
4724         if(this.reader.onMetaChange){
4725             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4726         }
4727     }
4728
4729     if(this.recordType){
4730         this.fields = this.recordType.prototype.fields;
4731     }
4732     this.modified = [];
4733
4734     this.addEvents({
4735         /**
4736          * @event datachanged
4737          * Fires when the data cache has changed, and a widget which is using this Store
4738          * as a Record cache should refresh its view.
4739          * @param {Store} this
4740          */
4741         datachanged : true,
4742         /**
4743          * @event metachange
4744          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4745          * @param {Store} this
4746          * @param {Object} meta The JSON metadata
4747          */
4748         metachange : true,
4749         /**
4750          * @event add
4751          * Fires when Records have been added to the Store
4752          * @param {Store} this
4753          * @param {Roo.data.Record[]} records The array of Records added
4754          * @param {Number} index The index at which the record(s) were added
4755          */
4756         add : true,
4757         /**
4758          * @event remove
4759          * Fires when a Record has been removed from the Store
4760          * @param {Store} this
4761          * @param {Roo.data.Record} record The Record that was removed
4762          * @param {Number} index The index at which the record was removed
4763          */
4764         remove : true,
4765         /**
4766          * @event update
4767          * Fires when a Record has been updated
4768          * @param {Store} this
4769          * @param {Roo.data.Record} record The Record that was updated
4770          * @param {String} operation The update operation being performed.  Value may be one of:
4771          * <pre><code>
4772  Roo.data.Record.EDIT
4773  Roo.data.Record.REJECT
4774  Roo.data.Record.COMMIT
4775          * </code></pre>
4776          */
4777         update : true,
4778         /**
4779          * @event clear
4780          * Fires when the data cache has been cleared.
4781          * @param {Store} this
4782          */
4783         clear : true,
4784         /**
4785          * @event beforeload
4786          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4787          * the load action will be canceled.
4788          * @param {Store} this
4789          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4790          */
4791         beforeload : true,
4792         /**
4793          * @event load
4794          * Fires after a new set of Records has been loaded.
4795          * @param {Store} this
4796          * @param {Roo.data.Record[]} records The Records that were loaded
4797          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4798          */
4799         load : true,
4800         /**
4801          * @event loadexception
4802          * Fires if an exception occurs in the Proxy during loading.
4803          * Called with the signature of the Proxy's "loadexception" event.
4804          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4805          * 
4806          * @param {Proxy} 
4807          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4808          * @param {Object} load options 
4809          * @param {Object} jsonData from your request (normally this contains the Exception)
4810          */
4811         loadexception : true
4812     });
4813     
4814     if(this.proxy){
4815         this.proxy = Roo.factory(this.proxy, Roo.data);
4816         this.proxy.xmodule = this.xmodule || false;
4817         this.relayEvents(this.proxy,  ["loadexception"]);
4818     }
4819     this.sortToggle = {};
4820
4821     Roo.data.Store.superclass.constructor.call(this);
4822
4823     if(this.inlineData){
4824         this.loadData(this.inlineData);
4825         delete this.inlineData;
4826     }
4827 };
4828 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4829      /**
4830     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4831     * without a remote query - used by combo/forms at present.
4832     */
4833     
4834     /**
4835     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4836     */
4837     /**
4838     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4839     */
4840     /**
4841     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4842     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4843     */
4844     /**
4845     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4846     * on any HTTP request
4847     */
4848     /**
4849     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4850     */
4851     /**
4852     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4853     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4854     */
4855     remoteSort : false,
4856
4857     /**
4858     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4859      * loaded or when a record is removed. (defaults to false).
4860     */
4861     pruneModifiedRecords : false,
4862
4863     // private
4864     lastOptions : null,
4865
4866     /**
4867      * Add Records to the Store and fires the add event.
4868      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4869      */
4870     add : function(records){
4871         records = [].concat(records);
4872         for(var i = 0, len = records.length; i < len; i++){
4873             records[i].join(this);
4874         }
4875         var index = this.data.length;
4876         this.data.addAll(records);
4877         this.fireEvent("add", this, records, index);
4878     },
4879
4880     /**
4881      * Remove a Record from the Store and fires the remove event.
4882      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4883      */
4884     remove : function(record){
4885         var index = this.data.indexOf(record);
4886         this.data.removeAt(index);
4887         if(this.pruneModifiedRecords){
4888             this.modified.remove(record);
4889         }
4890         this.fireEvent("remove", this, record, index);
4891     },
4892
4893     /**
4894      * Remove all Records from the Store and fires the clear event.
4895      */
4896     removeAll : function(){
4897         this.data.clear();
4898         if(this.pruneModifiedRecords){
4899             this.modified = [];
4900         }
4901         this.fireEvent("clear", this);
4902     },
4903
4904     /**
4905      * Inserts Records to the Store at the given index and fires the add event.
4906      * @param {Number} index The start index at which to insert the passed Records.
4907      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4908      */
4909     insert : function(index, records){
4910         records = [].concat(records);
4911         for(var i = 0, len = records.length; i < len; i++){
4912             this.data.insert(index, records[i]);
4913             records[i].join(this);
4914         }
4915         this.fireEvent("add", this, records, index);
4916     },
4917
4918     /**
4919      * Get the index within the cache of the passed Record.
4920      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4921      * @return {Number} The index of the passed Record. Returns -1 if not found.
4922      */
4923     indexOf : function(record){
4924         return this.data.indexOf(record);
4925     },
4926
4927     /**
4928      * Get the index within the cache of the Record with the passed id.
4929      * @param {String} id The id of the Record to find.
4930      * @return {Number} The index of the Record. Returns -1 if not found.
4931      */
4932     indexOfId : function(id){
4933         return this.data.indexOfKey(id);
4934     },
4935
4936     /**
4937      * Get the Record with the specified id.
4938      * @param {String} id The id of the Record to find.
4939      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4940      */
4941     getById : function(id){
4942         return this.data.key(id);
4943     },
4944
4945     /**
4946      * Get the Record at the specified index.
4947      * @param {Number} index The index of the Record to find.
4948      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4949      */
4950     getAt : function(index){
4951         return this.data.itemAt(index);
4952     },
4953
4954     /**
4955      * Returns a range of Records between specified indices.
4956      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4957      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4958      * @return {Roo.data.Record[]} An array of Records
4959      */
4960     getRange : function(start, end){
4961         return this.data.getRange(start, end);
4962     },
4963
4964     // private
4965     storeOptions : function(o){
4966         o = Roo.apply({}, o);
4967         delete o.callback;
4968         delete o.scope;
4969         this.lastOptions = o;
4970     },
4971
4972     /**
4973      * Loads the Record cache from the configured Proxy using the configured Reader.
4974      * <p>
4975      * If using remote paging, then the first load call must specify the <em>start</em>
4976      * and <em>limit</em> properties in the options.params property to establish the initial
4977      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4978      * <p>
4979      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4980      * and this call will return before the new data has been loaded. Perform any post-processing
4981      * in a callback function, or in a "load" event handler.</strong>
4982      * <p>
4983      * @param {Object} options An object containing properties which control loading options:<ul>
4984      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4985      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4986      * passed the following arguments:<ul>
4987      * <li>r : Roo.data.Record[]</li>
4988      * <li>options: Options object from the load call</li>
4989      * <li>success: Boolean success indicator</li></ul></li>
4990      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4991      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4992      * </ul>
4993      */
4994     load : function(options){
4995         options = options || {};
4996         if(this.fireEvent("beforeload", this, options) !== false){
4997             this.storeOptions(options);
4998             var p = Roo.apply(options.params || {}, this.baseParams);
4999             // if meta was not loaded from remote source.. try requesting it.
5000             if (!this.reader.metaFromRemote) {
5001                 p._requestMeta = 1;
5002             }
5003             if(this.sortInfo && this.remoteSort){
5004                 var pn = this.paramNames;
5005                 p[pn["sort"]] = this.sortInfo.field;
5006                 p[pn["dir"]] = this.sortInfo.direction;
5007             }
5008             this.proxy.load(p, this.reader, this.loadRecords, this, options);
5009         }
5010     },
5011
5012     /**
5013      * Reloads the Record cache from the configured Proxy using the configured Reader and
5014      * the options from the last load operation performed.
5015      * @param {Object} options (optional) An object containing properties which may override the options
5016      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5017      * the most recently used options are reused).
5018      */
5019     reload : function(options){
5020         this.load(Roo.applyIf(options||{}, this.lastOptions));
5021     },
5022
5023     // private
5024     // Called as a callback by the Reader during a load operation.
5025     loadRecords : function(o, options, success){
5026         if(!o || success === false){
5027             if(success !== false){
5028                 this.fireEvent("load", this, [], options);
5029             }
5030             if(options.callback){
5031                 options.callback.call(options.scope || this, [], options, false);
5032             }
5033             return;
5034         }
5035         // if data returned failure - throw an exception.
5036         if (o.success === false) {
5037             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5038             return;
5039         }
5040         var r = o.records, t = o.totalRecords || r.length;
5041         if(!options || options.add !== true){
5042             if(this.pruneModifiedRecords){
5043                 this.modified = [];
5044             }
5045             for(var i = 0, len = r.length; i < len; i++){
5046                 r[i].join(this);
5047             }
5048             if(this.snapshot){
5049                 this.data = this.snapshot;
5050                 delete this.snapshot;
5051             }
5052             this.data.clear();
5053             this.data.addAll(r);
5054             this.totalLength = t;
5055             this.applySort();
5056             this.fireEvent("datachanged", this);
5057         }else{
5058             this.totalLength = Math.max(t, this.data.length+r.length);
5059             this.add(r);
5060         }
5061         this.fireEvent("load", this, r, options);
5062         if(options.callback){
5063             options.callback.call(options.scope || this, r, options, true);
5064         }
5065     },
5066
5067     /**
5068      * Loads data from a passed data block. A Reader which understands the format of the data
5069      * must have been configured in the constructor.
5070      * @param {Object} data The data block from which to read the Records.  The format of the data expected
5071      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5072      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5073      */
5074     loadData : function(o, append){
5075         var r = this.reader.readRecords(o);
5076         this.loadRecords(r, {add: append}, true);
5077     },
5078
5079     /**
5080      * Gets the number of cached records.
5081      * <p>
5082      * <em>If using paging, this may not be the total size of the dataset. If the data object
5083      * used by the Reader contains the dataset size, then the getTotalCount() function returns
5084      * the data set size</em>
5085      */
5086     getCount : function(){
5087         return this.data.length || 0;
5088     },
5089
5090     /**
5091      * Gets the total number of records in the dataset as returned by the server.
5092      * <p>
5093      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5094      * the dataset size</em>
5095      */
5096     getTotalCount : function(){
5097         return this.totalLength || 0;
5098     },
5099
5100     /**
5101      * Returns the sort state of the Store as an object with two properties:
5102      * <pre><code>
5103  field {String} The name of the field by which the Records are sorted
5104  direction {String} The sort order, "ASC" or "DESC"
5105      * </code></pre>
5106      */
5107     getSortState : function(){
5108         return this.sortInfo;
5109     },
5110
5111     // private
5112     applySort : function(){
5113         if(this.sortInfo && !this.remoteSort){
5114             var s = this.sortInfo, f = s.field;
5115             var st = this.fields.get(f).sortType;
5116             var fn = function(r1, r2){
5117                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5118                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5119             };
5120             this.data.sort(s.direction, fn);
5121             if(this.snapshot && this.snapshot != this.data){
5122                 this.snapshot.sort(s.direction, fn);
5123             }
5124         }
5125     },
5126
5127     /**
5128      * Sets the default sort column and order to be used by the next load operation.
5129      * @param {String} fieldName The name of the field to sort by.
5130      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5131      */
5132     setDefaultSort : function(field, dir){
5133         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5134     },
5135
5136     /**
5137      * Sort the Records.
5138      * If remote sorting is used, the sort is performed on the server, and the cache is
5139      * reloaded. If local sorting is used, the cache is sorted internally.
5140      * @param {String} fieldName The name of the field to sort by.
5141      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5142      */
5143     sort : function(fieldName, dir){
5144         var f = this.fields.get(fieldName);
5145         if(!dir){
5146             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5147                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5148             }else{
5149                 dir = f.sortDir;
5150             }
5151         }
5152         this.sortToggle[f.name] = dir;
5153         this.sortInfo = {field: f.name, direction: dir};
5154         if(!this.remoteSort){
5155             this.applySort();
5156             this.fireEvent("datachanged", this);
5157         }else{
5158             this.load(this.lastOptions);
5159         }
5160     },
5161
5162     /**
5163      * Calls the specified function for each of the Records in the cache.
5164      * @param {Function} fn The function to call. The Record is passed as the first parameter.
5165      * Returning <em>false</em> aborts and exits the iteration.
5166      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5167      */
5168     each : function(fn, scope){
5169         this.data.each(fn, scope);
5170     },
5171
5172     /**
5173      * Gets all records modified since the last commit.  Modified records are persisted across load operations
5174      * (e.g., during paging).
5175      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5176      */
5177     getModifiedRecords : function(){
5178         return this.modified;
5179     },
5180
5181     // private
5182     createFilterFn : function(property, value, anyMatch){
5183         if(!value.exec){ // not a regex
5184             value = String(value);
5185             if(value.length == 0){
5186                 return false;
5187             }
5188             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5189         }
5190         return function(r){
5191             return value.test(r.data[property]);
5192         };
5193     },
5194
5195     /**
5196      * Sums the value of <i>property</i> for each record between start and end and returns the result.
5197      * @param {String} property A field on your records
5198      * @param {Number} start The record index to start at (defaults to 0)
5199      * @param {Number} end The last record index to include (defaults to length - 1)
5200      * @return {Number} The sum
5201      */
5202     sum : function(property, start, end){
5203         var rs = this.data.items, v = 0;
5204         start = start || 0;
5205         end = (end || end === 0) ? end : rs.length-1;
5206
5207         for(var i = start; i <= end; i++){
5208             v += (rs[i].data[property] || 0);
5209         }
5210         return v;
5211     },
5212
5213     /**
5214      * Filter the records by a specified property.
5215      * @param {String} field A field on your records
5216      * @param {String/RegExp} value Either a string that the field
5217      * should start with or a RegExp to test against the field
5218      * @param {Boolean} anyMatch True to match any part not just the beginning
5219      */
5220     filter : function(property, value, anyMatch){
5221         var fn = this.createFilterFn(property, value, anyMatch);
5222         return fn ? this.filterBy(fn) : this.clearFilter();
5223     },
5224
5225     /**
5226      * Filter by a function. The specified function will be called with each
5227      * record in this data source. If the function returns true the record is included,
5228      * otherwise it is filtered.
5229      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5230      * @param {Object} scope (optional) The scope of the function (defaults to this)
5231      */
5232     filterBy : function(fn, scope){
5233         this.snapshot = this.snapshot || this.data;
5234         this.data = this.queryBy(fn, scope||this);
5235         this.fireEvent("datachanged", this);
5236     },
5237
5238     /**
5239      * Query the records by a specified property.
5240      * @param {String} field A field on your records
5241      * @param {String/RegExp} value Either a string that the field
5242      * should start with or a RegExp to test against the field
5243      * @param {Boolean} anyMatch True to match any part not just the beginning
5244      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5245      */
5246     query : function(property, value, anyMatch){
5247         var fn = this.createFilterFn(property, value, anyMatch);
5248         return fn ? this.queryBy(fn) : this.data.clone();
5249     },
5250
5251     /**
5252      * Query by a function. The specified function will be called with each
5253      * record in this data source. If the function returns true the record is included
5254      * in the results.
5255      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5256      * @param {Object} scope (optional) The scope of the function (defaults to this)
5257       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5258      **/
5259     queryBy : function(fn, scope){
5260         var data = this.snapshot || this.data;
5261         return data.filterBy(fn, scope||this);
5262     },
5263
5264     /**
5265      * Collects unique values for a particular dataIndex from this store.
5266      * @param {String} dataIndex The property to collect
5267      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5268      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5269      * @return {Array} An array of the unique values
5270      **/
5271     collect : function(dataIndex, allowNull, bypassFilter){
5272         var d = (bypassFilter === true && this.snapshot) ?
5273                 this.snapshot.items : this.data.items;
5274         var v, sv, r = [], l = {};
5275         for(var i = 0, len = d.length; i < len; i++){
5276             v = d[i].data[dataIndex];
5277             sv = String(v);
5278             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5279                 l[sv] = true;
5280                 r[r.length] = v;
5281             }
5282         }
5283         return r;
5284     },
5285
5286     /**
5287      * Revert to a view of the Record cache with no filtering applied.
5288      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5289      */
5290     clearFilter : function(suppressEvent){
5291         if(this.snapshot && this.snapshot != this.data){
5292             this.data = this.snapshot;
5293             delete this.snapshot;
5294             if(suppressEvent !== true){
5295                 this.fireEvent("datachanged", this);
5296             }
5297         }
5298     },
5299
5300     // private
5301     afterEdit : function(record){
5302         if(this.modified.indexOf(record) == -1){
5303             this.modified.push(record);
5304         }
5305         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5306     },
5307
5308     // private
5309     afterReject : function(record){
5310         this.modified.remove(record);
5311         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5312     },
5313
5314     // private
5315     afterCommit : function(record){
5316         this.modified.remove(record);
5317         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5318     },
5319
5320     /**
5321      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5322      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5323      */
5324     commitChanges : function(){
5325         var m = this.modified.slice(0);
5326         this.modified = [];
5327         for(var i = 0, len = m.length; i < len; i++){
5328             m[i].commit();
5329         }
5330     },
5331
5332     /**
5333      * Cancel outstanding changes on all changed records.
5334      */
5335     rejectChanges : function(){
5336         var m = this.modified.slice(0);
5337         this.modified = [];
5338         for(var i = 0, len = m.length; i < len; i++){
5339             m[i].reject();
5340         }
5341     },
5342
5343     onMetaChange : function(meta, rtype, o){
5344         this.recordType = rtype;
5345         this.fields = rtype.prototype.fields;
5346         delete this.snapshot;
5347         this.sortInfo = meta.sortInfo || this.sortInfo;
5348         this.modified = [];
5349         this.fireEvent('metachange', this, this.reader.meta);
5350     }
5351 });/*
5352  * Based on:
5353  * Ext JS Library 1.1.1
5354  * Copyright(c) 2006-2007, Ext JS, LLC.
5355  *
5356  * Originally Released Under LGPL - original licence link has changed is not relivant.
5357  *
5358  * Fork - LGPL
5359  * <script type="text/javascript">
5360  */
5361
5362 /**
5363  * @class Roo.data.SimpleStore
5364  * @extends Roo.data.Store
5365  * Small helper class to make creating Stores from Array data easier.
5366  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5367  * @cfg {Array} fields An array of field definition objects, or field name strings.
5368  * @cfg {Array} data The multi-dimensional array of data
5369  * @constructor
5370  * @param {Object} config
5371  */
5372 Roo.data.SimpleStore = function(config){
5373     Roo.data.SimpleStore.superclass.constructor.call(this, {
5374         isLocal : true,
5375         reader: new Roo.data.ArrayReader({
5376                 id: config.id
5377             },
5378             Roo.data.Record.create(config.fields)
5379         ),
5380         proxy : new Roo.data.MemoryProxy(config.data)
5381     });
5382     this.load();
5383 };
5384 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5385  * Based on:
5386  * Ext JS Library 1.1.1
5387  * Copyright(c) 2006-2007, Ext JS, LLC.
5388  *
5389  * Originally Released Under LGPL - original licence link has changed is not relivant.
5390  *
5391  * Fork - LGPL
5392  * <script type="text/javascript">
5393  */
5394
5395 /**
5396 /**
5397  * @extends Roo.data.Store
5398  * @class Roo.data.JsonStore
5399  * Small helper class to make creating Stores for JSON data easier. <br/>
5400 <pre><code>
5401 var store = new Roo.data.JsonStore({
5402     url: 'get-images.php',
5403     root: 'images',
5404     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5405 });
5406 </code></pre>
5407  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5408  * JsonReader and HttpProxy (unless inline data is provided).</b>
5409  * @cfg {Array} fields An array of field definition objects, or field name strings.
5410  * @constructor
5411  * @param {Object} config
5412  */
5413 Roo.data.JsonStore = function(c){
5414     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5415         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5416         reader: new Roo.data.JsonReader(c, c.fields)
5417     }));
5418 };
5419 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5420  * Based on:
5421  * Ext JS Library 1.1.1
5422  * Copyright(c) 2006-2007, Ext JS, LLC.
5423  *
5424  * Originally Released Under LGPL - original licence link has changed is not relivant.
5425  *
5426  * Fork - LGPL
5427  * <script type="text/javascript">
5428  */
5429
5430  
5431 Roo.data.Field = function(config){
5432     if(typeof config == "string"){
5433         config = {name: config};
5434     }
5435     Roo.apply(this, config);
5436     
5437     if(!this.type){
5438         this.type = "auto";
5439     }
5440     
5441     var st = Roo.data.SortTypes;
5442     // named sortTypes are supported, here we look them up
5443     if(typeof this.sortType == "string"){
5444         this.sortType = st[this.sortType];
5445     }
5446     
5447     // set default sortType for strings and dates
5448     if(!this.sortType){
5449         switch(this.type){
5450             case "string":
5451                 this.sortType = st.asUCString;
5452                 break;
5453             case "date":
5454                 this.sortType = st.asDate;
5455                 break;
5456             default:
5457                 this.sortType = st.none;
5458         }
5459     }
5460
5461     // define once
5462     var stripRe = /[\$,%]/g;
5463
5464     // prebuilt conversion function for this field, instead of
5465     // switching every time we're reading a value
5466     if(!this.convert){
5467         var cv, dateFormat = this.dateFormat;
5468         switch(this.type){
5469             case "":
5470             case "auto":
5471             case undefined:
5472                 cv = function(v){ return v; };
5473                 break;
5474             case "string":
5475                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5476                 break;
5477             case "int":
5478                 cv = function(v){
5479                     return v !== undefined && v !== null && v !== '' ?
5480                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5481                     };
5482                 break;
5483             case "float":
5484                 cv = function(v){
5485                     return v !== undefined && v !== null && v !== '' ?
5486                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5487                     };
5488                 break;
5489             case "bool":
5490             case "boolean":
5491                 cv = function(v){ return v === true || v === "true" || v == 1; };
5492                 break;
5493             case "date":
5494                 cv = function(v){
5495                     if(!v){
5496                         return '';
5497                     }
5498                     if(v instanceof Date){
5499                         return v;
5500                     }
5501                     if(dateFormat){
5502                         if(dateFormat == "timestamp"){
5503                             return new Date(v*1000);
5504                         }
5505                         return Date.parseDate(v, dateFormat);
5506                     }
5507                     var parsed = Date.parse(v);
5508                     return parsed ? new Date(parsed) : null;
5509                 };
5510              break;
5511             
5512         }
5513         this.convert = cv;
5514     }
5515 };
5516
5517 Roo.data.Field.prototype = {
5518     dateFormat: null,
5519     defaultValue: "",
5520     mapping: null,
5521     sortType : null,
5522     sortDir : "ASC"
5523 };/*
5524  * Based on:
5525  * Ext JS Library 1.1.1
5526  * Copyright(c) 2006-2007, Ext JS, LLC.
5527  *
5528  * Originally Released Under LGPL - original licence link has changed is not relivant.
5529  *
5530  * Fork - LGPL
5531  * <script type="text/javascript">
5532  */
5533  
5534 // Base class for reading structured data from a data source.  This class is intended to be
5535 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5536
5537 /**
5538  * @class Roo.data.DataReader
5539  * Base class for reading structured data from a data source.  This class is intended to be
5540  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5541  */
5542
5543 Roo.data.DataReader = function(meta, recordType){
5544     
5545     this.meta = meta;
5546     
5547     this.recordType = recordType instanceof Array ? 
5548         Roo.data.Record.create(recordType) : recordType;
5549 };
5550
5551 Roo.data.DataReader.prototype = {
5552      /**
5553      * Create an empty record
5554      * @param {Object} data (optional) - overlay some values
5555      * @return {Roo.data.Record} record created.
5556      */
5557     newRow :  function(d) {
5558         var da =  {};
5559         this.recordType.prototype.fields.each(function(c) {
5560             switch( c.type) {
5561                 case 'int' : da[c.name] = 0; break;
5562                 case 'date' : da[c.name] = new Date(); break;
5563                 case 'float' : da[c.name] = 0.0; break;
5564                 case 'boolean' : da[c.name] = false; break;
5565                 default : da[c.name] = ""; break;
5566             }
5567             
5568         });
5569         return new this.recordType(Roo.apply(da, d));
5570     }
5571     
5572 };/*
5573  * Based on:
5574  * Ext JS Library 1.1.1
5575  * Copyright(c) 2006-2007, Ext JS, LLC.
5576  *
5577  * Originally Released Under LGPL - original licence link has changed is not relivant.
5578  *
5579  * Fork - LGPL
5580  * <script type="text/javascript">
5581  */
5582
5583 /**
5584  * @class Roo.data.DataProxy
5585  * @extends Roo.data.Observable
5586  * This class is an abstract base class for implementations which provide retrieval of
5587  * unformatted data objects.<br>
5588  * <p>
5589  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5590  * (of the appropriate type which knows how to parse the data object) to provide a block of
5591  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5592  * <p>
5593  * Custom implementations must implement the load method as described in
5594  * {@link Roo.data.HttpProxy#load}.
5595  */
5596 Roo.data.DataProxy = function(){
5597     this.addEvents({
5598         /**
5599          * @event beforeload
5600          * Fires before a network request is made to retrieve a data object.
5601          * @param {Object} This DataProxy object.
5602          * @param {Object} params The params parameter to the load function.
5603          */
5604         beforeload : true,
5605         /**
5606          * @event load
5607          * Fires before the load method's callback is called.
5608          * @param {Object} This DataProxy object.
5609          * @param {Object} o The data object.
5610          * @param {Object} arg The callback argument object passed to the load function.
5611          */
5612         load : true,
5613         /**
5614          * @event loadexception
5615          * Fires if an Exception occurs during data retrieval.
5616          * @param {Object} This DataProxy object.
5617          * @param {Object} o The data object.
5618          * @param {Object} arg The callback argument object passed to the load function.
5619          * @param {Object} e The Exception.
5620          */
5621         loadexception : true
5622     });
5623     Roo.data.DataProxy.superclass.constructor.call(this);
5624 };
5625
5626 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5627
5628     /**
5629      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5630      */
5631 /*
5632  * Based on:
5633  * Ext JS Library 1.1.1
5634  * Copyright(c) 2006-2007, Ext JS, LLC.
5635  *
5636  * Originally Released Under LGPL - original licence link has changed is not relivant.
5637  *
5638  * Fork - LGPL
5639  * <script type="text/javascript">
5640  */
5641 /**
5642  * @class Roo.data.MemoryProxy
5643  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5644  * to the Reader when its load method is called.
5645  * @constructor
5646  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5647  */
5648 Roo.data.MemoryProxy = function(data){
5649     if (data.data) {
5650         data = data.data;
5651     }
5652     Roo.data.MemoryProxy.superclass.constructor.call(this);
5653     this.data = data;
5654 };
5655
5656 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5657     /**
5658      * Load data from the requested source (in this case an in-memory
5659      * data object passed to the constructor), read the data object into
5660      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5661      * process that block using the passed callback.
5662      * @param {Object} params This parameter is not used by the MemoryProxy class.
5663      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5664      * object into a block of Roo.data.Records.
5665      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5666      * The function must be passed <ul>
5667      * <li>The Record block object</li>
5668      * <li>The "arg" argument from the load function</li>
5669      * <li>A boolean success indicator</li>
5670      * </ul>
5671      * @param {Object} scope The scope in which to call the callback
5672      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5673      */
5674     load : function(params, reader, callback, scope, arg){
5675         params = params || {};
5676         var result;
5677         try {
5678             result = reader.readRecords(this.data);
5679         }catch(e){
5680             this.fireEvent("loadexception", this, arg, null, e);
5681             callback.call(scope, null, arg, false);
5682             return;
5683         }
5684         callback.call(scope, result, arg, true);
5685     },
5686     
5687     // private
5688     update : function(params, records){
5689         
5690     }
5691 });/*
5692  * Based on:
5693  * Ext JS Library 1.1.1
5694  * Copyright(c) 2006-2007, Ext JS, LLC.
5695  *
5696  * Originally Released Under LGPL - original licence link has changed is not relivant.
5697  *
5698  * Fork - LGPL
5699  * <script type="text/javascript">
5700  */
5701 /**
5702  * @class Roo.data.HttpProxy
5703  * @extends Roo.data.DataProxy
5704  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5705  * configured to reference a certain URL.<br><br>
5706  * <p>
5707  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5708  * from which the running page was served.<br><br>
5709  * <p>
5710  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5711  * <p>
5712  * Be aware that to enable the browser to parse an XML document, the server must set
5713  * the Content-Type header in the HTTP response to "text/xml".
5714  * @constructor
5715  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5716  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5717  * will be used to make the request.
5718  */
5719 Roo.data.HttpProxy = function(conn){
5720     Roo.data.HttpProxy.superclass.constructor.call(this);
5721     // is conn a conn config or a real conn?
5722     this.conn = conn;
5723     this.useAjax = !conn || !conn.events;
5724   
5725 };
5726
5727 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5728     // thse are take from connection...
5729     
5730     /**
5731      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5732      */
5733     /**
5734      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5735      * extra parameters to each request made by this object. (defaults to undefined)
5736      */
5737     /**
5738      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5739      *  to each request made by this object. (defaults to undefined)
5740      */
5741     /**
5742      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5743      */
5744     /**
5745      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5746      */
5747      /**
5748      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5749      * @type Boolean
5750      */
5751   
5752
5753     /**
5754      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5755      * @type Boolean
5756      */
5757     /**
5758      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5759      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5760      * a finer-grained basis than the DataProxy events.
5761      */
5762     getConnection : function(){
5763         return this.useAjax ? Roo.Ajax : this.conn;
5764     },
5765
5766     /**
5767      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5768      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5769      * process that block using the passed callback.
5770      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5771      * for the request to the remote server.
5772      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5773      * object into a block of Roo.data.Records.
5774      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5775      * The function must be passed <ul>
5776      * <li>The Record block object</li>
5777      * <li>The "arg" argument from the load function</li>
5778      * <li>A boolean success indicator</li>
5779      * </ul>
5780      * @param {Object} scope The scope in which to call the callback
5781      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5782      */
5783     load : function(params, reader, callback, scope, arg){
5784         if(this.fireEvent("beforeload", this, params) !== false){
5785             var  o = {
5786                 params : params || {},
5787                 request: {
5788                     callback : callback,
5789                     scope : scope,
5790                     arg : arg
5791                 },
5792                 reader: reader,
5793                 callback : this.loadResponse,
5794                 scope: this
5795             };
5796             if(this.useAjax){
5797                 Roo.applyIf(o, this.conn);
5798                 if(this.activeRequest){
5799                     Roo.Ajax.abort(this.activeRequest);
5800                 }
5801                 this.activeRequest = Roo.Ajax.request(o);
5802             }else{
5803                 this.conn.request(o);
5804             }
5805         }else{
5806             callback.call(scope||this, null, arg, false);
5807         }
5808     },
5809
5810     // private
5811     loadResponse : function(o, success, response){
5812         delete this.activeRequest;
5813         if(!success){
5814             this.fireEvent("loadexception", this, o, response);
5815             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5816             return;
5817         }
5818         var result;
5819         try {
5820             result = o.reader.read(response);
5821         }catch(e){
5822             this.fireEvent("loadexception", this, o, response, e);
5823             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5824             return;
5825         }
5826         
5827         this.fireEvent("load", this, o, o.request.arg);
5828         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5829     },
5830
5831     // private
5832     update : function(dataSet){
5833
5834     },
5835
5836     // private
5837     updateResponse : function(dataSet){
5838
5839     }
5840 });/*
5841  * Based on:
5842  * Ext JS Library 1.1.1
5843  * Copyright(c) 2006-2007, Ext JS, LLC.
5844  *
5845  * Originally Released Under LGPL - original licence link has changed is not relivant.
5846  *
5847  * Fork - LGPL
5848  * <script type="text/javascript">
5849  */
5850
5851 /**
5852  * @class Roo.data.ScriptTagProxy
5853  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5854  * other than the originating domain of the running page.<br><br>
5855  * <p>
5856  * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5857  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5858  * <p>
5859  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5860  * source code that is used as the source inside a &lt;script> tag.<br><br>
5861  * <p>
5862  * In order for the browser to process the returned data, the server must wrap the data object
5863  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5864  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5865  * depending on whether the callback name was passed:
5866  * <p>
5867  * <pre><code>
5868 boolean scriptTag = false;
5869 String cb = request.getParameter("callback");
5870 if (cb != null) {
5871     scriptTag = true;
5872     response.setContentType("text/javascript");
5873 } else {
5874     response.setContentType("application/x-json");
5875 }
5876 Writer out = response.getWriter();
5877 if (scriptTag) {
5878     out.write(cb + "(");
5879 }
5880 out.print(dataBlock.toJsonString());
5881 if (scriptTag) {
5882     out.write(");");
5883 }
5884 </pre></code>
5885  *
5886  * @constructor
5887  * @param {Object} config A configuration object.
5888  */
5889 Roo.data.ScriptTagProxy = function(config){
5890     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5891     Roo.apply(this, config);
5892     this.head = document.getElementsByTagName("head")[0];
5893 };
5894
5895 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5896
5897 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5898     /**
5899      * @cfg {String} url The URL from which to request the data object.
5900      */
5901     /**
5902      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5903      */
5904     timeout : 30000,
5905     /**
5906      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5907      * the server the name of the callback function set up by the load call to process the returned data object.
5908      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5909      * javascript output which calls this named function passing the data object as its only parameter.
5910      */
5911     callbackParam : "callback",
5912     /**
5913      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5914      * name to the request.
5915      */
5916     nocache : true,
5917
5918     /**
5919      * Load data from the configured URL, read the data object into
5920      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5921      * process that block using the passed callback.
5922      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5923      * for the request to the remote server.
5924      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5925      * object into a block of Roo.data.Records.
5926      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5927      * The function must be passed <ul>
5928      * <li>The Record block object</li>
5929      * <li>The "arg" argument from the load function</li>
5930      * <li>A boolean success indicator</li>
5931      * </ul>
5932      * @param {Object} scope The scope in which to call the callback
5933      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5934      */
5935     load : function(params, reader, callback, scope, arg){
5936         if(this.fireEvent("beforeload", this, params) !== false){
5937
5938             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5939
5940             var url = this.url;
5941             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5942             if(this.nocache){
5943                 url += "&_dc=" + (new Date().getTime());
5944             }
5945             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5946             var trans = {
5947                 id : transId,
5948                 cb : "stcCallback"+transId,
5949                 scriptId : "stcScript"+transId,
5950                 params : params,
5951                 arg : arg,
5952                 url : url,
5953                 callback : callback,
5954                 scope : scope,
5955                 reader : reader
5956             };
5957             var conn = this;
5958
5959             window[trans.cb] = function(o){
5960                 conn.handleResponse(o, trans);
5961             };
5962
5963             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5964
5965             if(this.autoAbort !== false){
5966                 this.abort();
5967             }
5968
5969             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5970
5971             var script = document.createElement("script");
5972             script.setAttribute("src", url);
5973             script.setAttribute("type", "text/javascript");
5974             script.setAttribute("id", trans.scriptId);
5975             this.head.appendChild(script);
5976
5977             this.trans = trans;
5978         }else{
5979             callback.call(scope||this, null, arg, false);
5980         }
5981     },
5982
5983     // private
5984     isLoading : function(){
5985         return this.trans ? true : false;
5986     },
5987
5988     /**
5989      * Abort the current server request.
5990      */
5991     abort : function(){
5992         if(this.isLoading()){
5993             this.destroyTrans(this.trans);
5994         }
5995     },
5996
5997     // private
5998     destroyTrans : function(trans, isLoaded){
5999         this.head.removeChild(document.getElementById(trans.scriptId));
6000         clearTimeout(trans.timeoutId);
6001         if(isLoaded){
6002             window[trans.cb] = undefined;
6003             try{
6004                 delete window[trans.cb];
6005             }catch(e){}
6006         }else{
6007             // if hasn't been loaded, wait for load to remove it to prevent script error
6008             window[trans.cb] = function(){
6009                 window[trans.cb] = undefined;
6010                 try{
6011                     delete window[trans.cb];
6012                 }catch(e){}
6013             };
6014         }
6015     },
6016
6017     // private
6018     handleResponse : function(o, trans){
6019         this.trans = false;
6020         this.destroyTrans(trans, true);
6021         var result;
6022         try {
6023             result = trans.reader.readRecords(o);
6024         }catch(e){
6025             this.fireEvent("loadexception", this, o, trans.arg, e);
6026             trans.callback.call(trans.scope||window, null, trans.arg, false);
6027             return;
6028         }
6029         this.fireEvent("load", this, o, trans.arg);
6030         trans.callback.call(trans.scope||window, result, trans.arg, true);
6031     },
6032
6033     // private
6034     handleFailure : function(trans){
6035         this.trans = false;
6036         this.destroyTrans(trans, false);
6037         this.fireEvent("loadexception", this, null, trans.arg);
6038         trans.callback.call(trans.scope||window, null, trans.arg, false);
6039     }
6040 });/*
6041  * Based on:
6042  * Ext JS Library 1.1.1
6043  * Copyright(c) 2006-2007, Ext JS, LLC.
6044  *
6045  * Originally Released Under LGPL - original licence link has changed is not relivant.
6046  *
6047  * Fork - LGPL
6048  * <script type="text/javascript">
6049  */
6050
6051 /**
6052  * @class Roo.data.JsonReader
6053  * @extends Roo.data.DataReader
6054  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6055  * based on mappings in a provided Roo.data.Record constructor.
6056  * 
6057  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6058  * in the reply previously. 
6059  * 
6060  * <p>
6061  * Example code:
6062  * <pre><code>
6063 var RecordDef = Roo.data.Record.create([
6064     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6065     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6066 ]);
6067 var myReader = new Roo.data.JsonReader({
6068     totalProperty: "results",    // The property which contains the total dataset size (optional)
6069     root: "rows",                // The property which contains an Array of row objects
6070     id: "id"                     // The property within each row object that provides an ID for the record (optional)
6071 }, RecordDef);
6072 </code></pre>
6073  * <p>
6074  * This would consume a JSON file like this:
6075  * <pre><code>
6076 { 'results': 2, 'rows': [
6077     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6078     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6079 }
6080 </code></pre>
6081  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6082  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6083  * paged from the remote server.
6084  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6085  * @cfg {String} root name of the property which contains the Array of row objects.
6086  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6087  * @constructor
6088  * Create a new JsonReader
6089  * @param {Object} meta Metadata configuration options
6090  * @param {Object} recordType Either an Array of field definition objects,
6091  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6092  */
6093 Roo.data.JsonReader = function(meta, recordType){
6094     
6095     meta = meta || {};
6096     // set some defaults:
6097     Roo.applyIf(meta, {
6098         totalProperty: 'total',
6099         successProperty : 'success',
6100         root : 'data',
6101         id : 'id'
6102     });
6103     
6104     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6105 };
6106 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6107     
6108     /**
6109      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
6110      * Used by Store query builder to append _requestMeta to params.
6111      * 
6112      */
6113     metaFromRemote : false,
6114     /**
6115      * This method is only used by a DataProxy which has retrieved data from a remote server.
6116      * @param {Object} response The XHR object which contains the JSON data in its responseText.
6117      * @return {Object} data A data block which is used by an Roo.data.Store object as
6118      * a cache of Roo.data.Records.
6119      */
6120     read : function(response){
6121         var json = response.responseText;
6122        
6123         var o = /* eval:var:o */ eval("("+json+")");
6124         if(!o) {
6125             throw {message: "JsonReader.read: Json object not found"};
6126         }
6127         
6128         if(o.metaData){
6129             
6130             delete this.ef;
6131             this.metaFromRemote = true;
6132             this.meta = o.metaData;
6133             this.recordType = Roo.data.Record.create(o.metaData.fields);
6134             this.onMetaChange(this.meta, this.recordType, o);
6135         }
6136         return this.readRecords(o);
6137     },
6138
6139     // private function a store will implement
6140     onMetaChange : function(meta, recordType, o){
6141
6142     },
6143
6144     /**
6145          * @ignore
6146          */
6147     simpleAccess: function(obj, subsc) {
6148         return obj[subsc];
6149     },
6150
6151         /**
6152          * @ignore
6153          */
6154     getJsonAccessor: function(){
6155         var re = /[\[\.]/;
6156         return function(expr) {
6157             try {
6158                 return(re.test(expr))
6159                     ? new Function("obj", "return obj." + expr)
6160                     : function(obj){
6161                         return obj[expr];
6162                     };
6163             } catch(e){}
6164             return Roo.emptyFn;
6165         };
6166     }(),
6167
6168     /**
6169      * Create a data block containing Roo.data.Records from an XML document.
6170      * @param {Object} o An object which contains an Array of row objects in the property specified
6171      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6172      * which contains the total size of the dataset.
6173      * @return {Object} data A data block which is used by an Roo.data.Store object as
6174      * a cache of Roo.data.Records.
6175      */
6176     readRecords : function(o){
6177         /**
6178          * After any data loads, the raw JSON data is available for further custom processing.
6179          * @type Object
6180          */
6181         this.jsonData = o;
6182         var s = this.meta, Record = this.recordType,
6183             f = Record.prototype.fields, fi = f.items, fl = f.length;
6184
6185 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
6186         if (!this.ef) {
6187             if(s.totalProperty) {
6188                     this.getTotal = this.getJsonAccessor(s.totalProperty);
6189                 }
6190                 if(s.successProperty) {
6191                     this.getSuccess = this.getJsonAccessor(s.successProperty);
6192                 }
6193                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6194                 if (s.id) {
6195                         var g = this.getJsonAccessor(s.id);
6196                         this.getId = function(rec) {
6197                                 var r = g(rec);
6198                                 return (r === undefined || r === "") ? null : r;
6199                         };
6200                 } else {
6201                         this.getId = function(){return null;};
6202                 }
6203             this.ef = [];
6204             for(var jj = 0; jj < fl; jj++){
6205                 f = fi[jj];
6206                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6207                 this.ef[jj] = this.getJsonAccessor(map);
6208             }
6209         }
6210
6211         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6212         if(s.totalProperty){
6213             var vt = parseInt(this.getTotal(o), 10);
6214             if(!isNaN(vt)){
6215                 totalRecords = vt;
6216             }
6217         }
6218         if(s.successProperty){
6219             var vs = this.getSuccess(o);
6220             if(vs === false || vs === 'false'){
6221                 success = false;
6222             }
6223         }
6224         var records = [];
6225             for(var i = 0; i < c; i++){
6226                     var n = root[i];
6227                 var values = {};
6228                 var id = this.getId(n);
6229                 for(var j = 0; j < fl; j++){
6230                     f = fi[j];
6231                 var v = this.ef[j](n);
6232                 if (!f.convert) {
6233                     Roo.log('missing convert for ' + f.name);
6234                     Roo.log(f);
6235                     continue;
6236                 }
6237                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6238                 }
6239                 var record = new Record(values, id);
6240                 record.json = n;
6241                 records[i] = record;
6242             }
6243             return {
6244                 success : success,
6245                 records : records,
6246                 totalRecords : totalRecords
6247             };
6248     }
6249 });/*
6250  * Based on:
6251  * Ext JS Library 1.1.1
6252  * Copyright(c) 2006-2007, Ext JS, LLC.
6253  *
6254  * Originally Released Under LGPL - original licence link has changed is not relivant.
6255  *
6256  * Fork - LGPL
6257  * <script type="text/javascript">
6258  */
6259
6260 /**
6261  * @class Roo.data.XmlReader
6262  * @extends Roo.data.DataReader
6263  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6264  * based on mappings in a provided Roo.data.Record constructor.<br><br>
6265  * <p>
6266  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6267  * header in the HTTP response must be set to "text/xml".</em>
6268  * <p>
6269  * Example code:
6270  * <pre><code>
6271 var RecordDef = Roo.data.Record.create([
6272    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6273    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6274 ]);
6275 var myReader = new Roo.data.XmlReader({
6276    totalRecords: "results", // The element which contains the total dataset size (optional)
6277    record: "row",           // The repeated element which contains row information
6278    id: "id"                 // The element within the row that provides an ID for the record (optional)
6279 }, RecordDef);
6280 </code></pre>
6281  * <p>
6282  * This would consume an XML file like this:
6283  * <pre><code>
6284 &lt;?xml?>
6285 &lt;dataset>
6286  &lt;results>2&lt;/results>
6287  &lt;row>
6288    &lt;id>1&lt;/id>
6289    &lt;name>Bill&lt;/name>
6290    &lt;occupation>Gardener&lt;/occupation>
6291  &lt;/row>
6292  &lt;row>
6293    &lt;id>2&lt;/id>
6294    &lt;name>Ben&lt;/name>
6295    &lt;occupation>Horticulturalist&lt;/occupation>
6296  &lt;/row>
6297 &lt;/dataset>
6298 </code></pre>
6299  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6300  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6301  * paged from the remote server.
6302  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6303  * @cfg {String} success The DomQuery path to the success attribute used by forms.
6304  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6305  * a record identifier value.
6306  * @constructor
6307  * Create a new XmlReader
6308  * @param {Object} meta Metadata configuration options
6309  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
6310  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6311  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
6312  */
6313 Roo.data.XmlReader = function(meta, recordType){
6314     meta = meta || {};
6315     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6316 };
6317 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6318     /**
6319      * This method is only used by a DataProxy which has retrieved data from a remote server.
6320          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
6321          * to contain a method called 'responseXML' that returns an XML document object.
6322      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6323      * a cache of Roo.data.Records.
6324      */
6325     read : function(response){
6326         var doc = response.responseXML;
6327         if(!doc) {
6328             throw {message: "XmlReader.read: XML Document not available"};
6329         }
6330         return this.readRecords(doc);
6331     },
6332
6333     /**
6334      * Create a data block containing Roo.data.Records from an XML document.
6335          * @param {Object} doc A parsed XML document.
6336      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6337      * a cache of Roo.data.Records.
6338      */
6339     readRecords : function(doc){
6340         /**
6341          * After any data loads/reads, the raw XML Document is available for further custom processing.
6342          * @type XMLDocument
6343          */
6344         this.xmlData = doc;
6345         var root = doc.documentElement || doc;
6346         var q = Roo.DomQuery;
6347         var recordType = this.recordType, fields = recordType.prototype.fields;
6348         var sid = this.meta.id;
6349         var totalRecords = 0, success = true;
6350         if(this.meta.totalRecords){
6351             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6352         }
6353         
6354         if(this.meta.success){
6355             var sv = q.selectValue(this.meta.success, root, true);
6356             success = sv !== false && sv !== 'false';
6357         }
6358         var records = [];
6359         var ns = q.select(this.meta.record, root);
6360         for(var i = 0, len = ns.length; i < len; i++) {
6361                 var n = ns[i];
6362                 var values = {};
6363                 var id = sid ? q.selectValue(sid, n) : undefined;
6364                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6365                     var f = fields.items[j];
6366                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6367                     v = f.convert(v);
6368                     values[f.name] = v;
6369                 }
6370                 var record = new recordType(values, id);
6371                 record.node = n;
6372                 records[records.length] = record;
6373             }
6374
6375             return {
6376                 success : success,
6377                 records : records,
6378                 totalRecords : totalRecords || records.length
6379             };
6380     }
6381 });/*
6382  * Based on:
6383  * Ext JS Library 1.1.1
6384  * Copyright(c) 2006-2007, Ext JS, LLC.
6385  *
6386  * Originally Released Under LGPL - original licence link has changed is not relivant.
6387  *
6388  * Fork - LGPL
6389  * <script type="text/javascript">
6390  */
6391
6392 /**
6393  * @class Roo.data.ArrayReader
6394  * @extends Roo.data.DataReader
6395  * Data reader class to create an Array of Roo.data.Record objects from an Array.
6396  * Each element of that Array represents a row of data fields. The
6397  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6398  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6399  * <p>
6400  * Example code:.
6401  * <pre><code>
6402 var RecordDef = Roo.data.Record.create([
6403     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
6404     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
6405 ]);
6406 var myReader = new Roo.data.ArrayReader({
6407     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
6408 }, RecordDef);
6409 </code></pre>
6410  * <p>
6411  * This would consume an Array like this:
6412  * <pre><code>
6413 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6414   </code></pre>
6415  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6416  * @constructor
6417  * Create a new JsonReader
6418  * @param {Object} meta Metadata configuration options.
6419  * @param {Object} recordType Either an Array of field definition objects
6420  * as specified to {@link Roo.data.Record#create},
6421  * or an {@link Roo.data.Record} object
6422  * created using {@link Roo.data.Record#create}.
6423  */
6424 Roo.data.ArrayReader = function(meta, recordType){
6425     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6426 };
6427
6428 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6429     /**
6430      * Create a data block containing Roo.data.Records from an XML document.
6431      * @param {Object} o An Array of row objects which represents the dataset.
6432      * @return {Object} data A data block which is used by an Roo.data.Store object as
6433      * a cache of Roo.data.Records.
6434      */
6435     readRecords : function(o){
6436         var sid = this.meta ? this.meta.id : null;
6437         var recordType = this.recordType, fields = recordType.prototype.fields;
6438         var records = [];
6439         var root = o;
6440             for(var i = 0; i < root.length; i++){
6441                     var n = root[i];
6442                 var values = {};
6443                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6444                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6445                 var f = fields.items[j];
6446                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6447                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6448                 v = f.convert(v);
6449                 values[f.name] = v;
6450             }
6451                 var record = new recordType(values, id);
6452                 record.json = n;
6453                 records[records.length] = record;
6454             }
6455             return {
6456                 records : records,
6457                 totalRecords : records.length
6458             };
6459     }
6460 });/*
6461  * Based on:
6462  * Ext JS Library 1.1.1
6463  * Copyright(c) 2006-2007, Ext JS, LLC.
6464  *
6465  * Originally Released Under LGPL - original licence link has changed is not relivant.
6466  *
6467  * Fork - LGPL
6468  * <script type="text/javascript">
6469  */
6470
6471
6472 /**
6473  * @class Roo.data.Tree
6474  * @extends Roo.util.Observable
6475  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6476  * in the tree have most standard DOM functionality.
6477  * @constructor
6478  * @param {Node} root (optional) The root node
6479  */
6480 Roo.data.Tree = function(root){
6481    this.nodeHash = {};
6482    /**
6483     * The root node for this tree
6484     * @type Node
6485     */
6486    this.root = null;
6487    if(root){
6488        this.setRootNode(root);
6489    }
6490    this.addEvents({
6491        /**
6492         * @event append
6493         * Fires when a new child node is appended to a node in this tree.
6494         * @param {Tree} tree The owner tree
6495         * @param {Node} parent The parent node
6496         * @param {Node} node The newly appended node
6497         * @param {Number} index The index of the newly appended node
6498         */
6499        "append" : true,
6500        /**
6501         * @event remove
6502         * Fires when a child node is removed from a node in this tree.
6503         * @param {Tree} tree The owner tree
6504         * @param {Node} parent The parent node
6505         * @param {Node} node The child node removed
6506         */
6507        "remove" : true,
6508        /**
6509         * @event move
6510         * Fires when a node is moved to a new location in the tree
6511         * @param {Tree} tree The owner tree
6512         * @param {Node} node The node moved
6513         * @param {Node} oldParent The old parent of this node
6514         * @param {Node} newParent The new parent of this node
6515         * @param {Number} index The index it was moved to
6516         */
6517        "move" : true,
6518        /**
6519         * @event insert
6520         * Fires when a new child node is inserted in a node in this tree.
6521         * @param {Tree} tree The owner tree
6522         * @param {Node} parent The parent node
6523         * @param {Node} node The child node inserted
6524         * @param {Node} refNode The child node the node was inserted before
6525         */
6526        "insert" : true,
6527        /**
6528         * @event beforeappend
6529         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6530         * @param {Tree} tree The owner tree
6531         * @param {Node} parent The parent node
6532         * @param {Node} node The child node to be appended
6533         */
6534        "beforeappend" : true,
6535        /**
6536         * @event beforeremove
6537         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6538         * @param {Tree} tree The owner tree
6539         * @param {Node} parent The parent node
6540         * @param {Node} node The child node to be removed
6541         */
6542        "beforeremove" : true,
6543        /**
6544         * @event beforemove
6545         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6546         * @param {Tree} tree The owner tree
6547         * @param {Node} node The node being moved
6548         * @param {Node} oldParent The parent of the node
6549         * @param {Node} newParent The new parent the node is moving to
6550         * @param {Number} index The index it is being moved to
6551         */
6552        "beforemove" : true,
6553        /**
6554         * @event beforeinsert
6555         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6556         * @param {Tree} tree The owner tree
6557         * @param {Node} parent The parent node
6558         * @param {Node} node The child node to be inserted
6559         * @param {Node} refNode The child node the node is being inserted before
6560         */
6561        "beforeinsert" : true
6562    });
6563
6564     Roo.data.Tree.superclass.constructor.call(this);
6565 };
6566
6567 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6568     pathSeparator: "/",
6569
6570     proxyNodeEvent : function(){
6571         return this.fireEvent.apply(this, arguments);
6572     },
6573
6574     /**
6575      * Returns the root node for this tree.
6576      * @return {Node}
6577      */
6578     getRootNode : function(){
6579         return this.root;
6580     },
6581
6582     /**
6583      * Sets the root node for this tree.
6584      * @param {Node} node
6585      * @return {Node}
6586      */
6587     setRootNode : function(node){
6588         this.root = node;
6589         node.ownerTree = this;
6590         node.isRoot = true;
6591         this.registerNode(node);
6592         return node;
6593     },
6594
6595     /**
6596      * Gets a node in this tree by its id.
6597      * @param {String} id
6598      * @return {Node}
6599      */
6600     getNodeById : function(id){
6601         return this.nodeHash[id];
6602     },
6603
6604     registerNode : function(node){
6605         this.nodeHash[node.id] = node;
6606     },
6607
6608     unregisterNode : function(node){
6609         delete this.nodeHash[node.id];
6610     },
6611
6612     toString : function(){
6613         return "[Tree"+(this.id?" "+this.id:"")+"]";
6614     }
6615 });
6616
6617 /**
6618  * @class Roo.data.Node
6619  * @extends Roo.util.Observable
6620  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6621  * @cfg {String} id The id for this node. If one is not specified, one is generated.
6622  * @constructor
6623  * @param {Object} attributes The attributes/config for the node
6624  */
6625 Roo.data.Node = function(attributes){
6626     /**
6627      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6628      * @type {Object}
6629      */
6630     this.attributes = attributes || {};
6631     this.leaf = this.attributes.leaf;
6632     /**
6633      * The node id. @type String
6634      */
6635     this.id = this.attributes.id;
6636     if(!this.id){
6637         this.id = Roo.id(null, "ynode-");
6638         this.attributes.id = this.id;
6639     }
6640     /**
6641      * All child nodes of this node. @type Array
6642      */
6643     this.childNodes = [];
6644     if(!this.childNodes.indexOf){ // indexOf is a must
6645         this.childNodes.indexOf = function(o){
6646             for(var i = 0, len = this.length; i < len; i++){
6647                 if(this[i] == o) {
6648                     return i;
6649                 }
6650             }
6651             return -1;
6652         };
6653     }
6654     /**
6655      * The parent node for this node. @type Node
6656      */
6657     this.parentNode = null;
6658     /**
6659      * The first direct child node of this node, or null if this node has no child nodes. @type Node
6660      */
6661     this.firstChild = null;
6662     /**
6663      * The last direct child node of this node, or null if this node has no child nodes. @type Node
6664      */
6665     this.lastChild = null;
6666     /**
6667      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6668      */
6669     this.previousSibling = null;
6670     /**
6671      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6672      */
6673     this.nextSibling = null;
6674
6675     this.addEvents({
6676        /**
6677         * @event append
6678         * Fires when a new child node is appended
6679         * @param {Tree} tree The owner tree
6680         * @param {Node} this This node
6681         * @param {Node} node The newly appended node
6682         * @param {Number} index The index of the newly appended node
6683         */
6684        "append" : true,
6685        /**
6686         * @event remove
6687         * Fires when a child node is removed
6688         * @param {Tree} tree The owner tree
6689         * @param {Node} this This node
6690         * @param {Node} node The removed node
6691         */
6692        "remove" : true,
6693        /**
6694         * @event move
6695         * Fires when this node is moved to a new location in the tree
6696         * @param {Tree} tree The owner tree
6697         * @param {Node} this This node
6698         * @param {Node} oldParent The old parent of this node
6699         * @param {Node} newParent The new parent of this node
6700         * @param {Number} index The index it was moved to
6701         */
6702        "move" : true,
6703        /**
6704         * @event insert
6705         * Fires when a new child node is inserted.
6706         * @param {Tree} tree The owner tree
6707         * @param {Node} this This node
6708         * @param {Node} node The child node inserted
6709         * @param {Node} refNode The child node the node was inserted before
6710         */
6711        "insert" : true,
6712        /**
6713         * @event beforeappend
6714         * Fires before a new child is appended, return false to cancel the append.
6715         * @param {Tree} tree The owner tree
6716         * @param {Node} this This node
6717         * @param {Node} node The child node to be appended
6718         */
6719        "beforeappend" : true,
6720        /**
6721         * @event beforeremove
6722         * Fires before a child is removed, return false to cancel the remove.
6723         * @param {Tree} tree The owner tree
6724         * @param {Node} this This node
6725         * @param {Node} node The child node to be removed
6726         */
6727        "beforeremove" : true,
6728        /**
6729         * @event beforemove
6730         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6731         * @param {Tree} tree The owner tree
6732         * @param {Node} this This node
6733         * @param {Node} oldParent The parent of this node
6734         * @param {Node} newParent The new parent this node is moving to
6735         * @param {Number} index The index it is being moved to
6736         */
6737        "beforemove" : true,
6738        /**
6739         * @event beforeinsert
6740         * Fires before a new child is inserted, return false to cancel the insert.
6741         * @param {Tree} tree The owner tree
6742         * @param {Node} this This node
6743         * @param {Node} node The child node to be inserted
6744         * @param {Node} refNode The child node the node is being inserted before
6745         */
6746        "beforeinsert" : true
6747    });
6748     this.listeners = this.attributes.listeners;
6749     Roo.data.Node.superclass.constructor.call(this);
6750 };
6751
6752 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6753     fireEvent : function(evtName){
6754         // first do standard event for this node
6755         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6756             return false;
6757         }
6758         // then bubble it up to the tree if the event wasn't cancelled
6759         var ot = this.getOwnerTree();
6760         if(ot){
6761             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6762                 return false;
6763             }
6764         }
6765         return true;
6766     },
6767
6768     /**
6769      * Returns true if this node is a leaf
6770      * @return {Boolean}
6771      */
6772     isLeaf : function(){
6773         return this.leaf === true;
6774     },
6775
6776     // private
6777     setFirstChild : function(node){
6778         this.firstChild = node;
6779     },
6780
6781     //private
6782     setLastChild : function(node){
6783         this.lastChild = node;
6784     },
6785
6786
6787     /**
6788      * Returns true if this node is the last child of its parent
6789      * @return {Boolean}
6790      */
6791     isLast : function(){
6792        return (!this.parentNode ? true : this.parentNode.lastChild == this);
6793     },
6794
6795     /**
6796      * Returns true if this node is the first child of its parent
6797      * @return {Boolean}
6798      */
6799     isFirst : function(){
6800        return (!this.parentNode ? true : this.parentNode.firstChild == this);
6801     },
6802
6803     hasChildNodes : function(){
6804         return !this.isLeaf() && this.childNodes.length > 0;
6805     },
6806
6807     /**
6808      * Insert node(s) as the last child node of this node.
6809      * @param {Node/Array} node The node or Array of nodes to append
6810      * @return {Node} The appended node if single append, or null if an array was passed
6811      */
6812     appendChild : function(node){
6813         var multi = false;
6814         if(node instanceof Array){
6815             multi = node;
6816         }else if(arguments.length > 1){
6817             multi = arguments;
6818         }
6819         // if passed an array or multiple args do them one by one
6820         if(multi){
6821             for(var i = 0, len = multi.length; i < len; i++) {
6822                 this.appendChild(multi[i]);
6823             }
6824         }else{
6825             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6826                 return false;
6827             }
6828             var index = this.childNodes.length;
6829             var oldParent = node.parentNode;
6830             // it's a move, make sure we move it cleanly
6831             if(oldParent){
6832                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6833                     return false;
6834                 }
6835                 oldParent.removeChild(node);
6836             }
6837             index = this.childNodes.length;
6838             if(index == 0){
6839                 this.setFirstChild(node);
6840             }
6841             this.childNodes.push(node);
6842             node.parentNode = this;
6843             var ps = this.childNodes[index-1];
6844             if(ps){
6845                 node.previousSibling = ps;
6846                 ps.nextSibling = node;
6847             }else{
6848                 node.previousSibling = null;
6849             }
6850             node.nextSibling = null;
6851             this.setLastChild(node);
6852             node.setOwnerTree(this.getOwnerTree());
6853             this.fireEvent("append", this.ownerTree, this, node, index);
6854             if(oldParent){
6855                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6856             }
6857             return node;
6858         }
6859     },
6860
6861     /**
6862      * Removes a child node from this node.
6863      * @param {Node} node The node to remove
6864      * @return {Node} The removed node
6865      */
6866     removeChild : function(node){
6867         var index = this.childNodes.indexOf(node);
6868         if(index == -1){
6869             return false;
6870         }
6871         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6872             return false;
6873         }
6874
6875         // remove it from childNodes collection
6876         this.childNodes.splice(index, 1);
6877
6878         // update siblings
6879         if(node.previousSibling){
6880             node.previousSibling.nextSibling = node.nextSibling;
6881         }
6882         if(node.nextSibling){
6883             node.nextSibling.previousSibling = node.previousSibling;
6884         }
6885
6886         // update child refs
6887         if(this.firstChild == node){
6888             this.setFirstChild(node.nextSibling);
6889         }
6890         if(this.lastChild == node){
6891             this.setLastChild(node.previousSibling);
6892         }
6893
6894         node.setOwnerTree(null);
6895         // clear any references from the node
6896         node.parentNode = null;
6897         node.previousSibling = null;
6898         node.nextSibling = null;
6899         this.fireEvent("remove", this.ownerTree, this, node);
6900         return node;
6901     },
6902
6903     /**
6904      * Inserts the first node before the second node in this nodes childNodes collection.
6905      * @param {Node} node The node to insert
6906      * @param {Node} refNode The node to insert before (if null the node is appended)
6907      * @return {Node} The inserted node
6908      */
6909     insertBefore : function(node, refNode){
6910         if(!refNode){ // like standard Dom, refNode can be null for append
6911             return this.appendChild(node);
6912         }
6913         // nothing to do
6914         if(node == refNode){
6915             return false;
6916         }
6917
6918         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6919             return false;
6920         }
6921         var index = this.childNodes.indexOf(refNode);
6922         var oldParent = node.parentNode;
6923         var refIndex = index;
6924
6925         // when moving internally, indexes will change after remove
6926         if(oldParent == this && this.childNodes.indexOf(node) < index){
6927             refIndex--;
6928         }
6929
6930         // it's a move, make sure we move it cleanly
6931         if(oldParent){
6932             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6933                 return false;
6934             }
6935             oldParent.removeChild(node);
6936         }
6937         if(refIndex == 0){
6938             this.setFirstChild(node);
6939         }
6940         this.childNodes.splice(refIndex, 0, node);
6941         node.parentNode = this;
6942         var ps = this.childNodes[refIndex-1];
6943         if(ps){
6944             node.previousSibling = ps;
6945             ps.nextSibling = node;
6946         }else{
6947             node.previousSibling = null;
6948         }
6949         node.nextSibling = refNode;
6950         refNode.previousSibling = node;
6951         node.setOwnerTree(this.getOwnerTree());
6952         this.fireEvent("insert", this.ownerTree, this, node, refNode);
6953         if(oldParent){
6954             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6955         }
6956         return node;
6957     },
6958
6959     /**
6960      * Returns the child node at the specified index.
6961      * @param {Number} index
6962      * @return {Node}
6963      */
6964     item : function(index){
6965         return this.childNodes[index];
6966     },
6967
6968     /**
6969      * Replaces one child node in this node with another.
6970      * @param {Node} newChild The replacement node
6971      * @param {Node} oldChild The node to replace
6972      * @return {Node} The replaced node
6973      */
6974     replaceChild : function(newChild, oldChild){
6975         this.insertBefore(newChild, oldChild);
6976         this.removeChild(oldChild);
6977         return oldChild;
6978     },
6979
6980     /**
6981      * Returns the index of a child node
6982      * @param {Node} node
6983      * @return {Number} The index of the node or -1 if it was not found
6984      */
6985     indexOf : function(child){
6986         return this.childNodes.indexOf(child);
6987     },
6988
6989     /**
6990      * Returns the tree this node is in.
6991      * @return {Tree}
6992      */
6993     getOwnerTree : function(){
6994         // if it doesn't have one, look for one
6995         if(!this.ownerTree){
6996             var p = this;
6997             while(p){
6998                 if(p.ownerTree){
6999                     this.ownerTree = p.ownerTree;
7000                     break;
7001                 }
7002                 p = p.parentNode;
7003             }
7004         }
7005         return this.ownerTree;
7006     },
7007
7008     /**
7009      * Returns depth of this node (the root node has a depth of 0)
7010      * @return {Number}
7011      */
7012     getDepth : function(){
7013         var depth = 0;
7014         var p = this;
7015         while(p.parentNode){
7016             ++depth;
7017             p = p.parentNode;
7018         }
7019         return depth;
7020     },
7021
7022     // private
7023     setOwnerTree : function(tree){
7024         // if it's move, we need to update everyone
7025         if(tree != this.ownerTree){
7026             if(this.ownerTree){
7027                 this.ownerTree.unregisterNode(this);
7028             }
7029             this.ownerTree = tree;
7030             var cs = this.childNodes;
7031             for(var i = 0, len = cs.length; i < len; i++) {
7032                 cs[i].setOwnerTree(tree);
7033             }
7034             if(tree){
7035                 tree.registerNode(this);
7036             }
7037         }
7038     },
7039
7040     /**
7041      * Returns the path for this node. The path can be used to expand or select this node programmatically.
7042      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7043      * @return {String} The path
7044      */
7045     getPath : function(attr){
7046         attr = attr || "id";
7047         var p = this.parentNode;
7048         var b = [this.attributes[attr]];
7049         while(p){
7050             b.unshift(p.attributes[attr]);
7051             p = p.parentNode;
7052         }
7053         var sep = this.getOwnerTree().pathSeparator;
7054         return sep + b.join(sep);
7055     },
7056
7057     /**
7058      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7059      * function call will be the scope provided or the current node. The arguments to the function
7060      * will be the args provided or the current node. If the function returns false at any point,
7061      * the bubble is stopped.
7062      * @param {Function} fn The function to call
7063      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7064      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7065      */
7066     bubble : function(fn, scope, args){
7067         var p = this;
7068         while(p){
7069             if(fn.call(scope || p, args || p) === false){
7070                 break;
7071             }
7072             p = p.parentNode;
7073         }
7074     },
7075
7076     /**
7077      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7078      * function call will be the scope provided or the current node. The arguments to the function
7079      * will be the args provided or the current node. If the function returns false at any point,
7080      * the cascade is stopped on that branch.
7081      * @param {Function} fn The function to call
7082      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7083      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7084      */
7085     cascade : function(fn, scope, args){
7086         if(fn.call(scope || this, args || this) !== false){
7087             var cs = this.childNodes;
7088             for(var i = 0, len = cs.length; i < len; i++) {
7089                 cs[i].cascade(fn, scope, args);
7090             }
7091         }
7092     },
7093
7094     /**
7095      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7096      * function call will be the scope provided or the current node. The arguments to the function
7097      * will be the args provided or the current node. If the function returns false at any point,
7098      * the iteration stops.
7099      * @param {Function} fn The function to call
7100      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7101      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7102      */
7103     eachChild : function(fn, scope, args){
7104         var cs = this.childNodes;
7105         for(var i = 0, len = cs.length; i < len; i++) {
7106                 if(fn.call(scope || this, args || cs[i]) === false){
7107                     break;
7108                 }
7109         }
7110     },
7111
7112     /**
7113      * Finds the first child that has the attribute with the specified value.
7114      * @param {String} attribute The attribute name
7115      * @param {Mixed} value The value to search for
7116      * @return {Node} The found child or null if none was found
7117      */
7118     findChild : function(attribute, value){
7119         var cs = this.childNodes;
7120         for(var i = 0, len = cs.length; i < len; i++) {
7121                 if(cs[i].attributes[attribute] == value){
7122                     return cs[i];
7123                 }
7124         }
7125         return null;
7126     },
7127
7128     /**
7129      * Finds the first child by a custom function. The child matches if the function passed
7130      * returns true.
7131      * @param {Function} fn
7132      * @param {Object} scope (optional)
7133      * @return {Node} The found child or null if none was found
7134      */
7135     findChildBy : function(fn, scope){
7136         var cs = this.childNodes;
7137         for(var i = 0, len = cs.length; i < len; i++) {
7138                 if(fn.call(scope||cs[i], cs[i]) === true){
7139                     return cs[i];
7140                 }
7141         }
7142         return null;
7143     },
7144
7145     /**
7146      * Sorts this nodes children using the supplied sort function
7147      * @param {Function} fn
7148      * @param {Object} scope (optional)
7149      */
7150     sort : function(fn, scope){
7151         var cs = this.childNodes;
7152         var len = cs.length;
7153         if(len > 0){
7154             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7155             cs.sort(sortFn);
7156             for(var i = 0; i < len; i++){
7157                 var n = cs[i];
7158                 n.previousSibling = cs[i-1];
7159                 n.nextSibling = cs[i+1];
7160                 if(i == 0){
7161                     this.setFirstChild(n);
7162                 }
7163                 if(i == len-1){
7164                     this.setLastChild(n);
7165                 }
7166             }
7167         }
7168     },
7169
7170     /**
7171      * Returns true if this node is an ancestor (at any point) of the passed node.
7172      * @param {Node} node
7173      * @return {Boolean}
7174      */
7175     contains : function(node){
7176         return node.isAncestor(this);
7177     },
7178
7179     /**
7180      * Returns true if the passed node is an ancestor (at any point) of this node.
7181      * @param {Node} node
7182      * @return {Boolean}
7183      */
7184     isAncestor : function(node){
7185         var p = this.parentNode;
7186         while(p){
7187             if(p == node){
7188                 return true;
7189             }
7190             p = p.parentNode;
7191         }
7192         return false;
7193     },
7194
7195     toString : function(){
7196         return "[Node"+(this.id?" "+this.id:"")+"]";
7197     }
7198 });/*
7199  * Based on:
7200  * Ext JS Library 1.1.1
7201  * Copyright(c) 2006-2007, Ext JS, LLC.
7202  *
7203  * Originally Released Under LGPL - original licence link has changed is not relivant.
7204  *
7205  * Fork - LGPL
7206  * <script type="text/javascript">
7207  */
7208  
7209
7210 /**
7211  * @class Roo.ComponentMgr
7212  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7213  * @singleton
7214  */
7215 Roo.ComponentMgr = function(){
7216     var all = new Roo.util.MixedCollection();
7217
7218     return {
7219         /**
7220          * Registers a component.
7221          * @param {Roo.Component} c The component
7222          */
7223         register : function(c){
7224             all.add(c);
7225         },
7226
7227         /**
7228          * Unregisters a component.
7229          * @param {Roo.Component} c The component
7230          */
7231         unregister : function(c){
7232             all.remove(c);
7233         },
7234
7235         /**
7236          * Returns a component by id
7237          * @param {String} id The component id
7238          */
7239         get : function(id){
7240             return all.get(id);
7241         },
7242
7243         /**
7244          * Registers a function that will be called when a specified component is added to ComponentMgr
7245          * @param {String} id The component id
7246          * @param {Funtction} fn The callback function
7247          * @param {Object} scope The scope of the callback
7248          */
7249         onAvailable : function(id, fn, scope){
7250             all.on("add", function(index, o){
7251                 if(o.id == id){
7252                     fn.call(scope || o, o);
7253                     all.un("add", fn, scope);
7254                 }
7255             });
7256         }
7257     };
7258 }();/*
7259  * Based on:
7260  * Ext JS Library 1.1.1
7261  * Copyright(c) 2006-2007, Ext JS, LLC.
7262  *
7263  * Originally Released Under LGPL - original licence link has changed is not relivant.
7264  *
7265  * Fork - LGPL
7266  * <script type="text/javascript">
7267  */
7268  
7269 /**
7270  * @class Roo.Component
7271  * @extends Roo.util.Observable
7272  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
7273  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
7274  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7275  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7276  * All visual components (widgets) that require rendering into a layout should subclass Component.
7277  * @constructor
7278  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
7279  * 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
7280  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
7281  */
7282 Roo.Component = function(config){
7283     config = config || {};
7284     if(config.tagName || config.dom || typeof config == "string"){ // element object
7285         config = {el: config, id: config.id || config};
7286     }
7287     this.initialConfig = config;
7288
7289     Roo.apply(this, config);
7290     this.addEvents({
7291         /**
7292          * @event disable
7293          * Fires after the component is disabled.
7294              * @param {Roo.Component} this
7295              */
7296         disable : true,
7297         /**
7298          * @event enable
7299          * Fires after the component is enabled.
7300              * @param {Roo.Component} this
7301              */
7302         enable : true,
7303         /**
7304          * @event beforeshow
7305          * Fires before the component is shown.  Return false to stop the show.
7306              * @param {Roo.Component} this
7307              */
7308         beforeshow : true,
7309         /**
7310          * @event show
7311          * Fires after the component is shown.
7312              * @param {Roo.Component} this
7313              */
7314         show : true,
7315         /**
7316          * @event beforehide
7317          * Fires before the component is hidden. Return false to stop the hide.
7318              * @param {Roo.Component} this
7319              */
7320         beforehide : true,
7321         /**
7322          * @event hide
7323          * Fires after the component is hidden.
7324              * @param {Roo.Component} this
7325              */
7326         hide : true,
7327         /**
7328          * @event beforerender
7329          * Fires before the component is rendered. Return false to stop the render.
7330              * @param {Roo.Component} this
7331              */
7332         beforerender : true,
7333         /**
7334          * @event render
7335          * Fires after the component is rendered.
7336              * @param {Roo.Component} this
7337              */
7338         render : true,
7339         /**
7340          * @event beforedestroy
7341          * Fires before the component is destroyed. Return false to stop the destroy.
7342              * @param {Roo.Component} this
7343              */
7344         beforedestroy : true,
7345         /**
7346          * @event destroy
7347          * Fires after the component is destroyed.
7348              * @param {Roo.Component} this
7349              */
7350         destroy : true
7351     });
7352     if(!this.id){
7353         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7354     }
7355     Roo.ComponentMgr.register(this);
7356     Roo.Component.superclass.constructor.call(this);
7357     this.initComponent();
7358     if(this.renderTo){ // not supported by all components yet. use at your own risk!
7359         this.render(this.renderTo);
7360         delete this.renderTo;
7361     }
7362 };
7363
7364 // private
7365 Roo.Component.AUTO_ID = 1000;
7366
7367 Roo.extend(Roo.Component, Roo.util.Observable, {
7368     /**
7369      * @property {Boolean} hidden
7370      * true if this component is hidden. Read-only.
7371      */
7372     hidden : false,
7373     /**
7374      * true if this component is disabled. Read-only.
7375      */
7376     disabled : false,
7377     /**
7378      * true if this component has been rendered. Read-only.
7379      */
7380     rendered : false,
7381     
7382     /** @cfg {String} disableClass
7383      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7384      */
7385     disabledClass : "x-item-disabled",
7386         /** @cfg {Boolean} allowDomMove
7387          * Whether the component can move the Dom node when rendering (defaults to true).
7388          */
7389     allowDomMove : true,
7390     /** @cfg {String} hideMode
7391      * How this component should hidden. Supported values are
7392      * "visibility" (css visibility), "offsets" (negative offset position) and
7393      * "display" (css display) - defaults to "display".
7394      */
7395     hideMode: 'display',
7396
7397     // private
7398     ctype : "Roo.Component",
7399
7400     /** @cfg {String} actionMode 
7401      * which property holds the element that used for  hide() / show() / disable() / enable()
7402      * default is 'el' 
7403      */
7404     actionMode : "el",
7405
7406     // private
7407     getActionEl : function(){
7408         return this[this.actionMode];
7409     },
7410
7411     initComponent : Roo.emptyFn,
7412     /**
7413      * If this is a lazy rendering component, render it to its container element.
7414      * @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.
7415      */
7416     render : function(container, position){
7417         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7418             if(!container && this.el){
7419                 this.el = Roo.get(this.el);
7420                 container = this.el.dom.parentNode;
7421                 this.allowDomMove = false;
7422             }
7423             this.container = Roo.get(container);
7424             this.rendered = true;
7425             if(position !== undefined){
7426                 if(typeof position == 'number'){
7427                     position = this.container.dom.childNodes[position];
7428                 }else{
7429                     position = Roo.getDom(position);
7430                 }
7431             }
7432             this.onRender(this.container, position || null);
7433             if(this.cls){
7434                 this.el.addClass(this.cls);
7435                 delete this.cls;
7436             }
7437             if(this.style){
7438                 this.el.applyStyles(this.style);
7439                 delete this.style;
7440             }
7441             this.fireEvent("render", this);
7442             this.afterRender(this.container);
7443             if(this.hidden){
7444                 this.hide();
7445             }
7446             if(this.disabled){
7447                 this.disable();
7448             }
7449         }
7450         return this;
7451     },
7452
7453     // private
7454     // default function is not really useful
7455     onRender : function(ct, position){
7456         if(this.el){
7457             this.el = Roo.get(this.el);
7458             if(this.allowDomMove !== false){
7459                 ct.dom.insertBefore(this.el.dom, position);
7460             }
7461         }
7462     },
7463
7464     // private
7465     getAutoCreate : function(){
7466         var cfg = typeof this.autoCreate == "object" ?
7467                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7468         if(this.id && !cfg.id){
7469             cfg.id = this.id;
7470         }
7471         return cfg;
7472     },
7473
7474     // private
7475     afterRender : Roo.emptyFn,
7476
7477     /**
7478      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7479      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7480      */
7481     destroy : function(){
7482         if(this.fireEvent("beforedestroy", this) !== false){
7483             this.purgeListeners();
7484             this.beforeDestroy();
7485             if(this.rendered){
7486                 this.el.removeAllListeners();
7487                 this.el.remove();
7488                 if(this.actionMode == "container"){
7489                     this.container.remove();
7490                 }
7491             }
7492             this.onDestroy();
7493             Roo.ComponentMgr.unregister(this);
7494             this.fireEvent("destroy", this);
7495         }
7496     },
7497
7498         // private
7499     beforeDestroy : function(){
7500
7501     },
7502
7503         // private
7504         onDestroy : function(){
7505
7506     },
7507
7508     /**
7509      * Returns the underlying {@link Roo.Element}.
7510      * @return {Roo.Element} The element
7511      */
7512     getEl : function(){
7513         return this.el;
7514     },
7515
7516     /**
7517      * Returns the id of this component.
7518      * @return {String}
7519      */
7520     getId : function(){
7521         return this.id;
7522     },
7523
7524     /**
7525      * Try to focus this component.
7526      * @param {Boolean} selectText True to also select the text in this component (if applicable)
7527      * @return {Roo.Component} this
7528      */
7529     focus : function(selectText){
7530         if(this.rendered){
7531             this.el.focus();
7532             if(selectText === true){
7533                 this.el.dom.select();
7534             }
7535         }
7536         return this;
7537     },
7538
7539     // private
7540     blur : function(){
7541         if(this.rendered){
7542             this.el.blur();
7543         }
7544         return this;
7545     },
7546
7547     /**
7548      * Disable this component.
7549      * @return {Roo.Component} this
7550      */
7551     disable : function(){
7552         if(this.rendered){
7553             this.onDisable();
7554         }
7555         this.disabled = true;
7556         this.fireEvent("disable", this);
7557         return this;
7558     },
7559
7560         // private
7561     onDisable : function(){
7562         this.getActionEl().addClass(this.disabledClass);
7563         this.el.dom.disabled = true;
7564     },
7565
7566     /**
7567      * Enable this component.
7568      * @return {Roo.Component} this
7569      */
7570     enable : function(){
7571         if(this.rendered){
7572             this.onEnable();
7573         }
7574         this.disabled = false;
7575         this.fireEvent("enable", this);
7576         return this;
7577     },
7578
7579         // private
7580     onEnable : function(){
7581         this.getActionEl().removeClass(this.disabledClass);
7582         this.el.dom.disabled = false;
7583     },
7584
7585     /**
7586      * Convenience function for setting disabled/enabled by boolean.
7587      * @param {Boolean} disabled
7588      */
7589     setDisabled : function(disabled){
7590         this[disabled ? "disable" : "enable"]();
7591     },
7592
7593     /**
7594      * Show this component.
7595      * @return {Roo.Component} this
7596      */
7597     show: function(){
7598         if(this.fireEvent("beforeshow", this) !== false){
7599             this.hidden = false;
7600             if(this.rendered){
7601                 this.onShow();
7602             }
7603             this.fireEvent("show", this);
7604         }
7605         return this;
7606     },
7607
7608     // private
7609     onShow : function(){
7610         var ae = this.getActionEl();
7611         if(this.hideMode == 'visibility'){
7612             ae.dom.style.visibility = "visible";
7613         }else if(this.hideMode == 'offsets'){
7614             ae.removeClass('x-hidden');
7615         }else{
7616             ae.dom.style.display = "";
7617         }
7618     },
7619
7620     /**
7621      * Hide this component.
7622      * @return {Roo.Component} this
7623      */
7624     hide: function(){
7625         if(this.fireEvent("beforehide", this) !== false){
7626             this.hidden = true;
7627             if(this.rendered){
7628                 this.onHide();
7629             }
7630             this.fireEvent("hide", this);
7631         }
7632         return this;
7633     },
7634
7635     // private
7636     onHide : function(){
7637         var ae = this.getActionEl();
7638         if(this.hideMode == 'visibility'){
7639             ae.dom.style.visibility = "hidden";
7640         }else if(this.hideMode == 'offsets'){
7641             ae.addClass('x-hidden');
7642         }else{
7643             ae.dom.style.display = "none";
7644         }
7645     },
7646
7647     /**
7648      * Convenience function to hide or show this component by boolean.
7649      * @param {Boolean} visible True to show, false to hide
7650      * @return {Roo.Component} this
7651      */
7652     setVisible: function(visible){
7653         if(visible) {
7654             this.show();
7655         }else{
7656             this.hide();
7657         }
7658         return this;
7659     },
7660
7661     /**
7662      * Returns true if this component is visible.
7663      */
7664     isVisible : function(){
7665         return this.getActionEl().isVisible();
7666     },
7667
7668     cloneConfig : function(overrides){
7669         overrides = overrides || {};
7670         var id = overrides.id || Roo.id();
7671         var cfg = Roo.applyIf(overrides, this.initialConfig);
7672         cfg.id = id; // prevent dup id
7673         return new this.constructor(cfg);
7674     }
7675 });/*
7676  * Based on:
7677  * Ext JS Library 1.1.1
7678  * Copyright(c) 2006-2007, Ext JS, LLC.
7679  *
7680  * Originally Released Under LGPL - original licence link has changed is not relivant.
7681  *
7682  * Fork - LGPL
7683  * <script type="text/javascript">
7684  */
7685  (function(){ 
7686 /**
7687  * @class Roo.Layer
7688  * @extends Roo.Element
7689  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7690  * automatic maintaining of shadow/shim positions.
7691  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7692  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7693  * you can pass a string with a CSS class name. False turns off the shadow.
7694  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7695  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7696  * @cfg {String} cls CSS class to add to the element
7697  * @cfg {Number} zindex Starting z-index (defaults to 11000)
7698  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7699  * @constructor
7700  * @param {Object} config An object with config options.
7701  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7702  */
7703
7704 Roo.Layer = function(config, existingEl){
7705     config = config || {};
7706     var dh = Roo.DomHelper;
7707     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7708     if(existingEl){
7709         this.dom = Roo.getDom(existingEl);
7710     }
7711     if(!this.dom){
7712         var o = config.dh || {tag: "div", cls: "x-layer"};
7713         this.dom = dh.append(pel, o);
7714     }
7715     if(config.cls){
7716         this.addClass(config.cls);
7717     }
7718     this.constrain = config.constrain !== false;
7719     this.visibilityMode = Roo.Element.VISIBILITY;
7720     if(config.id){
7721         this.id = this.dom.id = config.id;
7722     }else{
7723         this.id = Roo.id(this.dom);
7724     }
7725     this.zindex = config.zindex || this.getZIndex();
7726     this.position("absolute", this.zindex);
7727     if(config.shadow){
7728         this.shadowOffset = config.shadowOffset || 4;
7729         this.shadow = new Roo.Shadow({
7730             offset : this.shadowOffset,
7731             mode : config.shadow
7732         });
7733     }else{
7734         this.shadowOffset = 0;
7735     }
7736     this.useShim = config.shim !== false && Roo.useShims;
7737     this.useDisplay = config.useDisplay;
7738     this.hide();
7739 };
7740
7741 var supr = Roo.Element.prototype;
7742
7743 // shims are shared among layer to keep from having 100 iframes
7744 var shims = [];
7745
7746 Roo.extend(Roo.Layer, Roo.Element, {
7747
7748     getZIndex : function(){
7749         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7750     },
7751
7752     getShim : function(){
7753         if(!this.useShim){
7754             return null;
7755         }
7756         if(this.shim){
7757             return this.shim;
7758         }
7759         var shim = shims.shift();
7760         if(!shim){
7761             shim = this.createShim();
7762             shim.enableDisplayMode('block');
7763             shim.dom.style.display = 'none';
7764             shim.dom.style.visibility = 'visible';
7765         }
7766         var pn = this.dom.parentNode;
7767         if(shim.dom.parentNode != pn){
7768             pn.insertBefore(shim.dom, this.dom);
7769         }
7770         shim.setStyle('z-index', this.getZIndex()-2);
7771         this.shim = shim;
7772         return shim;
7773     },
7774
7775     hideShim : function(){
7776         if(this.shim){
7777             this.shim.setDisplayed(false);
7778             shims.push(this.shim);
7779             delete this.shim;
7780         }
7781     },
7782
7783     disableShadow : function(){
7784         if(this.shadow){
7785             this.shadowDisabled = true;
7786             this.shadow.hide();
7787             this.lastShadowOffset = this.shadowOffset;
7788             this.shadowOffset = 0;
7789         }
7790     },
7791
7792     enableShadow : function(show){
7793         if(this.shadow){
7794             this.shadowDisabled = false;
7795             this.shadowOffset = this.lastShadowOffset;
7796             delete this.lastShadowOffset;
7797             if(show){
7798                 this.sync(true);
7799             }
7800         }
7801     },
7802
7803     // private
7804     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7805     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7806     sync : function(doShow){
7807         var sw = this.shadow;
7808         if(!this.updating && this.isVisible() && (sw || this.useShim)){
7809             var sh = this.getShim();
7810
7811             var w = this.getWidth(),
7812                 h = this.getHeight();
7813
7814             var l = this.getLeft(true),
7815                 t = this.getTop(true);
7816
7817             if(sw && !this.shadowDisabled){
7818                 if(doShow && !sw.isVisible()){
7819                     sw.show(this);
7820                 }else{
7821                     sw.realign(l, t, w, h);
7822                 }
7823                 if(sh){
7824                     if(doShow){
7825                        sh.show();
7826                     }
7827                     // fit the shim behind the shadow, so it is shimmed too
7828                     var a = sw.adjusts, s = sh.dom.style;
7829                     s.left = (Math.min(l, l+a.l))+"px";
7830                     s.top = (Math.min(t, t+a.t))+"px";
7831                     s.width = (w+a.w)+"px";
7832                     s.height = (h+a.h)+"px";
7833                 }
7834             }else if(sh){
7835                 if(doShow){
7836                    sh.show();
7837                 }
7838                 sh.setSize(w, h);
7839                 sh.setLeftTop(l, t);
7840             }
7841             
7842         }
7843     },
7844
7845     // private
7846     destroy : function(){
7847         this.hideShim();
7848         if(this.shadow){
7849             this.shadow.hide();
7850         }
7851         this.removeAllListeners();
7852         var pn = this.dom.parentNode;
7853         if(pn){
7854             pn.removeChild(this.dom);
7855         }
7856         Roo.Element.uncache(this.id);
7857     },
7858
7859     remove : function(){
7860         this.destroy();
7861     },
7862
7863     // private
7864     beginUpdate : function(){
7865         this.updating = true;
7866     },
7867
7868     // private
7869     endUpdate : function(){
7870         this.updating = false;
7871         this.sync(true);
7872     },
7873
7874     // private
7875     hideUnders : function(negOffset){
7876         if(this.shadow){
7877             this.shadow.hide();
7878         }
7879         this.hideShim();
7880     },
7881
7882     // private
7883     constrainXY : function(){
7884         if(this.constrain){
7885             var vw = Roo.lib.Dom.getViewWidth(),
7886                 vh = Roo.lib.Dom.getViewHeight();
7887             var s = Roo.get(document).getScroll();
7888
7889             var xy = this.getXY();
7890             var x = xy[0], y = xy[1];   
7891             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7892             // only move it if it needs it
7893             var moved = false;
7894             // first validate right/bottom
7895             if((x + w) > vw+s.left){
7896                 x = vw - w - this.shadowOffset;
7897                 moved = true;
7898             }
7899             if((y + h) > vh+s.top){
7900                 y = vh - h - this.shadowOffset;
7901                 moved = true;
7902             }
7903             // then make sure top/left isn't negative
7904             if(x < s.left){
7905                 x = s.left;
7906                 moved = true;
7907             }
7908             if(y < s.top){
7909                 y = s.top;
7910                 moved = true;
7911             }
7912             if(moved){
7913                 if(this.avoidY){
7914                     var ay = this.avoidY;
7915                     if(y <= ay && (y+h) >= ay){
7916                         y = ay-h-5;   
7917                     }
7918                 }
7919                 xy = [x, y];
7920                 this.storeXY(xy);
7921                 supr.setXY.call(this, xy);
7922                 this.sync();
7923             }
7924         }
7925     },
7926
7927     isVisible : function(){
7928         return this.visible;    
7929     },
7930
7931     // private
7932     showAction : function(){
7933         this.visible = true; // track visibility to prevent getStyle calls
7934         if(this.useDisplay === true){
7935             this.setDisplayed("");
7936         }else if(this.lastXY){
7937             supr.setXY.call(this, this.lastXY);
7938         }else if(this.lastLT){
7939             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7940         }
7941     },
7942
7943     // private
7944     hideAction : function(){
7945         this.visible = false;
7946         if(this.useDisplay === true){
7947             this.setDisplayed(false);
7948         }else{
7949             this.setLeftTop(-10000,-10000);
7950         }
7951     },
7952
7953     // overridden Element method
7954     setVisible : function(v, a, d, c, e){
7955         if(v){
7956             this.showAction();
7957         }
7958         if(a && v){
7959             var cb = function(){
7960                 this.sync(true);
7961                 if(c){
7962                     c();
7963                 }
7964             }.createDelegate(this);
7965             supr.setVisible.call(this, true, true, d, cb, e);
7966         }else{
7967             if(!v){
7968                 this.hideUnders(true);
7969             }
7970             var cb = c;
7971             if(a){
7972                 cb = function(){
7973                     this.hideAction();
7974                     if(c){
7975                         c();
7976                     }
7977                 }.createDelegate(this);
7978             }
7979             supr.setVisible.call(this, v, a, d, cb, e);
7980             if(v){
7981                 this.sync(true);
7982             }else if(!a){
7983                 this.hideAction();
7984             }
7985         }
7986     },
7987
7988     storeXY : function(xy){
7989         delete this.lastLT;
7990         this.lastXY = xy;
7991     },
7992
7993     storeLeftTop : function(left, top){
7994         delete this.lastXY;
7995         this.lastLT = [left, top];
7996     },
7997
7998     // private
7999     beforeFx : function(){
8000         this.beforeAction();
8001         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8002     },
8003
8004     // private
8005     afterFx : function(){
8006         Roo.Layer.superclass.afterFx.apply(this, arguments);
8007         this.sync(this.isVisible());
8008     },
8009
8010     // private
8011     beforeAction : function(){
8012         if(!this.updating && this.shadow){
8013             this.shadow.hide();
8014         }
8015     },
8016
8017     // overridden Element method
8018     setLeft : function(left){
8019         this.storeLeftTop(left, this.getTop(true));
8020         supr.setLeft.apply(this, arguments);
8021         this.sync();
8022     },
8023
8024     setTop : function(top){
8025         this.storeLeftTop(this.getLeft(true), top);
8026         supr.setTop.apply(this, arguments);
8027         this.sync();
8028     },
8029
8030     setLeftTop : function(left, top){
8031         this.storeLeftTop(left, top);
8032         supr.setLeftTop.apply(this, arguments);
8033         this.sync();
8034     },
8035
8036     setXY : function(xy, a, d, c, e){
8037         this.fixDisplay();
8038         this.beforeAction();
8039         this.storeXY(xy);
8040         var cb = this.createCB(c);
8041         supr.setXY.call(this, xy, a, d, cb, e);
8042         if(!a){
8043             cb();
8044         }
8045     },
8046
8047     // private
8048     createCB : function(c){
8049         var el = this;
8050         return function(){
8051             el.constrainXY();
8052             el.sync(true);
8053             if(c){
8054                 c();
8055             }
8056         };
8057     },
8058
8059     // overridden Element method
8060     setX : function(x, a, d, c, e){
8061         this.setXY([x, this.getY()], a, d, c, e);
8062     },
8063
8064     // overridden Element method
8065     setY : function(y, a, d, c, e){
8066         this.setXY([this.getX(), y], a, d, c, e);
8067     },
8068
8069     // overridden Element method
8070     setSize : function(w, h, a, d, c, e){
8071         this.beforeAction();
8072         var cb = this.createCB(c);
8073         supr.setSize.call(this, w, h, a, d, cb, e);
8074         if(!a){
8075             cb();
8076         }
8077     },
8078
8079     // overridden Element method
8080     setWidth : function(w, a, d, c, e){
8081         this.beforeAction();
8082         var cb = this.createCB(c);
8083         supr.setWidth.call(this, w, a, d, cb, e);
8084         if(!a){
8085             cb();
8086         }
8087     },
8088
8089     // overridden Element method
8090     setHeight : function(h, a, d, c, e){
8091         this.beforeAction();
8092         var cb = this.createCB(c);
8093         supr.setHeight.call(this, h, a, d, cb, e);
8094         if(!a){
8095             cb();
8096         }
8097     },
8098
8099     // overridden Element method
8100     setBounds : function(x, y, w, h, a, d, c, e){
8101         this.beforeAction();
8102         var cb = this.createCB(c);
8103         if(!a){
8104             this.storeXY([x, y]);
8105             supr.setXY.call(this, [x, y]);
8106             supr.setSize.call(this, w, h, a, d, cb, e);
8107             cb();
8108         }else{
8109             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8110         }
8111         return this;
8112     },
8113     
8114     /**
8115      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8116      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8117      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8118      * @param {Number} zindex The new z-index to set
8119      * @return {this} The Layer
8120      */
8121     setZIndex : function(zindex){
8122         this.zindex = zindex;
8123         this.setStyle("z-index", zindex + 2);
8124         if(this.shadow){
8125             this.shadow.setZIndex(zindex + 1);
8126         }
8127         if(this.shim){
8128             this.shim.setStyle("z-index", zindex);
8129         }
8130     }
8131 });
8132 })();/*
8133  * Based on:
8134  * Ext JS Library 1.1.1
8135  * Copyright(c) 2006-2007, Ext JS, LLC.
8136  *
8137  * Originally Released Under LGPL - original licence link has changed is not relivant.
8138  *
8139  * Fork - LGPL
8140  * <script type="text/javascript">
8141  */
8142
8143
8144 /**
8145  * @class Roo.Shadow
8146  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
8147  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
8148  * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8149  * @constructor
8150  * Create a new Shadow
8151  * @param {Object} config The config object
8152  */
8153 Roo.Shadow = function(config){
8154     Roo.apply(this, config);
8155     if(typeof this.mode != "string"){
8156         this.mode = this.defaultMode;
8157     }
8158     var o = this.offset, a = {h: 0};
8159     var rad = Math.floor(this.offset/2);
8160     switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8161         case "drop":
8162             a.w = 0;
8163             a.l = a.t = o;
8164             a.t -= 1;
8165             if(Roo.isIE){
8166                 a.l -= this.offset + rad;
8167                 a.t -= this.offset + rad;
8168                 a.w -= rad;
8169                 a.h -= rad;
8170                 a.t += 1;
8171             }
8172         break;
8173         case "sides":
8174             a.w = (o*2);
8175             a.l = -o;
8176             a.t = o-1;
8177             if(Roo.isIE){
8178                 a.l -= (this.offset - rad);
8179                 a.t -= this.offset + rad;
8180                 a.l += 1;
8181                 a.w -= (this.offset - rad)*2;
8182                 a.w -= rad + 1;
8183                 a.h -= 1;
8184             }
8185         break;
8186         case "frame":
8187             a.w = a.h = (o*2);
8188             a.l = a.t = -o;
8189             a.t += 1;
8190             a.h -= 2;
8191             if(Roo.isIE){
8192                 a.l -= (this.offset - rad);
8193                 a.t -= (this.offset - rad);
8194                 a.l += 1;
8195                 a.w -= (this.offset + rad + 1);
8196                 a.h -= (this.offset + rad);
8197                 a.h += 1;
8198             }
8199         break;
8200     };
8201
8202     this.adjusts = a;
8203 };
8204
8205 Roo.Shadow.prototype = {
8206     /**
8207      * @cfg {String} mode
8208      * The shadow display mode.  Supports the following options:<br />
8209      * sides: Shadow displays on both sides and bottom only<br />
8210      * frame: Shadow displays equally on all four sides<br />
8211      * drop: Traditional bottom-right drop shadow (default)
8212      */
8213     /**
8214      * @cfg {String} offset
8215      * The number of pixels to offset the shadow from the element (defaults to 4)
8216      */
8217     offset: 4,
8218
8219     // private
8220     defaultMode: "drop",
8221
8222     /**
8223      * Displays the shadow under the target element
8224      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8225      */
8226     show : function(target){
8227         target = Roo.get(target);
8228         if(!this.el){
8229             this.el = Roo.Shadow.Pool.pull();
8230             if(this.el.dom.nextSibling != target.dom){
8231                 this.el.insertBefore(target);
8232             }
8233         }
8234         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8235         if(Roo.isIE){
8236             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8237         }
8238         this.realign(
8239             target.getLeft(true),
8240             target.getTop(true),
8241             target.getWidth(),
8242             target.getHeight()
8243         );
8244         this.el.dom.style.display = "block";
8245     },
8246
8247     /**
8248      * Returns true if the shadow is visible, else false
8249      */
8250     isVisible : function(){
8251         return this.el ? true : false;  
8252     },
8253
8254     /**
8255      * Direct alignment when values are already available. Show must be called at least once before
8256      * calling this method to ensure it is initialized.
8257      * @param {Number} left The target element left position
8258      * @param {Number} top The target element top position
8259      * @param {Number} width The target element width
8260      * @param {Number} height The target element height
8261      */
8262     realign : function(l, t, w, h){
8263         if(!this.el){
8264             return;
8265         }
8266         var a = this.adjusts, d = this.el.dom, s = d.style;
8267         var iea = 0;
8268         s.left = (l+a.l)+"px";
8269         s.top = (t+a.t)+"px";
8270         var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8271  
8272         if(s.width != sws || s.height != shs){
8273             s.width = sws;
8274             s.height = shs;
8275             if(!Roo.isIE){
8276                 var cn = d.childNodes;
8277                 var sww = Math.max(0, (sw-12))+"px";
8278                 cn[0].childNodes[1].style.width = sww;
8279                 cn[1].childNodes[1].style.width = sww;
8280                 cn[2].childNodes[1].style.width = sww;
8281                 cn[1].style.height = Math.max(0, (sh-12))+"px";
8282             }
8283         }
8284     },
8285
8286     /**
8287      * Hides this shadow
8288      */
8289     hide : function(){
8290         if(this.el){
8291             this.el.dom.style.display = "none";
8292             Roo.Shadow.Pool.push(this.el);
8293             delete this.el;
8294         }
8295     },
8296
8297     /**
8298      * Adjust the z-index of this shadow
8299      * @param {Number} zindex The new z-index
8300      */
8301     setZIndex : function(z){
8302         this.zIndex = z;
8303         if(this.el){
8304             this.el.setStyle("z-index", z);
8305         }
8306     }
8307 };
8308
8309 // Private utility class that manages the internal Shadow cache
8310 Roo.Shadow.Pool = function(){
8311     var p = [];
8312     var markup = Roo.isIE ?
8313                  '<div class="x-ie-shadow"></div>' :
8314                  '<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>';
8315     return {
8316         pull : function(){
8317             var sh = p.shift();
8318             if(!sh){
8319                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8320                 sh.autoBoxAdjust = false;
8321             }
8322             return sh;
8323         },
8324
8325         push : function(sh){
8326             p.push(sh);
8327         }
8328     };
8329 }();/*
8330  * Based on:
8331  * Ext JS Library 1.1.1
8332  * Copyright(c) 2006-2007, Ext JS, LLC.
8333  *
8334  * Originally Released Under LGPL - original licence link has changed is not relivant.
8335  *
8336  * Fork - LGPL
8337  * <script type="text/javascript">
8338  */
8339
8340 /**
8341  * @class Roo.BoxComponent
8342  * @extends Roo.Component
8343  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
8344  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
8345  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8346  * layout containers.
8347  * @constructor
8348  * @param {Roo.Element/String/Object} config The configuration options.
8349  */
8350 Roo.BoxComponent = function(config){
8351     Roo.Component.call(this, config);
8352     this.addEvents({
8353         /**
8354          * @event resize
8355          * Fires after the component is resized.
8356              * @param {Roo.Component} this
8357              * @param {Number} adjWidth The box-adjusted width that was set
8358              * @param {Number} adjHeight The box-adjusted height that was set
8359              * @param {Number} rawWidth The width that was originally specified
8360              * @param {Number} rawHeight The height that was originally specified
8361              */
8362         resize : true,
8363         /**
8364          * @event move
8365          * Fires after the component is moved.
8366              * @param {Roo.Component} this
8367              * @param {Number} x The new x position
8368              * @param {Number} y The new y position
8369              */
8370         move : true
8371     });
8372 };
8373
8374 Roo.extend(Roo.BoxComponent, Roo.Component, {
8375     // private, set in afterRender to signify that the component has been rendered
8376     boxReady : false,
8377     // private, used to defer height settings to subclasses
8378     deferHeight: false,
8379     /** @cfg {Number} width
8380      * width (optional) size of component
8381      */
8382      /** @cfg {Number} height
8383      * height (optional) size of component
8384      */
8385      
8386     /**
8387      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
8388      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8389      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8390      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8391      * @return {Roo.BoxComponent} this
8392      */
8393     setSize : function(w, h){
8394         // support for standard size objects
8395         if(typeof w == 'object'){
8396             h = w.height;
8397             w = w.width;
8398         }
8399         // not rendered
8400         if(!this.boxReady){
8401             this.width = w;
8402             this.height = h;
8403             return this;
8404         }
8405
8406         // prevent recalcs when not needed
8407         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8408             return this;
8409         }
8410         this.lastSize = {width: w, height: h};
8411
8412         var adj = this.adjustSize(w, h);
8413         var aw = adj.width, ah = adj.height;
8414         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8415             var rz = this.getResizeEl();
8416             if(!this.deferHeight && aw !== undefined && ah !== undefined){
8417                 rz.setSize(aw, ah);
8418             }else if(!this.deferHeight && ah !== undefined){
8419                 rz.setHeight(ah);
8420             }else if(aw !== undefined){
8421                 rz.setWidth(aw);
8422             }
8423             this.onResize(aw, ah, w, h);
8424             this.fireEvent('resize', this, aw, ah, w, h);
8425         }
8426         return this;
8427     },
8428
8429     /**
8430      * Gets the current size of the component's underlying element.
8431      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8432      */
8433     getSize : function(){
8434         return this.el.getSize();
8435     },
8436
8437     /**
8438      * Gets the current XY position of the component's underlying element.
8439      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8440      * @return {Array} The XY position of the element (e.g., [100, 200])
8441      */
8442     getPosition : function(local){
8443         if(local === true){
8444             return [this.el.getLeft(true), this.el.getTop(true)];
8445         }
8446         return this.xy || this.el.getXY();
8447     },
8448
8449     /**
8450      * Gets the current box measurements of the component's underlying element.
8451      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8452      * @returns {Object} box An object in the format {x, y, width, height}
8453      */
8454     getBox : function(local){
8455         var s = this.el.getSize();
8456         if(local){
8457             s.x = this.el.getLeft(true);
8458             s.y = this.el.getTop(true);
8459         }else{
8460             var xy = this.xy || this.el.getXY();
8461             s.x = xy[0];
8462             s.y = xy[1];
8463         }
8464         return s;
8465     },
8466
8467     /**
8468      * Sets the current box measurements of the component's underlying element.
8469      * @param {Object} box An object in the format {x, y, width, height}
8470      * @returns {Roo.BoxComponent} this
8471      */
8472     updateBox : function(box){
8473         this.setSize(box.width, box.height);
8474         this.setPagePosition(box.x, box.y);
8475         return this;
8476     },
8477
8478     // protected
8479     getResizeEl : function(){
8480         return this.resizeEl || this.el;
8481     },
8482
8483     // protected
8484     getPositionEl : function(){
8485         return this.positionEl || this.el;
8486     },
8487
8488     /**
8489      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
8490      * This method fires the move event.
8491      * @param {Number} left The new left
8492      * @param {Number} top The new top
8493      * @returns {Roo.BoxComponent} this
8494      */
8495     setPosition : function(x, y){
8496         this.x = x;
8497         this.y = y;
8498         if(!this.boxReady){
8499             return this;
8500         }
8501         var adj = this.adjustPosition(x, y);
8502         var ax = adj.x, ay = adj.y;
8503
8504         var el = this.getPositionEl();
8505         if(ax !== undefined || ay !== undefined){
8506             if(ax !== undefined && ay !== undefined){
8507                 el.setLeftTop(ax, ay);
8508             }else if(ax !== undefined){
8509                 el.setLeft(ax);
8510             }else if(ay !== undefined){
8511                 el.setTop(ay);
8512             }
8513             this.onPosition(ax, ay);
8514             this.fireEvent('move', this, ax, ay);
8515         }
8516         return this;
8517     },
8518
8519     /**
8520      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
8521      * This method fires the move event.
8522      * @param {Number} x The new x position
8523      * @param {Number} y The new y position
8524      * @returns {Roo.BoxComponent} this
8525      */
8526     setPagePosition : function(x, y){
8527         this.pageX = x;
8528         this.pageY = y;
8529         if(!this.boxReady){
8530             return;
8531         }
8532         if(x === undefined || y === undefined){ // cannot translate undefined points
8533             return;
8534         }
8535         var p = this.el.translatePoints(x, y);
8536         this.setPosition(p.left, p.top);
8537         return this;
8538     },
8539
8540     // private
8541     onRender : function(ct, position){
8542         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8543         if(this.resizeEl){
8544             this.resizeEl = Roo.get(this.resizeEl);
8545         }
8546         if(this.positionEl){
8547             this.positionEl = Roo.get(this.positionEl);
8548         }
8549     },
8550
8551     // private
8552     afterRender : function(){
8553         Roo.BoxComponent.superclass.afterRender.call(this);
8554         this.boxReady = true;
8555         this.setSize(this.width, this.height);
8556         if(this.x || this.y){
8557             this.setPosition(this.x, this.y);
8558         }
8559         if(this.pageX || this.pageY){
8560             this.setPagePosition(this.pageX, this.pageY);
8561         }
8562     },
8563
8564     /**
8565      * Force the component's size to recalculate based on the underlying element's current height and width.
8566      * @returns {Roo.BoxComponent} this
8567      */
8568     syncSize : function(){
8569         delete this.lastSize;
8570         this.setSize(this.el.getWidth(), this.el.getHeight());
8571         return this;
8572     },
8573
8574     /**
8575      * Called after the component is resized, this method is empty by default but can be implemented by any
8576      * subclass that needs to perform custom logic after a resize occurs.
8577      * @param {Number} adjWidth The box-adjusted width that was set
8578      * @param {Number} adjHeight The box-adjusted height that was set
8579      * @param {Number} rawWidth The width that was originally specified
8580      * @param {Number} rawHeight The height that was originally specified
8581      */
8582     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8583
8584     },
8585
8586     /**
8587      * Called after the component is moved, this method is empty by default but can be implemented by any
8588      * subclass that needs to perform custom logic after a move occurs.
8589      * @param {Number} x The new x position
8590      * @param {Number} y The new y position
8591      */
8592     onPosition : function(x, y){
8593
8594     },
8595
8596     // private
8597     adjustSize : function(w, h){
8598         if(this.autoWidth){
8599             w = 'auto';
8600         }
8601         if(this.autoHeight){
8602             h = 'auto';
8603         }
8604         return {width : w, height: h};
8605     },
8606
8607     // private
8608     adjustPosition : function(x, y){
8609         return {x : x, y: y};
8610     }
8611 });/*
8612  * Based on:
8613  * Ext JS Library 1.1.1
8614  * Copyright(c) 2006-2007, Ext JS, LLC.
8615  *
8616  * Originally Released Under LGPL - original licence link has changed is not relivant.
8617  *
8618  * Fork - LGPL
8619  * <script type="text/javascript">
8620  */
8621
8622
8623 /**
8624  * @class Roo.SplitBar
8625  * @extends Roo.util.Observable
8626  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8627  * <br><br>
8628  * Usage:
8629  * <pre><code>
8630 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8631                    Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8632 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8633 split.minSize = 100;
8634 split.maxSize = 600;
8635 split.animate = true;
8636 split.on('moved', splitterMoved);
8637 </code></pre>
8638  * @constructor
8639  * Create a new SplitBar
8640  * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
8641  * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
8642  * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8643  * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
8644                         Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8645                         position of the SplitBar).
8646  */
8647 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8648     
8649     /** @private */
8650     this.el = Roo.get(dragElement, true);
8651     this.el.dom.unselectable = "on";
8652     /** @private */
8653     this.resizingEl = Roo.get(resizingElement, true);
8654
8655     /**
8656      * @private
8657      * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8658      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8659      * @type Number
8660      */
8661     this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8662     
8663     /**
8664      * The minimum size of the resizing element. (Defaults to 0)
8665      * @type Number
8666      */
8667     this.minSize = 0;
8668     
8669     /**
8670      * The maximum size of the resizing element. (Defaults to 2000)
8671      * @type Number
8672      */
8673     this.maxSize = 2000;
8674     
8675     /**
8676      * Whether to animate the transition to the new size
8677      * @type Boolean
8678      */
8679     this.animate = false;
8680     
8681     /**
8682      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8683      * @type Boolean
8684      */
8685     this.useShim = false;
8686     
8687     /** @private */
8688     this.shim = null;
8689     
8690     if(!existingProxy){
8691         /** @private */
8692         this.proxy = Roo.SplitBar.createProxy(this.orientation);
8693     }else{
8694         this.proxy = Roo.get(existingProxy).dom;
8695     }
8696     /** @private */
8697     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8698     
8699     /** @private */
8700     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8701     
8702     /** @private */
8703     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8704     
8705     /** @private */
8706     this.dragSpecs = {};
8707     
8708     /**
8709      * @private The adapter to use to positon and resize elements
8710      */
8711     this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8712     this.adapter.init(this);
8713     
8714     if(this.orientation == Roo.SplitBar.HORIZONTAL){
8715         /** @private */
8716         this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8717         this.el.addClass("x-splitbar-h");
8718     }else{
8719         /** @private */
8720         this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8721         this.el.addClass("x-splitbar-v");
8722     }
8723     
8724     this.addEvents({
8725         /**
8726          * @event resize
8727          * Fires when the splitter is moved (alias for {@link #event-moved})
8728          * @param {Roo.SplitBar} this
8729          * @param {Number} newSize the new width or height
8730          */
8731         "resize" : true,
8732         /**
8733          * @event moved
8734          * Fires when the splitter is moved
8735          * @param {Roo.SplitBar} this
8736          * @param {Number} newSize the new width or height
8737          */
8738         "moved" : true,
8739         /**
8740          * @event beforeresize
8741          * Fires before the splitter is dragged
8742          * @param {Roo.SplitBar} this
8743          */
8744         "beforeresize" : true,
8745
8746         "beforeapply" : true
8747     });
8748
8749     Roo.util.Observable.call(this);
8750 };
8751
8752 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8753     onStartProxyDrag : function(x, y){
8754         this.fireEvent("beforeresize", this);
8755         if(!this.overlay){
8756             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
8757             o.unselectable();
8758             o.enableDisplayMode("block");
8759             // all splitbars share the same overlay
8760             Roo.SplitBar.prototype.overlay = o;
8761         }
8762         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8763         this.overlay.show();
8764         Roo.get(this.proxy).setDisplayed("block");
8765         var size = this.adapter.getElementSize(this);
8766         this.activeMinSize = this.getMinimumSize();;
8767         this.activeMaxSize = this.getMaximumSize();;
8768         var c1 = size - this.activeMinSize;
8769         var c2 = Math.max(this.activeMaxSize - size, 0);
8770         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8771             this.dd.resetConstraints();
8772             this.dd.setXConstraint(
8773                 this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
8774                 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8775             );
8776             this.dd.setYConstraint(0, 0);
8777         }else{
8778             this.dd.resetConstraints();
8779             this.dd.setXConstraint(0, 0);
8780             this.dd.setYConstraint(
8781                 this.placement == Roo.SplitBar.TOP ? c1 : c2, 
8782                 this.placement == Roo.SplitBar.TOP ? c2 : c1
8783             );
8784          }
8785         this.dragSpecs.startSize = size;
8786         this.dragSpecs.startPoint = [x, y];
8787         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8788     },
8789     
8790     /** 
8791      * @private Called after the drag operation by the DDProxy
8792      */
8793     onEndProxyDrag : function(e){
8794         Roo.get(this.proxy).setDisplayed(false);
8795         var endPoint = Roo.lib.Event.getXY(e);
8796         if(this.overlay){
8797             this.overlay.hide();
8798         }
8799         var newSize;
8800         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8801             newSize = this.dragSpecs.startSize + 
8802                 (this.placement == Roo.SplitBar.LEFT ?
8803                     endPoint[0] - this.dragSpecs.startPoint[0] :
8804                     this.dragSpecs.startPoint[0] - endPoint[0]
8805                 );
8806         }else{
8807             newSize = this.dragSpecs.startSize + 
8808                 (this.placement == Roo.SplitBar.TOP ?
8809                     endPoint[1] - this.dragSpecs.startPoint[1] :
8810                     this.dragSpecs.startPoint[1] - endPoint[1]
8811                 );
8812         }
8813         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8814         if(newSize != this.dragSpecs.startSize){
8815             if(this.fireEvent('beforeapply', this, newSize) !== false){
8816                 this.adapter.setElementSize(this, newSize);
8817                 this.fireEvent("moved", this, newSize);
8818                 this.fireEvent("resize", this, newSize);
8819             }
8820         }
8821     },
8822     
8823     /**
8824      * Get the adapter this SplitBar uses
8825      * @return The adapter object
8826      */
8827     getAdapter : function(){
8828         return this.adapter;
8829     },
8830     
8831     /**
8832      * Set the adapter this SplitBar uses
8833      * @param {Object} adapter A SplitBar adapter object
8834      */
8835     setAdapter : function(adapter){
8836         this.adapter = adapter;
8837         this.adapter.init(this);
8838     },
8839     
8840     /**
8841      * Gets the minimum size for the resizing element
8842      * @return {Number} The minimum size
8843      */
8844     getMinimumSize : function(){
8845         return this.minSize;
8846     },
8847     
8848     /**
8849      * Sets the minimum size for the resizing element
8850      * @param {Number} minSize The minimum size
8851      */
8852     setMinimumSize : function(minSize){
8853         this.minSize = minSize;
8854     },
8855     
8856     /**
8857      * Gets the maximum size for the resizing element
8858      * @return {Number} The maximum size
8859      */
8860     getMaximumSize : function(){
8861         return this.maxSize;
8862     },
8863     
8864     /**
8865      * Sets the maximum size for the resizing element
8866      * @param {Number} maxSize The maximum size
8867      */
8868     setMaximumSize : function(maxSize){
8869         this.maxSize = maxSize;
8870     },
8871     
8872     /**
8873      * Sets the initialize size for the resizing element
8874      * @param {Number} size The initial size
8875      */
8876     setCurrentSize : function(size){
8877         var oldAnimate = this.animate;
8878         this.animate = false;
8879         this.adapter.setElementSize(this, size);
8880         this.animate = oldAnimate;
8881     },
8882     
8883     /**
8884      * Destroy this splitbar. 
8885      * @param {Boolean} removeEl True to remove the element
8886      */
8887     destroy : function(removeEl){
8888         if(this.shim){
8889             this.shim.remove();
8890         }
8891         this.dd.unreg();
8892         this.proxy.parentNode.removeChild(this.proxy);
8893         if(removeEl){
8894             this.el.remove();
8895         }
8896     }
8897 });
8898
8899 /**
8900  * @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.
8901  */
8902 Roo.SplitBar.createProxy = function(dir){
8903     var proxy = new Roo.Element(document.createElement("div"));
8904     proxy.unselectable();
8905     var cls = 'x-splitbar-proxy';
8906     proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8907     document.body.appendChild(proxy.dom);
8908     return proxy.dom;
8909 };
8910
8911 /** 
8912  * @class Roo.SplitBar.BasicLayoutAdapter
8913  * Default Adapter. It assumes the splitter and resizing element are not positioned
8914  * elements and only gets/sets the width of the element. Generally used for table based layouts.
8915  */
8916 Roo.SplitBar.BasicLayoutAdapter = function(){
8917 };
8918
8919 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8920     // do nothing for now
8921     init : function(s){
8922     
8923     },
8924     /**
8925      * Called before drag operations to get the current size of the resizing element. 
8926      * @param {Roo.SplitBar} s The SplitBar using this adapter
8927      */
8928      getElementSize : function(s){
8929         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8930             return s.resizingEl.getWidth();
8931         }else{
8932             return s.resizingEl.getHeight();
8933         }
8934     },
8935     
8936     /**
8937      * Called after drag operations to set the size of the resizing element.
8938      * @param {Roo.SplitBar} s The SplitBar using this adapter
8939      * @param {Number} newSize The new size to set
8940      * @param {Function} onComplete A function to be invoked when resizing is complete
8941      */
8942     setElementSize : function(s, newSize, onComplete){
8943         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8944             if(!s.animate){
8945                 s.resizingEl.setWidth(newSize);
8946                 if(onComplete){
8947                     onComplete(s, newSize);
8948                 }
8949             }else{
8950                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8951             }
8952         }else{
8953             
8954             if(!s.animate){
8955                 s.resizingEl.setHeight(newSize);
8956                 if(onComplete){
8957                     onComplete(s, newSize);
8958                 }
8959             }else{
8960                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8961             }
8962         }
8963     }
8964 };
8965
8966 /** 
8967  *@class Roo.SplitBar.AbsoluteLayoutAdapter
8968  * @extends Roo.SplitBar.BasicLayoutAdapter
8969  * Adapter that  moves the splitter element to align with the resized sizing element. 
8970  * Used with an absolute positioned SplitBar.
8971  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8972  * document.body, make sure you assign an id to the body element.
8973  */
8974 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8975     this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8976     this.container = Roo.get(container);
8977 };
8978
8979 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8980     init : function(s){
8981         this.basic.init(s);
8982     },
8983     
8984     getElementSize : function(s){
8985         return this.basic.getElementSize(s);
8986     },
8987     
8988     setElementSize : function(s, newSize, onComplete){
8989         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8990     },
8991     
8992     moveSplitter : function(s){
8993         var yes = Roo.SplitBar;
8994         switch(s.placement){
8995             case yes.LEFT:
8996                 s.el.setX(s.resizingEl.getRight());
8997                 break;
8998             case yes.RIGHT:
8999                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9000                 break;
9001             case yes.TOP:
9002                 s.el.setY(s.resizingEl.getBottom());
9003                 break;
9004             case yes.BOTTOM:
9005                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9006                 break;
9007         }
9008     }
9009 };
9010
9011 /**
9012  * Orientation constant - Create a vertical SplitBar
9013  * @static
9014  * @type Number
9015  */
9016 Roo.SplitBar.VERTICAL = 1;
9017
9018 /**
9019  * Orientation constant - Create a horizontal SplitBar
9020  * @static
9021  * @type Number
9022  */
9023 Roo.SplitBar.HORIZONTAL = 2;
9024
9025 /**
9026  * Placement constant - The resizing element is to the left of the splitter element
9027  * @static
9028  * @type Number
9029  */
9030 Roo.SplitBar.LEFT = 1;
9031
9032 /**
9033  * Placement constant - The resizing element is to the right of the splitter element
9034  * @static
9035  * @type Number
9036  */
9037 Roo.SplitBar.RIGHT = 2;
9038
9039 /**
9040  * Placement constant - The resizing element is positioned above the splitter element
9041  * @static
9042  * @type Number
9043  */
9044 Roo.SplitBar.TOP = 3;
9045
9046 /**
9047  * Placement constant - The resizing element is positioned under splitter element
9048  * @static
9049  * @type Number
9050  */
9051 Roo.SplitBar.BOTTOM = 4;
9052 /*
9053  * Based on:
9054  * Ext JS Library 1.1.1
9055  * Copyright(c) 2006-2007, Ext JS, LLC.
9056  *
9057  * Originally Released Under LGPL - original licence link has changed is not relivant.
9058  *
9059  * Fork - LGPL
9060  * <script type="text/javascript">
9061  */
9062
9063 /**
9064  * @class Roo.View
9065  * @extends Roo.util.Observable
9066  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
9067  * This class also supports single and multi selection modes. <br>
9068  * Create a data model bound view:
9069  <pre><code>
9070  var store = new Roo.data.Store(...);
9071
9072  var view = new Roo.View({
9073     el : "my-element",
9074     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
9075  
9076     singleSelect: true,
9077     selectedClass: "ydataview-selected",
9078     store: store
9079  });
9080
9081  // listen for node click?
9082  view.on("click", function(vw, index, node, e){
9083  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9084  });
9085
9086  // load XML data
9087  dataModel.load("foobar.xml");
9088  </code></pre>
9089  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9090  * <br><br>
9091  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9092  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9093  * 
9094  * Note: old style constructor is still suported (container, template, config)
9095  * 
9096  * @constructor
9097  * Create a new View
9098  * @param {Object} config The config object
9099  * 
9100  */
9101 Roo.View = function(config, depreciated_tpl, depreciated_config){
9102     
9103     if (typeof(depreciated_tpl) == 'undefined') {
9104         // new way.. - universal constructor.
9105         Roo.apply(this, config);
9106         this.el  = Roo.get(this.el);
9107     } else {
9108         // old format..
9109         this.el  = Roo.get(config);
9110         this.tpl = depreciated_tpl;
9111         Roo.apply(this, depreciated_config);
9112     }
9113      
9114     
9115     if(typeof(this.tpl) == "string"){
9116         this.tpl = new Roo.Template(this.tpl);
9117     } else {
9118         // support xtype ctors..
9119         this.tpl = new Roo.factory(this.tpl, Roo);
9120     }
9121     
9122     
9123     this.tpl.compile();
9124    
9125
9126      
9127     /** @private */
9128     this.addEvents({
9129     /**
9130      * @event beforeclick
9131      * Fires before a click is processed. Returns false to cancel the default action.
9132      * @param {Roo.View} this
9133      * @param {Number} index The index of the target node
9134      * @param {HTMLElement} node The target node
9135      * @param {Roo.EventObject} e The raw event object
9136      */
9137         "beforeclick" : true,
9138     /**
9139      * @event click
9140      * Fires when a template node is clicked.
9141      * @param {Roo.View} this
9142      * @param {Number} index The index of the target node
9143      * @param {HTMLElement} node The target node
9144      * @param {Roo.EventObject} e The raw event object
9145      */
9146         "click" : true,
9147     /**
9148      * @event dblclick
9149      * Fires when a template node is double clicked.
9150      * @param {Roo.View} this
9151      * @param {Number} index The index of the target node
9152      * @param {HTMLElement} node The target node
9153      * @param {Roo.EventObject} e The raw event object
9154      */
9155         "dblclick" : true,
9156     /**
9157      * @event contextmenu
9158      * Fires when a template node is right clicked.
9159      * @param {Roo.View} this
9160      * @param {Number} index The index of the target node
9161      * @param {HTMLElement} node The target node
9162      * @param {Roo.EventObject} e The raw event object
9163      */
9164         "contextmenu" : true,
9165     /**
9166      * @event selectionchange
9167      * Fires when the selected nodes change.
9168      * @param {Roo.View} this
9169      * @param {Array} selections Array of the selected nodes
9170      */
9171         "selectionchange" : true,
9172
9173     /**
9174      * @event beforeselect
9175      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9176      * @param {Roo.View} this
9177      * @param {HTMLElement} node The node to be selected
9178      * @param {Array} selections Array of currently selected nodes
9179      */
9180         "beforeselect" : true
9181     });
9182
9183     this.el.on({
9184         "click": this.onClick,
9185         "dblclick": this.onDblClick,
9186         "contextmenu": this.onContextMenu,
9187         scope:this
9188     });
9189
9190     this.selections = [];
9191     this.nodes = [];
9192     this.cmp = new Roo.CompositeElementLite([]);
9193     if(this.store){
9194         this.store = Roo.factory(this.store, Roo.data);
9195         this.setStore(this.store, true);
9196     }
9197     Roo.View.superclass.constructor.call(this);
9198 };
9199
9200 Roo.extend(Roo.View, Roo.util.Observable, {
9201     
9202      /**
9203      * @cfg {Roo.data.Store} store Data store to load data from.
9204      */
9205     store : false,
9206     
9207     /**
9208      * @cfg {String|Roo.Element} el The container element.
9209      */
9210     el : '',
9211     
9212     /**
9213      * @cfg {String|Roo.Template} tpl The template used by this View 
9214      */
9215     tpl : false,
9216     
9217     /**
9218      * @cfg {String} selectedClass The css class to add to selected nodes
9219      */
9220     selectedClass : "x-view-selected",
9221      /**
9222      * @cfg {String} emptyText The empty text to show when nothing is loaded.
9223      */
9224     emptyText : "",
9225     /**
9226      * @cfg {Boolean} multiSelect Allow multiple selection
9227      */
9228     
9229     multiSelect : false,
9230     /**
9231      * @cfg {Boolean} singleSelect Allow single selection
9232      */
9233     singleSelect:  false,
9234     
9235     /**
9236      * Returns the element this view is bound to.
9237      * @return {Roo.Element}
9238      */
9239     getEl : function(){
9240         return this.el;
9241     },
9242
9243     /**
9244      * Refreshes the view.
9245      */
9246     refresh : function(){
9247         var t = this.tpl;
9248         this.clearSelections();
9249         this.el.update("");
9250         var html = [];
9251         var records = this.store.getRange();
9252         if(records.length < 1){
9253             this.el.update(this.emptyText);
9254             return;
9255         }
9256         for(var i = 0, len = records.length; i < len; i++){
9257             var data = this.prepareData(records[i].data, i, records[i]);
9258             html[html.length] = t.apply(data);
9259         }
9260         this.el.update(html.join(""));
9261         this.nodes = this.el.dom.childNodes;
9262         this.updateIndexes(0);
9263     },
9264
9265     /**
9266      * Function to override to reformat the data that is sent to
9267      * the template for each node.
9268      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9269      * a JSON object for an UpdateManager bound view).
9270      */
9271     prepareData : function(data){
9272         return data;
9273     },
9274
9275     onUpdate : function(ds, record){
9276         this.clearSelections();
9277         var index = this.store.indexOf(record);
9278         var n = this.nodes[index];
9279         this.tpl.insertBefore(n, this.prepareData(record.data));
9280         n.parentNode.removeChild(n);
9281         this.updateIndexes(index, index);
9282     },
9283
9284     onAdd : function(ds, records, index){
9285         this.clearSelections();
9286         if(this.nodes.length == 0){
9287             this.refresh();
9288             return;
9289         }
9290         var n = this.nodes[index];
9291         for(var i = 0, len = records.length; i < len; i++){
9292             var d = this.prepareData(records[i].data);
9293             if(n){
9294                 this.tpl.insertBefore(n, d);
9295             }else{
9296                 this.tpl.append(this.el, d);
9297             }
9298         }
9299         this.updateIndexes(index);
9300     },
9301
9302     onRemove : function(ds, record, index){
9303         this.clearSelections();
9304         this.el.dom.removeChild(this.nodes[index]);
9305         this.updateIndexes(index);
9306     },
9307
9308     /**
9309      * Refresh an individual node.
9310      * @param {Number} index
9311      */
9312     refreshNode : function(index){
9313         this.onUpdate(this.store, this.store.getAt(index));
9314     },
9315
9316     updateIndexes : function(startIndex, endIndex){
9317         var ns = this.nodes;
9318         startIndex = startIndex || 0;
9319         endIndex = endIndex || ns.length - 1;
9320         for(var i = startIndex; i <= endIndex; i++){
9321             ns[i].nodeIndex = i;
9322         }
9323     },
9324
9325     /**
9326      * Changes the data store this view uses and refresh the view.
9327      * @param {Store} store
9328      */
9329     setStore : function(store, initial){
9330         if(!initial && this.store){
9331             this.store.un("datachanged", this.refresh);
9332             this.store.un("add", this.onAdd);
9333             this.store.un("remove", this.onRemove);
9334             this.store.un("update", this.onUpdate);
9335             this.store.un("clear", this.refresh);
9336         }
9337         if(store){
9338           
9339             store.on("datachanged", this.refresh, this);
9340             store.on("add", this.onAdd, this);
9341             store.on("remove", this.onRemove, this);
9342             store.on("update", this.onUpdate, this);
9343             store.on("clear", this.refresh, this);
9344         }
9345         
9346         if(store){
9347             this.refresh();
9348         }
9349     },
9350
9351     /**
9352      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9353      * @param {HTMLElement} node
9354      * @return {HTMLElement} The template node
9355      */
9356     findItemFromChild : function(node){
9357         var el = this.el.dom;
9358         if(!node || node.parentNode == el){
9359                     return node;
9360             }
9361             var p = node.parentNode;
9362             while(p && p != el){
9363             if(p.parentNode == el){
9364                 return p;
9365             }
9366             p = p.parentNode;
9367         }
9368             return null;
9369     },
9370
9371     /** @ignore */
9372     onClick : function(e){
9373         var item = this.findItemFromChild(e.getTarget());
9374         if(item){
9375             var index = this.indexOf(item);
9376             if(this.onItemClick(item, index, e) !== false){
9377                 this.fireEvent("click", this, index, item, e);
9378             }
9379         }else{
9380             this.clearSelections();
9381         }
9382     },
9383
9384     /** @ignore */
9385     onContextMenu : function(e){
9386         var item = this.findItemFromChild(e.getTarget());
9387         if(item){
9388             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9389         }
9390     },
9391
9392     /** @ignore */
9393     onDblClick : function(e){
9394         var item = this.findItemFromChild(e.getTarget());
9395         if(item){
9396             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9397         }
9398     },
9399
9400     onItemClick : function(item, index, e){
9401         if(this.fireEvent("beforeclick", this, index, item, e) === false){
9402             return false;
9403         }
9404         if(this.multiSelect || this.singleSelect){
9405             if(this.multiSelect && e.shiftKey && this.lastSelection){
9406                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9407             }else{
9408                 this.select(item, this.multiSelect && e.ctrlKey);
9409                 this.lastSelection = item;
9410             }
9411             e.preventDefault();
9412         }
9413         return true;
9414     },
9415
9416     /**
9417      * Get the number of selected nodes.
9418      * @return {Number}
9419      */
9420     getSelectionCount : function(){
9421         return this.selections.length;
9422     },
9423
9424     /**
9425      * Get the currently selected nodes.
9426      * @return {Array} An array of HTMLElements
9427      */
9428     getSelectedNodes : function(){
9429         return this.selections;
9430     },
9431
9432     /**
9433      * Get the indexes of the selected nodes.
9434      * @return {Array}
9435      */
9436     getSelectedIndexes : function(){
9437         var indexes = [], s = this.selections;
9438         for(var i = 0, len = s.length; i < len; i++){
9439             indexes.push(s[i].nodeIndex);
9440         }
9441         return indexes;
9442     },
9443
9444     /**
9445      * Clear all selections
9446      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9447      */
9448     clearSelections : function(suppressEvent){
9449         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9450             this.cmp.elements = this.selections;
9451             this.cmp.removeClass(this.selectedClass);
9452             this.selections = [];
9453             if(!suppressEvent){
9454                 this.fireEvent("selectionchange", this, this.selections);
9455             }
9456         }
9457     },
9458
9459     /**
9460      * Returns true if the passed node is selected
9461      * @param {HTMLElement/Number} node The node or node index
9462      * @return {Boolean}
9463      */
9464     isSelected : function(node){
9465         var s = this.selections;
9466         if(s.length < 1){
9467             return false;
9468         }
9469         node = this.getNode(node);
9470         return s.indexOf(node) !== -1;
9471     },
9472
9473     /**
9474      * Selects nodes.
9475      * @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
9476      * @param {Boolean} keepExisting (optional) true to keep existing selections
9477      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9478      */
9479     select : function(nodeInfo, keepExisting, suppressEvent){
9480         if(nodeInfo instanceof Array){
9481             if(!keepExisting){
9482                 this.clearSelections(true);
9483             }
9484             for(var i = 0, len = nodeInfo.length; i < len; i++){
9485                 this.select(nodeInfo[i], true, true);
9486             }
9487         } else{
9488             var node = this.getNode(nodeInfo);
9489             if(node && !this.isSelected(node)){
9490                 if(!keepExisting){
9491                     this.clearSelections(true);
9492                 }
9493                 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9494                     Roo.fly(node).addClass(this.selectedClass);
9495                     this.selections.push(node);
9496                     if(!suppressEvent){
9497                         this.fireEvent("selectionchange", this, this.selections);
9498                     }
9499                 }
9500             }
9501         }
9502     },
9503
9504     /**
9505      * Gets a template node.
9506      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9507      * @return {HTMLElement} The node or null if it wasn't found
9508      */
9509     getNode : function(nodeInfo){
9510         if(typeof nodeInfo == "string"){
9511             return document.getElementById(nodeInfo);
9512         }else if(typeof nodeInfo == "number"){
9513             return this.nodes[nodeInfo];
9514         }
9515         return nodeInfo;
9516     },
9517
9518     /**
9519      * Gets a range template nodes.
9520      * @param {Number} startIndex
9521      * @param {Number} endIndex
9522      * @return {Array} An array of nodes
9523      */
9524     getNodes : function(start, end){
9525         var ns = this.nodes;
9526         start = start || 0;
9527         end = typeof end == "undefined" ? ns.length - 1 : end;
9528         var nodes = [];
9529         if(start <= end){
9530             for(var i = start; i <= end; i++){
9531                 nodes.push(ns[i]);
9532             }
9533         } else{
9534             for(var i = start; i >= end; i--){
9535                 nodes.push(ns[i]);
9536             }
9537         }
9538         return nodes;
9539     },
9540
9541     /**
9542      * Finds the index of the passed node
9543      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9544      * @return {Number} The index of the node or -1
9545      */
9546     indexOf : function(node){
9547         node = this.getNode(node);
9548         if(typeof node.nodeIndex == "number"){
9549             return node.nodeIndex;
9550         }
9551         var ns = this.nodes;
9552         for(var i = 0, len = ns.length; i < len; i++){
9553             if(ns[i] == node){
9554                 return i;
9555             }
9556         }
9557         return -1;
9558     }
9559 });
9560 /*
9561  * Based on:
9562  * Ext JS Library 1.1.1
9563  * Copyright(c) 2006-2007, Ext JS, LLC.
9564  *
9565  * Originally Released Under LGPL - original licence link has changed is not relivant.
9566  *
9567  * Fork - LGPL
9568  * <script type="text/javascript">
9569  */
9570
9571 /**
9572  * @class Roo.JsonView
9573  * @extends Roo.View
9574  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9575 <pre><code>
9576 var view = new Roo.JsonView({
9577     container: "my-element",
9578     tpl: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
9579     multiSelect: true, 
9580     jsonRoot: "data" 
9581 });
9582
9583 // listen for node click?
9584 view.on("click", function(vw, index, node, e){
9585     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9586 });
9587
9588 // direct load of JSON data
9589 view.load("foobar.php");
9590
9591 // Example from my blog list
9592 var tpl = new Roo.Template(
9593     '&lt;div class="entry"&gt;' +
9594     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
9595     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
9596     "&lt;/div&gt;&lt;hr /&gt;"
9597 );
9598
9599 var moreView = new Roo.JsonView({
9600     container :  "entry-list", 
9601     template : tpl,
9602     jsonRoot: "posts"
9603 });
9604 moreView.on("beforerender", this.sortEntries, this);
9605 moreView.load({
9606     url: "/blog/get-posts.php",
9607     params: "allposts=true",
9608     text: "Loading Blog Entries..."
9609 });
9610 </code></pre>
9611
9612 * Note: old code is supported with arguments : (container, template, config)
9613
9614
9615  * @constructor
9616  * Create a new JsonView
9617  * 
9618  * @param {Object} config The config object
9619  * 
9620  */
9621 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9622     
9623     
9624     Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9625
9626     var um = this.el.getUpdateManager();
9627     um.setRenderer(this);
9628     um.on("update", this.onLoad, this);
9629     um.on("failure", this.onLoadException, this);
9630
9631     /**
9632      * @event beforerender
9633      * Fires before rendering of the downloaded JSON data.
9634      * @param {Roo.JsonView} this
9635      * @param {Object} data The JSON data loaded
9636      */
9637     /**
9638      * @event load
9639      * Fires when data is loaded.
9640      * @param {Roo.JsonView} this
9641      * @param {Object} data The JSON data loaded
9642      * @param {Object} response The raw Connect response object
9643      */
9644     /**
9645      * @event loadexception
9646      * Fires when loading fails.
9647      * @param {Roo.JsonView} this
9648      * @param {Object} response The raw Connect response object
9649      */
9650     this.addEvents({
9651         'beforerender' : true,
9652         'load' : true,
9653         'loadexception' : true
9654     });
9655 };
9656 Roo.extend(Roo.JsonView, Roo.View, {
9657     /**
9658      * @type {String} The root property in the loaded JSON object that contains the data
9659      */
9660     jsonRoot : "",
9661
9662     /**
9663      * Refreshes the view.
9664      */
9665     refresh : function(){
9666         this.clearSelections();
9667         this.el.update("");
9668         var html = [];
9669         var o = this.jsonData;
9670         if(o && o.length > 0){
9671             for(var i = 0, len = o.length; i < len; i++){
9672                 var data = this.prepareData(o[i], i, o);
9673                 html[html.length] = this.tpl.apply(data);
9674             }
9675         }else{
9676             html.push(this.emptyText);
9677         }
9678         this.el.update(html.join(""));
9679         this.nodes = this.el.dom.childNodes;
9680         this.updateIndexes(0);
9681     },
9682
9683     /**
9684      * 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.
9685      * @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:
9686      <pre><code>
9687      view.load({
9688          url: "your-url.php",
9689          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9690          callback: yourFunction,
9691          scope: yourObject, //(optional scope)
9692          discardUrl: false,
9693          nocache: false,
9694          text: "Loading...",
9695          timeout: 30,
9696          scripts: false
9697      });
9698      </code></pre>
9699      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9700      * 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.
9701      * @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}
9702      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9703      * @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.
9704      */
9705     load : function(){
9706         var um = this.el.getUpdateManager();
9707         um.update.apply(um, arguments);
9708     },
9709
9710     render : function(el, response){
9711         this.clearSelections();
9712         this.el.update("");
9713         var o;
9714         try{
9715             o = Roo.util.JSON.decode(response.responseText);
9716             if(this.jsonRoot){
9717                 
9718                 o = o[this.jsonRoot];
9719             }
9720         } catch(e){
9721         }
9722         /**
9723          * The current JSON data or null
9724          */
9725         this.jsonData = o;
9726         this.beforeRender();
9727         this.refresh();
9728     },
9729
9730 /**
9731  * Get the number of records in the current JSON dataset
9732  * @return {Number}
9733  */
9734     getCount : function(){
9735         return this.jsonData ? this.jsonData.length : 0;
9736     },
9737
9738 /**
9739  * Returns the JSON object for the specified node(s)
9740  * @param {HTMLElement/Array} node The node or an array of nodes
9741  * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9742  * you get the JSON object for the node
9743  */
9744     getNodeData : function(node){
9745         if(node instanceof Array){
9746             var data = [];
9747             for(var i = 0, len = node.length; i < len; i++){
9748                 data.push(this.getNodeData(node[i]));
9749             }
9750             return data;
9751         }
9752         return this.jsonData[this.indexOf(node)] || null;
9753     },
9754
9755     beforeRender : function(){
9756         this.snapshot = this.jsonData;
9757         if(this.sortInfo){
9758             this.sort.apply(this, this.sortInfo);
9759         }
9760         this.fireEvent("beforerender", this, this.jsonData);
9761     },
9762
9763     onLoad : function(el, o){
9764         this.fireEvent("load", this, this.jsonData, o);
9765     },
9766
9767     onLoadException : function(el, o){
9768         this.fireEvent("loadexception", this, o);
9769     },
9770
9771 /**
9772  * Filter the data by a specific property.
9773  * @param {String} property A property on your JSON objects
9774  * @param {String/RegExp} value Either string that the property values
9775  * should start with, or a RegExp to test against the property
9776  */
9777     filter : function(property, value){
9778         if(this.jsonData){
9779             var data = [];
9780             var ss = this.snapshot;
9781             if(typeof value == "string"){
9782                 var vlen = value.length;
9783                 if(vlen == 0){
9784                     this.clearFilter();
9785                     return;
9786                 }
9787                 value = value.toLowerCase();
9788                 for(var i = 0, len = ss.length; i < len; i++){
9789                     var o = ss[i];
9790                     if(o[property].substr(0, vlen).toLowerCase() == value){
9791                         data.push(o);
9792                     }
9793                 }
9794             } else if(value.exec){ // regex?
9795                 for(var i = 0, len = ss.length; i < len; i++){
9796                     var o = ss[i];
9797                     if(value.test(o[property])){
9798                         data.push(o);
9799                     }
9800                 }
9801             } else{
9802                 return;
9803             }
9804             this.jsonData = data;
9805             this.refresh();
9806         }
9807     },
9808
9809 /**
9810  * Filter by a function. The passed function will be called with each
9811  * object in the current dataset. If the function returns true the value is kept,
9812  * otherwise it is filtered.
9813  * @param {Function} fn
9814  * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9815  */
9816     filterBy : function(fn, scope){
9817         if(this.jsonData){
9818             var data = [];
9819             var ss = this.snapshot;
9820             for(var i = 0, len = ss.length; i < len; i++){
9821                 var o = ss[i];
9822                 if(fn.call(scope || this, o)){
9823                     data.push(o);
9824                 }
9825             }
9826             this.jsonData = data;
9827             this.refresh();
9828         }
9829     },
9830
9831 /**
9832  * Clears the current filter.
9833  */
9834     clearFilter : function(){
9835         if(this.snapshot && this.jsonData != this.snapshot){
9836             this.jsonData = this.snapshot;
9837             this.refresh();
9838         }
9839     },
9840
9841
9842 /**
9843  * Sorts the data for this view and refreshes it.
9844  * @param {String} property A property on your JSON objects to sort on
9845  * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9846  * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9847  */
9848     sort : function(property, dir, sortType){
9849         this.sortInfo = Array.prototype.slice.call(arguments, 0);
9850         if(this.jsonData){
9851             var p = property;
9852             var dsc = dir && dir.toLowerCase() == "desc";
9853             var f = function(o1, o2){
9854                 var v1 = sortType ? sortType(o1[p]) : o1[p];
9855                 var v2 = sortType ? sortType(o2[p]) : o2[p];
9856                 ;
9857                 if(v1 < v2){
9858                     return dsc ? +1 : -1;
9859                 } else if(v1 > v2){
9860                     return dsc ? -1 : +1;
9861                 } else{
9862                     return 0;
9863                 }
9864             };
9865             this.jsonData.sort(f);
9866             this.refresh();
9867             if(this.jsonData != this.snapshot){
9868                 this.snapshot.sort(f);
9869             }
9870         }
9871     }
9872 });/*
9873  * Based on:
9874  * Ext JS Library 1.1.1
9875  * Copyright(c) 2006-2007, Ext JS, LLC.
9876  *
9877  * Originally Released Under LGPL - original licence link has changed is not relivant.
9878  *
9879  * Fork - LGPL
9880  * <script type="text/javascript">
9881  */
9882  
9883
9884 /**
9885  * @class Roo.ColorPalette
9886  * @extends Roo.Component
9887  * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
9888  * Here's an example of typical usage:
9889  * <pre><code>
9890 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
9891 cp.render('my-div');
9892
9893 cp.on('select', function(palette, selColor){
9894     // do something with selColor
9895 });
9896 </code></pre>
9897  * @constructor
9898  * Create a new ColorPalette
9899  * @param {Object} config The config object
9900  */
9901 Roo.ColorPalette = function(config){
9902     Roo.ColorPalette.superclass.constructor.call(this, config);
9903     this.addEvents({
9904         /**
9905              * @event select
9906              * Fires when a color is selected
9907              * @param {ColorPalette} this
9908              * @param {String} color The 6-digit color hex code (without the # symbol)
9909              */
9910         select: true
9911     });
9912
9913     if(this.handler){
9914         this.on("select", this.handler, this.scope, true);
9915     }
9916 };
9917 Roo.extend(Roo.ColorPalette, Roo.Component, {
9918     /**
9919      * @cfg {String} itemCls
9920      * The CSS class to apply to the containing element (defaults to "x-color-palette")
9921      */
9922     itemCls : "x-color-palette",
9923     /**
9924      * @cfg {String} value
9925      * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
9926      * the hex codes are case-sensitive.
9927      */
9928     value : null,
9929     clickEvent:'click',
9930     // private
9931     ctype: "Roo.ColorPalette",
9932
9933     /**
9934      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9935      */
9936     allowReselect : false,
9937
9938     /**
9939      * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
9940      * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
9941      * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9942      * of colors with the width setting until the box is symmetrical.</p>
9943      * <p>You can override individual colors if needed:</p>
9944      * <pre><code>
9945 var cp = new Roo.ColorPalette();
9946 cp.colors[0] = "FF0000";  // change the first box to red
9947 </code></pre>
9948
9949 Or you can provide a custom array of your own for complete control:
9950 <pre><code>
9951 var cp = new Roo.ColorPalette();
9952 cp.colors = ["000000", "993300", "333300"];
9953 </code></pre>
9954      * @type Array
9955      */
9956     colors : [
9957         "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9958         "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9959         "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9960         "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9961         "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9962     ],
9963
9964     // private
9965     onRender : function(container, position){
9966         var t = new Roo.MasterTemplate(
9967             '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
9968         );
9969         var c = this.colors;
9970         for(var i = 0, len = c.length; i < len; i++){
9971             t.add([c[i]]);
9972         }
9973         var el = document.createElement("div");
9974         el.className = this.itemCls;
9975         t.overwrite(el);
9976         container.dom.insertBefore(el, position);
9977         this.el = Roo.get(el);
9978         this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
9979         if(this.clickEvent != 'click'){
9980             this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
9981         }
9982     },
9983
9984     // private
9985     afterRender : function(){
9986         Roo.ColorPalette.superclass.afterRender.call(this);
9987         if(this.value){
9988             var s = this.value;
9989             this.value = null;
9990             this.select(s);
9991         }
9992     },
9993
9994     // private
9995     handleClick : function(e, t){
9996         e.preventDefault();
9997         if(!this.disabled){
9998             var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9999             this.select(c.toUpperCase());
10000         }
10001     },
10002
10003     /**
10004      * Selects the specified color in the palette (fires the select event)
10005      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10006      */
10007     select : function(color){
10008         color = color.replace("#", "");
10009         if(color != this.value || this.allowReselect){
10010             var el = this.el;
10011             if(this.value){
10012                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10013             }
10014             el.child("a.color-"+color).addClass("x-color-palette-sel");
10015             this.value = color;
10016             this.fireEvent("select", this, color);
10017         }
10018     }
10019 });/*
10020  * Based on:
10021  * Ext JS Library 1.1.1
10022  * Copyright(c) 2006-2007, Ext JS, LLC.
10023  *
10024  * Originally Released Under LGPL - original licence link has changed is not relivant.
10025  *
10026  * Fork - LGPL
10027  * <script type="text/javascript">
10028  */
10029  
10030 /**
10031  * @class Roo.DatePicker
10032  * @extends Roo.Component
10033  * Simple date picker class.
10034  * @constructor
10035  * Create a new DatePicker
10036  * @param {Object} config The config object
10037  */
10038 Roo.DatePicker = function(config){
10039     Roo.DatePicker.superclass.constructor.call(this, config);
10040
10041     this.value = config && config.value ?
10042                  config.value.clearTime() : new Date().clearTime();
10043
10044     this.addEvents({
10045         /**
10046              * @event select
10047              * Fires when a date is selected
10048              * @param {DatePicker} this
10049              * @param {Date} date The selected date
10050              */
10051         select: true
10052     });
10053
10054     if(this.handler){
10055         this.on("select", this.handler,  this.scope || this);
10056     }
10057     // build the disabledDatesRE
10058     if(!this.disabledDatesRE && this.disabledDates){
10059         var dd = this.disabledDates;
10060         var re = "(?:";
10061         for(var i = 0; i < dd.length; i++){
10062             re += dd[i];
10063             if(i != dd.length-1) re += "|";
10064         }
10065         this.disabledDatesRE = new RegExp(re + ")");
10066     }
10067 };
10068
10069 Roo.extend(Roo.DatePicker, Roo.Component, {
10070     /**
10071      * @cfg {String} todayText
10072      * The text to display on the button that selects the current date (defaults to "Today")
10073      */
10074     todayText : "Today",
10075     /**
10076      * @cfg {String} okText
10077      * The text to display on the ok button
10078      */
10079     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
10080     /**
10081      * @cfg {String} cancelText
10082      * The text to display on the cancel button
10083      */
10084     cancelText : "Cancel",
10085     /**
10086      * @cfg {String} todayTip
10087      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10088      */
10089     todayTip : "{0} (Spacebar)",
10090     /**
10091      * @cfg {Date} minDate
10092      * Minimum allowable date (JavaScript date object, defaults to null)
10093      */
10094     minDate : null,
10095     /**
10096      * @cfg {Date} maxDate
10097      * Maximum allowable date (JavaScript date object, defaults to null)
10098      */
10099     maxDate : null,
10100     /**
10101      * @cfg {String} minText
10102      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10103      */
10104     minText : "This date is before the minimum date",
10105     /**
10106      * @cfg {String} maxText
10107      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10108      */
10109     maxText : "This date is after the maximum date",
10110     /**
10111      * @cfg {String} format
10112      * The default date format string which can be overriden for localization support.  The format must be
10113      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10114      */
10115     format : "m/d/y",
10116     /**
10117      * @cfg {Array} disabledDays
10118      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10119      */
10120     disabledDays : null,
10121     /**
10122      * @cfg {String} disabledDaysText
10123      * The tooltip to display when the date falls on a disabled day (defaults to "")
10124      */
10125     disabledDaysText : "",
10126     /**
10127      * @cfg {RegExp} disabledDatesRE
10128      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10129      */
10130     disabledDatesRE : null,
10131     /**
10132      * @cfg {String} disabledDatesText
10133      * The tooltip text to display when the date falls on a disabled date (defaults to "")
10134      */
10135     disabledDatesText : "",
10136     /**
10137      * @cfg {Boolean} constrainToViewport
10138      * True to constrain the date picker to the viewport (defaults to true)
10139      */
10140     constrainToViewport : true,
10141     /**
10142      * @cfg {Array} monthNames
10143      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10144      */
10145     monthNames : Date.monthNames,
10146     /**
10147      * @cfg {Array} dayNames
10148      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10149      */
10150     dayNames : Date.dayNames,
10151     /**
10152      * @cfg {String} nextText
10153      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10154      */
10155     nextText: 'Next Month (Control+Right)',
10156     /**
10157      * @cfg {String} prevText
10158      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10159      */
10160     prevText: 'Previous Month (Control+Left)',
10161     /**
10162      * @cfg {String} monthYearText
10163      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10164      */
10165     monthYearText: 'Choose a month (Control+Up/Down to move years)',
10166     /**
10167      * @cfg {Number} startDay
10168      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10169      */
10170     startDay : 0,
10171     /**
10172      * @cfg {Bool} showClear
10173      * Show a clear button (usefull for date form elements that can be blank.)
10174      */
10175     
10176     showClear: false,
10177     
10178     /**
10179      * Sets the value of the date field
10180      * @param {Date} value The date to set
10181      */
10182     setValue : function(value){
10183         var old = this.value;
10184         this.value = value.clearTime(true);
10185         if(this.el){
10186             this.update(this.value);
10187         }
10188     },
10189
10190     /**
10191      * Gets the current selected value of the date field
10192      * @return {Date} The selected date
10193      */
10194     getValue : function(){
10195         return this.value;
10196     },
10197
10198     // private
10199     focus : function(){
10200         if(this.el){
10201             this.update(this.activeDate);
10202         }
10203     },
10204
10205     // private
10206     onRender : function(container, position){
10207         var m = [
10208              '<table cellspacing="0">',
10209                 '<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>',
10210                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10211         var dn = this.dayNames;
10212         for(var i = 0; i < 7; i++){
10213             var d = this.startDay+i;
10214             if(d > 6){
10215                 d = d-7;
10216             }
10217             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10218         }
10219         m[m.length] = "</tr></thead><tbody><tr>";
10220         for(var i = 0; i < 42; i++) {
10221             if(i % 7 == 0 && i != 0){
10222                 m[m.length] = "</tr><tr>";
10223             }
10224             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10225         }
10226         m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10227             '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10228
10229         var el = document.createElement("div");
10230         el.className = "x-date-picker";
10231         el.innerHTML = m.join("");
10232
10233         container.dom.insertBefore(el, position);
10234
10235         this.el = Roo.get(el);
10236         this.eventEl = Roo.get(el.firstChild);
10237
10238         new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10239             handler: this.showPrevMonth,
10240             scope: this,
10241             preventDefault:true,
10242             stopDefault:true
10243         });
10244
10245         new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10246             handler: this.showNextMonth,
10247             scope: this,
10248             preventDefault:true,
10249             stopDefault:true
10250         });
10251
10252         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
10253
10254         this.monthPicker = this.el.down('div.x-date-mp');
10255         this.monthPicker.enableDisplayMode('block');
10256         
10257         var kn = new Roo.KeyNav(this.eventEl, {
10258             "left" : function(e){
10259                 e.ctrlKey ?
10260                     this.showPrevMonth() :
10261                     this.update(this.activeDate.add("d", -1));
10262             },
10263
10264             "right" : function(e){
10265                 e.ctrlKey ?
10266                     this.showNextMonth() :
10267                     this.update(this.activeDate.add("d", 1));
10268             },
10269
10270             "up" : function(e){
10271                 e.ctrlKey ?
10272                     this.showNextYear() :
10273                     this.update(this.activeDate.add("d", -7));
10274             },
10275
10276             "down" : function(e){
10277                 e.ctrlKey ?
10278                     this.showPrevYear() :
10279                     this.update(this.activeDate.add("d", 7));
10280             },
10281
10282             "pageUp" : function(e){
10283                 this.showNextMonth();
10284             },
10285
10286             "pageDown" : function(e){
10287                 this.showPrevMonth();
10288             },
10289
10290             "enter" : function(e){
10291                 e.stopPropagation();
10292                 return true;
10293             },
10294
10295             scope : this
10296         });
10297
10298         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
10299
10300         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
10301
10302         this.el.unselectable();
10303         
10304         this.cells = this.el.select("table.x-date-inner tbody td");
10305         this.textNodes = this.el.query("table.x-date-inner tbody span");
10306
10307         this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10308             text: "&#160;",
10309             tooltip: this.monthYearText
10310         });
10311
10312         this.mbtn.on('click', this.showMonthPicker, this);
10313         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10314
10315
10316         var today = (new Date()).dateFormat(this.format);
10317         
10318         var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10319         if (this.showClear) {
10320             baseTb.add( new Roo.Toolbar.Fill());
10321         }
10322         baseTb.add({
10323             text: String.format(this.todayText, today),
10324             tooltip: String.format(this.todayTip, today),
10325             handler: this.selectToday,
10326             scope: this
10327         });
10328         
10329         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10330             
10331         //});
10332         if (this.showClear) {
10333             
10334             baseTb.add( new Roo.Toolbar.Fill());
10335             baseTb.add({
10336                 text: '&#160;',
10337                 cls: 'x-btn-icon x-btn-clear',
10338                 handler: function() {
10339                     //this.value = '';
10340                     this.fireEvent("select", this, '');
10341                 },
10342                 scope: this
10343             });
10344         }
10345         
10346         
10347         if(Roo.isIE){
10348             this.el.repaint();
10349         }
10350         this.update(this.value);
10351     },
10352
10353     createMonthPicker : function(){
10354         if(!this.monthPicker.dom.firstChild){
10355             var buf = ['<table border="0" cellspacing="0">'];
10356             for(var i = 0; i < 6; i++){
10357                 buf.push(
10358                     '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10359                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10360                     i == 0 ?
10361                     '<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>' :
10362                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10363                 );
10364             }
10365             buf.push(
10366                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10367                     this.okText,
10368                     '</button><button type="button" class="x-date-mp-cancel">',
10369                     this.cancelText,
10370                     '</button></td></tr>',
10371                 '</table>'
10372             );
10373             this.monthPicker.update(buf.join(''));
10374             this.monthPicker.on('click', this.onMonthClick, this);
10375             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10376
10377             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10378             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10379
10380             this.mpMonths.each(function(m, a, i){
10381                 i += 1;
10382                 if((i%2) == 0){
10383                     m.dom.xmonth = 5 + Math.round(i * .5);
10384                 }else{
10385                     m.dom.xmonth = Math.round((i-1) * .5);
10386                 }
10387             });
10388         }
10389     },
10390
10391     showMonthPicker : function(){
10392         this.createMonthPicker();
10393         var size = this.el.getSize();
10394         this.monthPicker.setSize(size);
10395         this.monthPicker.child('table').setSize(size);
10396
10397         this.mpSelMonth = (this.activeDate || this.value).getMonth();
10398         this.updateMPMonth(this.mpSelMonth);
10399         this.mpSelYear = (this.activeDate || this.value).getFullYear();
10400         this.updateMPYear(this.mpSelYear);
10401
10402         this.monthPicker.slideIn('t', {duration:.2});
10403     },
10404
10405     updateMPYear : function(y){
10406         this.mpyear = y;
10407         var ys = this.mpYears.elements;
10408         for(var i = 1; i <= 10; i++){
10409             var td = ys[i-1], y2;
10410             if((i%2) == 0){
10411                 y2 = y + Math.round(i * .5);
10412                 td.firstChild.innerHTML = y2;
10413                 td.xyear = y2;
10414             }else{
10415                 y2 = y - (5-Math.round(i * .5));
10416                 td.firstChild.innerHTML = y2;
10417                 td.xyear = y2;
10418             }
10419             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10420         }
10421     },
10422
10423     updateMPMonth : function(sm){
10424         this.mpMonths.each(function(m, a, i){
10425             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10426         });
10427     },
10428
10429     selectMPMonth: function(m){
10430         
10431     },
10432
10433     onMonthClick : function(e, t){
10434         e.stopEvent();
10435         var el = new Roo.Element(t), pn;
10436         if(el.is('button.x-date-mp-cancel')){
10437             this.hideMonthPicker();
10438         }
10439         else if(el.is('button.x-date-mp-ok')){
10440             this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10441             this.hideMonthPicker();
10442         }
10443         else if(pn = el.up('td.x-date-mp-month', 2)){
10444             this.mpMonths.removeClass('x-date-mp-sel');
10445             pn.addClass('x-date-mp-sel');
10446             this.mpSelMonth = pn.dom.xmonth;
10447         }
10448         else if(pn = el.up('td.x-date-mp-year', 2)){
10449             this.mpYears.removeClass('x-date-mp-sel');
10450             pn.addClass('x-date-mp-sel');
10451             this.mpSelYear = pn.dom.xyear;
10452         }
10453         else if(el.is('a.x-date-mp-prev')){
10454             this.updateMPYear(this.mpyear-10);
10455         }
10456         else if(el.is('a.x-date-mp-next')){
10457             this.updateMPYear(this.mpyear+10);
10458         }
10459     },
10460
10461     onMonthDblClick : function(e, t){
10462         e.stopEvent();
10463         var el = new Roo.Element(t), pn;
10464         if(pn = el.up('td.x-date-mp-month', 2)){
10465             this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10466             this.hideMonthPicker();
10467         }
10468         else if(pn = el.up('td.x-date-mp-year', 2)){
10469             this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10470             this.hideMonthPicker();
10471         }
10472     },
10473
10474     hideMonthPicker : function(disableAnim){
10475         if(this.monthPicker){
10476             if(disableAnim === true){
10477                 this.monthPicker.hide();
10478             }else{
10479                 this.monthPicker.slideOut('t', {duration:.2});
10480             }
10481         }
10482     },
10483
10484     // private
10485     showPrevMonth : function(e){
10486         this.update(this.activeDate.add("mo", -1));
10487     },
10488
10489     // private
10490     showNextMonth : function(e){
10491         this.update(this.activeDate.add("mo", 1));
10492     },
10493
10494     // private
10495     showPrevYear : function(){
10496         this.update(this.activeDate.add("y", -1));
10497     },
10498
10499     // private
10500     showNextYear : function(){
10501         this.update(this.activeDate.add("y", 1));
10502     },
10503
10504     // private
10505     handleMouseWheel : function(e){
10506         var delta = e.getWheelDelta();
10507         if(delta > 0){
10508             this.showPrevMonth();
10509             e.stopEvent();
10510         } else if(delta < 0){
10511             this.showNextMonth();
10512             e.stopEvent();
10513         }
10514     },
10515
10516     // private
10517     handleDateClick : function(e, t){
10518         e.stopEvent();
10519         if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10520             this.setValue(new Date(t.dateValue));
10521             this.fireEvent("select", this, this.value);
10522         }
10523     },
10524
10525     // private
10526     selectToday : function(){
10527         this.setValue(new Date().clearTime());
10528         this.fireEvent("select", this, this.value);
10529     },
10530
10531     // private
10532     update : function(date){
10533         var vd = this.activeDate;
10534         this.activeDate = date;
10535         if(vd && this.el){
10536             var t = date.getTime();
10537             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10538                 this.cells.removeClass("x-date-selected");
10539                 this.cells.each(function(c){
10540                    if(c.dom.firstChild.dateValue == t){
10541                        c.addClass("x-date-selected");
10542                        setTimeout(function(){
10543                             try{c.dom.firstChild.focus();}catch(e){}
10544                        }, 50);
10545                        return false;
10546                    }
10547                 });
10548                 return;
10549             }
10550         }
10551         var days = date.getDaysInMonth();
10552         var firstOfMonth = date.getFirstDateOfMonth();
10553         var startingPos = firstOfMonth.getDay()-this.startDay;
10554
10555         if(startingPos <= this.startDay){
10556             startingPos += 7;
10557         }
10558
10559         var pm = date.add("mo", -1);
10560         var prevStart = pm.getDaysInMonth()-startingPos;
10561
10562         var cells = this.cells.elements;
10563         var textEls = this.textNodes;
10564         days += startingPos;
10565
10566         // convert everything to numbers so it's fast
10567         var day = 86400000;
10568         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10569         var today = new Date().clearTime().getTime();
10570         var sel = date.clearTime().getTime();
10571         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10572         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10573         var ddMatch = this.disabledDatesRE;
10574         var ddText = this.disabledDatesText;
10575         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10576         var ddaysText = this.disabledDaysText;
10577         var format = this.format;
10578
10579         var setCellClass = function(cal, cell){
10580             cell.title = "";
10581             var t = d.getTime();
10582             cell.firstChild.dateValue = t;
10583             if(t == today){
10584                 cell.className += " x-date-today";
10585                 cell.title = cal.todayText;
10586             }
10587             if(t == sel){
10588                 cell.className += " x-date-selected";
10589                 setTimeout(function(){
10590                     try{cell.firstChild.focus();}catch(e){}
10591                 }, 50);
10592             }
10593             // disabling
10594             if(t < min) {
10595                 cell.className = " x-date-disabled";
10596                 cell.title = cal.minText;
10597                 return;
10598             }
10599             if(t > max) {
10600                 cell.className = " x-date-disabled";
10601                 cell.title = cal.maxText;
10602                 return;
10603             }
10604             if(ddays){
10605                 if(ddays.indexOf(d.getDay()) != -1){
10606                     cell.title = ddaysText;
10607                     cell.className = " x-date-disabled";
10608                 }
10609             }
10610             if(ddMatch && format){
10611                 var fvalue = d.dateFormat(format);
10612                 if(ddMatch.test(fvalue)){
10613                     cell.title = ddText.replace("%0", fvalue);
10614                     cell.className = " x-date-disabled";
10615                 }
10616             }
10617         };
10618
10619         var i = 0;
10620         for(; i < startingPos; i++) {
10621             textEls[i].innerHTML = (++prevStart);
10622             d.setDate(d.getDate()+1);
10623             cells[i].className = "x-date-prevday";
10624             setCellClass(this, cells[i]);
10625         }
10626         for(; i < days; i++){
10627             intDay = i - startingPos + 1;
10628             textEls[i].innerHTML = (intDay);
10629             d.setDate(d.getDate()+1);
10630             cells[i].className = "x-date-active";
10631             setCellClass(this, cells[i]);
10632         }
10633         var extraDays = 0;
10634         for(; i < 42; i++) {
10635              textEls[i].innerHTML = (++extraDays);
10636              d.setDate(d.getDate()+1);
10637              cells[i].className = "x-date-nextday";
10638              setCellClass(this, cells[i]);
10639         }
10640
10641         this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10642
10643         if(!this.internalRender){
10644             var main = this.el.dom.firstChild;
10645             var w = main.offsetWidth;
10646             this.el.setWidth(w + this.el.getBorderWidth("lr"));
10647             Roo.fly(main).setWidth(w);
10648             this.internalRender = true;
10649             // opera does not respect the auto grow header center column
10650             // then, after it gets a width opera refuses to recalculate
10651             // without a second pass
10652             if(Roo.isOpera && !this.secondPass){
10653                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10654                 this.secondPass = true;
10655                 this.update.defer(10, this, [date]);
10656             }
10657         }
10658     }
10659 });/*
10660  * Based on:
10661  * Ext JS Library 1.1.1
10662  * Copyright(c) 2006-2007, Ext JS, LLC.
10663  *
10664  * Originally Released Under LGPL - original licence link has changed is not relivant.
10665  *
10666  * Fork - LGPL
10667  * <script type="text/javascript">
10668  */
10669 /**
10670  * @class Roo.TabPanel
10671  * @extends Roo.util.Observable
10672  * A lightweight tab container.
10673  * <br><br>
10674  * Usage:
10675  * <pre><code>
10676 // basic tabs 1, built from existing content
10677 var tabs = new Roo.TabPanel("tabs1");
10678 tabs.addTab("script", "View Script");
10679 tabs.addTab("markup", "View Markup");
10680 tabs.activate("script");
10681
10682 // more advanced tabs, built from javascript
10683 var jtabs = new Roo.TabPanel("jtabs");
10684 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10685
10686 // set up the UpdateManager
10687 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10688 var updater = tab2.getUpdateManager();
10689 updater.setDefaultUrl("ajax1.htm");
10690 tab2.on('activate', updater.refresh, updater, true);
10691
10692 // Use setUrl for Ajax loading
10693 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10694 tab3.setUrl("ajax2.htm", null, true);
10695
10696 // Disabled tab
10697 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10698 tab4.disable();
10699
10700 jtabs.activate("jtabs-1");
10701  * </code></pre>
10702  * @constructor
10703  * Create a new TabPanel.
10704  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10705  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10706  */
10707 Roo.TabPanel = function(container, config){
10708     /**
10709     * The container element for this TabPanel.
10710     * @type Roo.Element
10711     */
10712     this.el = Roo.get(container, true);
10713     if(config){
10714         if(typeof config == "boolean"){
10715             this.tabPosition = config ? "bottom" : "top";
10716         }else{
10717             Roo.apply(this, config);
10718         }
10719     }
10720     if(this.tabPosition == "bottom"){
10721         this.bodyEl = Roo.get(this.createBody(this.el.dom));
10722         this.el.addClass("x-tabs-bottom");
10723     }
10724     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10725     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10726     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10727     if(Roo.isIE){
10728         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10729     }
10730     if(this.tabPosition != "bottom"){
10731     /** The body element that contains {@link Roo.TabPanelItem} bodies.
10732      * @type Roo.Element
10733      */
10734       this.bodyEl = Roo.get(this.createBody(this.el.dom));
10735       this.el.addClass("x-tabs-top");
10736     }
10737     this.items = [];
10738
10739     this.bodyEl.setStyle("position", "relative");
10740
10741     this.active = null;
10742     this.activateDelegate = this.activate.createDelegate(this);
10743
10744     this.addEvents({
10745         /**
10746          * @event tabchange
10747          * Fires when the active tab changes
10748          * @param {Roo.TabPanel} this
10749          * @param {Roo.TabPanelItem} activePanel The new active tab
10750          */
10751         "tabchange": true,
10752         /**
10753          * @event beforetabchange
10754          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10755          * @param {Roo.TabPanel} this
10756          * @param {Object} e Set cancel to true on this object to cancel the tab change
10757          * @param {Roo.TabPanelItem} tab The tab being changed to
10758          */
10759         "beforetabchange" : true
10760     });
10761
10762     Roo.EventManager.onWindowResize(this.onResize, this);
10763     this.cpad = this.el.getPadding("lr");
10764     this.hiddenCount = 0;
10765
10766     Roo.TabPanel.superclass.constructor.call(this);
10767 };
10768
10769 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10770         /*
10771          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10772          */
10773     tabPosition : "top",
10774         /*
10775          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10776          */
10777     currentTabWidth : 0,
10778         /*
10779          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10780          */
10781     minTabWidth : 40,
10782         /*
10783          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10784          */
10785     maxTabWidth : 250,
10786         /*
10787          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10788          */
10789     preferredTabWidth : 175,
10790         /*
10791          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10792          */
10793     resizeTabs : false,
10794         /*
10795          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10796          */
10797     monitorResize : true,
10798
10799     /**
10800      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10801      * @param {String} id The id of the div to use <b>or create</b>
10802      * @param {String} text The text for the tab
10803      * @param {String} content (optional) Content to put in the TabPanelItem body
10804      * @param {Boolean} closable (optional) True to create a close icon on the tab
10805      * @return {Roo.TabPanelItem} The created TabPanelItem
10806      */
10807     addTab : function(id, text, content, closable){
10808         var item = new Roo.TabPanelItem(this, id, text, closable);
10809         this.addTabItem(item);
10810         if(content){
10811             item.setContent(content);
10812         }
10813         return item;
10814     },
10815
10816     /**
10817      * Returns the {@link Roo.TabPanelItem} with the specified id/index
10818      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10819      * @return {Roo.TabPanelItem}
10820      */
10821     getTab : function(id){
10822         return this.items[id];
10823     },
10824
10825     /**
10826      * Hides the {@link Roo.TabPanelItem} with the specified id/index
10827      * @param {String/Number} id The id or index of the TabPanelItem to hide.
10828      */
10829     hideTab : function(id){
10830         var t = this.items[id];
10831         if(!t.isHidden()){
10832            t.setHidden(true);
10833            this.hiddenCount++;
10834            this.autoSizeTabs();
10835         }
10836     },
10837
10838     /**
10839      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10840      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10841      */
10842     unhideTab : function(id){
10843         var t = this.items[id];
10844         if(t.isHidden()){
10845            t.setHidden(false);
10846            this.hiddenCount--;
10847            this.autoSizeTabs();
10848         }
10849     },
10850
10851     /**
10852      * Adds an existing {@link Roo.TabPanelItem}.
10853      * @param {Roo.TabPanelItem} item The TabPanelItem to add
10854      */
10855     addTabItem : function(item){
10856         this.items[item.id] = item;
10857         this.items.push(item);
10858         if(this.resizeTabs){
10859            item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10860            this.autoSizeTabs();
10861         }else{
10862             item.autoSize();
10863         }
10864     },
10865
10866     /**
10867      * Removes a {@link Roo.TabPanelItem}.
10868      * @param {String/Number} id The id or index of the TabPanelItem to remove.
10869      */
10870     removeTab : function(id){
10871         var items = this.items;
10872         var tab = items[id];
10873         if(!tab) { return; }
10874         var index = items.indexOf(tab);
10875         if(this.active == tab && items.length > 1){
10876             var newTab = this.getNextAvailable(index);
10877             if(newTab) {
10878                 newTab.activate();
10879             }
10880         }
10881         this.stripEl.dom.removeChild(tab.pnode.dom);
10882         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10883             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10884         }
10885         items.splice(index, 1);
10886         delete this.items[tab.id];
10887         tab.fireEvent("close", tab);
10888         tab.purgeListeners();
10889         this.autoSizeTabs();
10890     },
10891
10892     getNextAvailable : function(start){
10893         var items = this.items;
10894         var index = start;
10895         // look for a next tab that will slide over to
10896         // replace the one being removed
10897         while(index < items.length){
10898             var item = items[++index];
10899             if(item && !item.isHidden()){
10900                 return item;
10901             }
10902         }
10903         // if one isn't found select the previous tab (on the left)
10904         index = start;
10905         while(index >= 0){
10906             var item = items[--index];
10907             if(item && !item.isHidden()){
10908                 return item;
10909             }
10910         }
10911         return null;
10912     },
10913
10914     /**
10915      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10916      * @param {String/Number} id The id or index of the TabPanelItem to disable.
10917      */
10918     disableTab : function(id){
10919         var tab = this.items[id];
10920         if(tab && this.active != tab){
10921             tab.disable();
10922         }
10923     },
10924
10925     /**
10926      * Enables a {@link Roo.TabPanelItem} that is disabled.
10927      * @param {String/Number} id The id or index of the TabPanelItem to enable.
10928      */
10929     enableTab : function(id){
10930         var tab = this.items[id];
10931         tab.enable();
10932     },
10933
10934     /**
10935      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10936      * @param {String/Number} id The id or index of the TabPanelItem to activate.
10937      * @return {Roo.TabPanelItem} The TabPanelItem.
10938      */
10939     activate : function(id){
10940         var tab = this.items[id];
10941         if(!tab){
10942             return null;
10943         }
10944         if(tab == this.active || tab.disabled){
10945             return tab;
10946         }
10947         var e = {};
10948         this.fireEvent("beforetabchange", this, e, tab);
10949         if(e.cancel !== true && !tab.disabled){
10950             if(this.active){
10951                 this.active.hide();
10952             }
10953             this.active = this.items[id];
10954             this.active.show();
10955             this.fireEvent("tabchange", this, this.active);
10956         }
10957         return tab;
10958     },
10959
10960     /**
10961      * Gets the active {@link Roo.TabPanelItem}.
10962      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10963      */
10964     getActiveTab : function(){
10965         return this.active;
10966     },
10967
10968     /**
10969      * Updates the tab body element to fit the height of the container element
10970      * for overflow scrolling
10971      * @param {Number} targetHeight (optional) Override the starting height from the elements height
10972      */
10973     syncHeight : function(targetHeight){
10974         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10975         var bm = this.bodyEl.getMargins();
10976         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10977         this.bodyEl.setHeight(newHeight);
10978         return newHeight;
10979     },
10980
10981     onResize : function(){
10982         if(this.monitorResize){
10983             this.autoSizeTabs();
10984         }
10985     },
10986
10987     /**
10988      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10989      */
10990     beginUpdate : function(){
10991         this.updating = true;
10992     },
10993
10994     /**
10995      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10996      */
10997     endUpdate : function(){
10998         this.updating = false;
10999         this.autoSizeTabs();
11000     },
11001
11002     /**
11003      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11004      */
11005     autoSizeTabs : function(){
11006         var count = this.items.length;
11007         var vcount = count - this.hiddenCount;
11008         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11009         var w = Math.max(this.el.getWidth() - this.cpad, 10);
11010         var availWidth = Math.floor(w / vcount);
11011         var b = this.stripBody;
11012         if(b.getWidth() > w){
11013             var tabs = this.items;
11014             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11015             if(availWidth < this.minTabWidth){
11016                 /*if(!this.sleft){    // incomplete scrolling code
11017                     this.createScrollButtons();
11018                 }
11019                 this.showScroll();
11020                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11021             }
11022         }else{
11023             if(this.currentTabWidth < this.preferredTabWidth){
11024                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11025             }
11026         }
11027     },
11028
11029     /**
11030      * Returns the number of tabs in this TabPanel.
11031      * @return {Number}
11032      */
11033      getCount : function(){
11034          return this.items.length;
11035      },
11036
11037     /**
11038      * Resizes all the tabs to the passed width
11039      * @param {Number} The new width
11040      */
11041     setTabWidth : function(width){
11042         this.currentTabWidth = width;
11043         for(var i = 0, len = this.items.length; i < len; i++) {
11044                 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11045         }
11046     },
11047
11048     /**
11049      * Destroys this TabPanel
11050      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11051      */
11052     destroy : function(removeEl){
11053         Roo.EventManager.removeResizeListener(this.onResize, this);
11054         for(var i = 0, len = this.items.length; i < len; i++){
11055             this.items[i].purgeListeners();
11056         }
11057         if(removeEl === true){
11058             this.el.update("");
11059             this.el.remove();
11060         }
11061     }
11062 });
11063
11064 /**
11065  * @class Roo.TabPanelItem
11066  * @extends Roo.util.Observable
11067  * Represents an individual item (tab plus body) in a TabPanel.
11068  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11069  * @param {String} id The id of this TabPanelItem
11070  * @param {String} text The text for the tab of this TabPanelItem
11071  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11072  */
11073 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11074     /**
11075      * The {@link Roo.TabPanel} this TabPanelItem belongs to
11076      * @type Roo.TabPanel
11077      */
11078     this.tabPanel = tabPanel;
11079     /**
11080      * The id for this TabPanelItem
11081      * @type String
11082      */
11083     this.id = id;
11084     /** @private */
11085     this.disabled = false;
11086     /** @private */
11087     this.text = text;
11088     /** @private */
11089     this.loaded = false;
11090     this.closable = closable;
11091
11092     /**
11093      * The body element for this TabPanelItem.
11094      * @type Roo.Element
11095      */
11096     this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11097     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11098     this.bodyEl.setStyle("display", "block");
11099     this.bodyEl.setStyle("zoom", "1");
11100     this.hideAction();
11101
11102     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11103     /** @private */
11104     this.el = Roo.get(els.el, true);
11105     this.inner = Roo.get(els.inner, true);
11106     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11107     this.pnode = Roo.get(els.el.parentNode, true);
11108     this.el.on("mousedown", this.onTabMouseDown, this);
11109     this.el.on("click", this.onTabClick, this);
11110     /** @private */
11111     if(closable){
11112         var c = Roo.get(els.close, true);
11113         c.dom.title = this.closeText;
11114         c.addClassOnOver("close-over");
11115         c.on("click", this.closeClick, this);
11116      }
11117
11118     this.addEvents({
11119          /**
11120          * @event activate
11121          * Fires when this tab becomes the active tab.
11122          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11123          * @param {Roo.TabPanelItem} this
11124          */
11125         "activate": true,
11126         /**
11127          * @event beforeclose
11128          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11129          * @param {Roo.TabPanelItem} this
11130          * @param {Object} e Set cancel to true on this object to cancel the close.
11131          */
11132         "beforeclose": true,
11133         /**
11134          * @event close
11135          * Fires when this tab is closed.
11136          * @param {Roo.TabPanelItem} this
11137          */
11138          "close": true,
11139         /**
11140          * @event deactivate
11141          * Fires when this tab is no longer the active tab.
11142          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11143          * @param {Roo.TabPanelItem} this
11144          */
11145          "deactivate" : true
11146     });
11147     this.hidden = false;
11148
11149     Roo.TabPanelItem.superclass.constructor.call(this);
11150 };
11151
11152 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11153     purgeListeners : function(){
11154        Roo.util.Observable.prototype.purgeListeners.call(this);
11155        this.el.removeAllListeners();
11156     },
11157     /**
11158      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11159      */
11160     show : function(){
11161         this.pnode.addClass("on");
11162         this.showAction();
11163         if(Roo.isOpera){
11164             this.tabPanel.stripWrap.repaint();
11165         }
11166         this.fireEvent("activate", this.tabPanel, this);
11167     },
11168
11169     /**
11170      * Returns true if this tab is the active tab.
11171      * @return {Boolean}
11172      */
11173     isActive : function(){
11174         return this.tabPanel.getActiveTab() == this;
11175     },
11176
11177     /**
11178      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11179      */
11180     hide : function(){
11181         this.pnode.removeClass("on");
11182         this.hideAction();
11183         this.fireEvent("deactivate", this.tabPanel, this);
11184     },
11185
11186     hideAction : function(){
11187         this.bodyEl.hide();
11188         this.bodyEl.setStyle("position", "absolute");
11189         this.bodyEl.setLeft("-20000px");
11190         this.bodyEl.setTop("-20000px");
11191     },
11192
11193     showAction : function(){
11194         this.bodyEl.setStyle("position", "relative");
11195         this.bodyEl.setTop("");
11196         this.bodyEl.setLeft("");
11197         this.bodyEl.show();
11198     },
11199
11200     /**
11201      * Set the tooltip for the tab.
11202      * @param {String} tooltip The tab's tooltip
11203      */
11204     setTooltip : function(text){
11205         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11206             this.textEl.dom.qtip = text;
11207             this.textEl.dom.removeAttribute('title');
11208         }else{
11209             this.textEl.dom.title = text;
11210         }
11211     },
11212
11213     onTabClick : function(e){
11214         e.preventDefault();
11215         this.tabPanel.activate(this.id);
11216     },
11217
11218     onTabMouseDown : function(e){
11219         e.preventDefault();
11220         this.tabPanel.activate(this.id);
11221     },
11222
11223     getWidth : function(){
11224         return this.inner.getWidth();
11225     },
11226
11227     setWidth : function(width){
11228         var iwidth = width - this.pnode.getPadding("lr");
11229         this.inner.setWidth(iwidth);
11230         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11231         this.pnode.setWidth(width);
11232     },
11233
11234     /**
11235      * Show or hide the tab
11236      * @param {Boolean} hidden True to hide or false to show.
11237      */
11238     setHidden : function(hidden){
11239         this.hidden = hidden;
11240         this.pnode.setStyle("display", hidden ? "none" : "");
11241     },
11242
11243     /**
11244      * Returns true if this tab is "hidden"
11245      * @return {Boolean}
11246      */
11247     isHidden : function(){
11248         return this.hidden;
11249     },
11250
11251     /**
11252      * Returns the text for this tab
11253      * @return {String}
11254      */
11255     getText : function(){
11256         return this.text;
11257     },
11258
11259     autoSize : function(){
11260         //this.el.beginMeasure();
11261         this.textEl.setWidth(1);
11262         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11263         //this.el.endMeasure();
11264     },
11265
11266     /**
11267      * Sets the text for the tab (Note: this also sets the tooltip text)
11268      * @param {String} text The tab's text and tooltip
11269      */
11270     setText : function(text){
11271         this.text = text;
11272         this.textEl.update(text);
11273         this.setTooltip(text);
11274         if(!this.tabPanel.resizeTabs){
11275             this.autoSize();
11276         }
11277     },
11278     /**
11279      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11280      */
11281     activate : function(){
11282         this.tabPanel.activate(this.id);
11283     },
11284
11285     /**
11286      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11287      */
11288     disable : function(){
11289         if(this.tabPanel.active != this){
11290             this.disabled = true;
11291             this.pnode.addClass("disabled");
11292         }
11293     },
11294
11295     /**
11296      * Enables this TabPanelItem if it was previously disabled.
11297      */
11298     enable : function(){
11299         this.disabled = false;
11300         this.pnode.removeClass("disabled");
11301     },
11302
11303     /**
11304      * Sets the content for this TabPanelItem.
11305      * @param {String} content The content
11306      * @param {Boolean} loadScripts true to look for and load scripts
11307      */
11308     setContent : function(content, loadScripts){
11309         this.bodyEl.update(content, loadScripts);
11310     },
11311
11312     /**
11313      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11314      * @return {Roo.UpdateManager} The UpdateManager
11315      */
11316     getUpdateManager : function(){
11317         return this.bodyEl.getUpdateManager();
11318     },
11319
11320     /**
11321      * Set a URL to be used to load the content for this TabPanelItem.
11322      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11323      * @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)
11324      * @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)
11325      * @return {Roo.UpdateManager} The UpdateManager
11326      */
11327     setUrl : function(url, params, loadOnce){
11328         if(this.refreshDelegate){
11329             this.un('activate', this.refreshDelegate);
11330         }
11331         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11332         this.on("activate", this.refreshDelegate);
11333         return this.bodyEl.getUpdateManager();
11334     },
11335
11336     /** @private */
11337     _handleRefresh : function(url, params, loadOnce){
11338         if(!loadOnce || !this.loaded){
11339             var updater = this.bodyEl.getUpdateManager();
11340             updater.update(url, params, this._setLoaded.createDelegate(this));
11341         }
11342     },
11343
11344     /**
11345      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
11346      *   Will fail silently if the setUrl method has not been called.
11347      *   This does not activate the panel, just updates its content.
11348      */
11349     refresh : function(){
11350         if(this.refreshDelegate){
11351            this.loaded = false;
11352            this.refreshDelegate();
11353         }
11354     },
11355
11356     /** @private */
11357     _setLoaded : function(){
11358         this.loaded = true;
11359     },
11360
11361     /** @private */
11362     closeClick : function(e){
11363         var o = {};
11364         e.stopEvent();
11365         this.fireEvent("beforeclose", this, o);
11366         if(o.cancel !== true){
11367             this.tabPanel.removeTab(this.id);
11368         }
11369     },
11370     /**
11371      * The text displayed in the tooltip for the close icon.
11372      * @type String
11373      */
11374     closeText : "Close this tab"
11375 });
11376
11377 /** @private */
11378 Roo.TabPanel.prototype.createStrip = function(container){
11379     var strip = document.createElement("div");
11380     strip.className = "x-tabs-wrap";
11381     container.appendChild(strip);
11382     return strip;
11383 };
11384 /** @private */
11385 Roo.TabPanel.prototype.createStripList = function(strip){
11386     // div wrapper for retard IE
11387     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>';
11388     return strip.firstChild.firstChild.firstChild.firstChild;
11389 };
11390 /** @private */
11391 Roo.TabPanel.prototype.createBody = function(container){
11392     var body = document.createElement("div");
11393     Roo.id(body, "tab-body");
11394     Roo.fly(body).addClass("x-tabs-body");
11395     container.appendChild(body);
11396     return body;
11397 };
11398 /** @private */
11399 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11400     var body = Roo.getDom(id);
11401     if(!body){
11402         body = document.createElement("div");
11403         body.id = id;
11404     }
11405     Roo.fly(body).addClass("x-tabs-item-body");
11406     bodyEl.insertBefore(body, bodyEl.firstChild);
11407     return body;
11408 };
11409 /** @private */
11410 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11411     var td = document.createElement("td");
11412     stripEl.appendChild(td);
11413     if(closable){
11414         td.className = "x-tabs-closable";
11415         if(!this.closeTpl){
11416             this.closeTpl = new Roo.Template(
11417                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11418                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11419                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
11420             );
11421         }
11422         var el = this.closeTpl.overwrite(td, {"text": text});
11423         var close = el.getElementsByTagName("div")[0];
11424         var inner = el.getElementsByTagName("em")[0];
11425         return {"el": el, "close": close, "inner": inner};
11426     } else {
11427         if(!this.tabTpl){
11428             this.tabTpl = new Roo.Template(
11429                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11430                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11431             );
11432         }
11433         var el = this.tabTpl.overwrite(td, {"text": text});
11434         var inner = el.getElementsByTagName("em")[0];
11435         return {"el": el, "inner": inner};
11436     }
11437 };/*
11438  * Based on:
11439  * Ext JS Library 1.1.1
11440  * Copyright(c) 2006-2007, Ext JS, LLC.
11441  *
11442  * Originally Released Under LGPL - original licence link has changed is not relivant.
11443  *
11444  * Fork - LGPL
11445  * <script type="text/javascript">
11446  */
11447
11448 /**
11449  * @class Roo.Button
11450  * @extends Roo.util.Observable
11451  * Simple Button class
11452  * @cfg {String} text The button text
11453  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11454  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11455  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11456  * @cfg {Object} scope The scope of the handler
11457  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11458  * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11459  * @cfg {Boolean} hidden True to start hidden (defaults to false)
11460  * @cfg {Boolean} disabled True to start disabled (defaults to false)
11461  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11462  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11463    applies if enableToggle = true)
11464  * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11465  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11466   an {@link Roo.util.ClickRepeater} config object (defaults to false).
11467  * @constructor
11468  * Create a new button
11469  * @param {Object} config The config object
11470  */
11471 Roo.Button = function(renderTo, config)
11472 {
11473     if (!config) {
11474         config = renderTo;
11475         renderTo = config.renderTo || false;
11476     }
11477     
11478     Roo.apply(this, config);
11479     this.addEvents({
11480         /**
11481              * @event click
11482              * Fires when this button is clicked
11483              * @param {Button} this
11484              * @param {EventObject} e The click event
11485              */
11486             "click" : true,
11487         /**
11488              * @event toggle
11489              * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11490              * @param {Button} this
11491              * @param {Boolean} pressed
11492              */
11493             "toggle" : true,
11494         /**
11495              * @event mouseover
11496              * Fires when the mouse hovers over the button
11497              * @param {Button} this
11498              * @param {Event} e The event object
11499              */
11500         'mouseover' : true,
11501         /**
11502              * @event mouseout
11503              * Fires when the mouse exits the button
11504              * @param {Button} this
11505              * @param {Event} e The event object
11506              */
11507         'mouseout': true,
11508          /**
11509              * @event render
11510              * Fires when the button is rendered
11511              * @param {Button} this
11512              */
11513         'render': true
11514     });
11515     if(this.menu){
11516         this.menu = Roo.menu.MenuMgr.get(this.menu);
11517     }
11518     // register listeners first!!  - so render can be captured..
11519     Roo.util.Observable.call(this);
11520     if(renderTo){
11521         this.render(renderTo);
11522     }
11523     
11524   
11525 };
11526
11527 Roo.extend(Roo.Button, Roo.util.Observable, {
11528     /**
11529      * 
11530      */
11531     
11532     /**
11533      * Read-only. True if this button is hidden
11534      * @type Boolean
11535      */
11536     hidden : false,
11537     /**
11538      * Read-only. True if this button is disabled
11539      * @type Boolean
11540      */
11541     disabled : false,
11542     /**
11543      * Read-only. True if this button is pressed (only if enableToggle = true)
11544      * @type Boolean
11545      */
11546     pressed : false,
11547
11548     /**
11549      * @cfg {Number} tabIndex 
11550      * The DOM tabIndex for this button (defaults to undefined)
11551      */
11552     tabIndex : undefined,
11553
11554     /**
11555      * @cfg {Boolean} enableToggle
11556      * True to enable pressed/not pressed toggling (defaults to false)
11557      */
11558     enableToggle: false,
11559     /**
11560      * @cfg {Mixed} menu
11561      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11562      */
11563     menu : undefined,
11564     /**
11565      * @cfg {String} menuAlign
11566      * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11567      */
11568     menuAlign : "tl-bl?",
11569
11570     /**
11571      * @cfg {String} iconCls
11572      * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11573      */
11574     iconCls : undefined,
11575     /**
11576      * @cfg {String} type
11577      * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
11578      */
11579     type : 'button',
11580
11581     // private
11582     menuClassTarget: 'tr',
11583
11584     /**
11585      * @cfg {String} clickEvent
11586      * The type of event to map to the button's event handler (defaults to 'click')
11587      */
11588     clickEvent : 'click',
11589
11590     /**
11591      * @cfg {Boolean} handleMouseEvents
11592      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11593      */
11594     handleMouseEvents : true,
11595
11596     /**
11597      * @cfg {String} tooltipType
11598      * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11599      */
11600     tooltipType : 'qtip',
11601
11602     /**
11603      * @cfg {String} cls
11604      * A CSS class to apply to the button's main element.
11605      */
11606     
11607     /**
11608      * @cfg {Roo.Template} template (Optional)
11609      * An {@link Roo.Template} with which to create the Button's main element. This Template must
11610      * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11611      * require code modifications if required elements (e.g. a button) aren't present.
11612      */
11613
11614     // private
11615     render : function(renderTo){
11616         var btn;
11617         if(this.hideParent){
11618             this.parentEl = Roo.get(renderTo);
11619         }
11620         if(!this.dhconfig){
11621             if(!this.template){
11622                 if(!Roo.Button.buttonTemplate){
11623                     // hideous table template
11624                     Roo.Button.buttonTemplate = new Roo.Template(
11625                         '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11626                         '<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>',
11627                         "</tr></tbody></table>");
11628                 }
11629                 this.template = Roo.Button.buttonTemplate;
11630             }
11631             btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
11632             var btnEl = btn.child("button:first");
11633             btnEl.on('focus', this.onFocus, this);
11634             btnEl.on('blur', this.onBlur, this);
11635             if(this.cls){
11636                 btn.addClass(this.cls);
11637             }
11638             if(this.icon){
11639                 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11640             }
11641             if(this.iconCls){
11642                 btnEl.addClass(this.iconCls);
11643                 if(!this.cls){
11644                     btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11645                 }
11646             }
11647             if(this.tabIndex !== undefined){
11648                 btnEl.dom.tabIndex = this.tabIndex;
11649             }
11650             if(this.tooltip){
11651                 if(typeof this.tooltip == 'object'){
11652                     Roo.QuickTips.tips(Roo.apply({
11653                           target: btnEl.id
11654                     }, this.tooltip));
11655                 } else {
11656                     btnEl.dom[this.tooltipType] = this.tooltip;
11657                 }
11658             }
11659         }else{
11660             btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11661         }
11662         this.el = btn;
11663         if(this.id){
11664             this.el.dom.id = this.el.id = this.id;
11665         }
11666         if(this.menu){
11667             this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11668             this.menu.on("show", this.onMenuShow, this);
11669             this.menu.on("hide", this.onMenuHide, this);
11670         }
11671         btn.addClass("x-btn");
11672         if(Roo.isIE && !Roo.isIE7){
11673             this.autoWidth.defer(1, this);
11674         }else{
11675             this.autoWidth();
11676         }
11677         if(this.handleMouseEvents){
11678             btn.on("mouseover", this.onMouseOver, this);
11679             btn.on("mouseout", this.onMouseOut, this);
11680             btn.on("mousedown", this.onMouseDown, this);
11681         }
11682         btn.on(this.clickEvent, this.onClick, this);
11683         //btn.on("mouseup", this.onMouseUp, this);
11684         if(this.hidden){
11685             this.hide();
11686         }
11687         if(this.disabled){
11688             this.disable();
11689         }
11690         Roo.ButtonToggleMgr.register(this);
11691         if(this.pressed){
11692             this.el.addClass("x-btn-pressed");
11693         }
11694         if(this.repeat){
11695             var repeater = new Roo.util.ClickRepeater(btn,
11696                 typeof this.repeat == "object" ? this.repeat : {}
11697             );
11698             repeater.on("click", this.onClick,  this);
11699         }
11700         
11701         this.fireEvent('render', this);
11702         
11703     },
11704     /**
11705      * Returns the button's underlying element
11706      * @return {Roo.Element} The element
11707      */
11708     getEl : function(){
11709         return this.el;  
11710     },
11711     
11712     /**
11713      * Destroys this Button and removes any listeners.
11714      */
11715     destroy : function(){
11716         Roo.ButtonToggleMgr.unregister(this);
11717         this.el.removeAllListeners();
11718         this.purgeListeners();
11719         this.el.remove();
11720     },
11721
11722     // private
11723     autoWidth : function(){
11724         if(this.el){
11725             this.el.setWidth("auto");
11726             if(Roo.isIE7 && Roo.isStrict){
11727                 var ib = this.el.child('button');
11728                 if(ib && ib.getWidth() > 20){
11729                     ib.clip();
11730                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11731                 }
11732             }
11733             if(this.minWidth){
11734                 if(this.hidden){
11735                     this.el.beginMeasure();
11736                 }
11737                 if(this.el.getWidth() < this.minWidth){
11738                     this.el.setWidth(this.minWidth);
11739                 }
11740                 if(this.hidden){
11741                     this.el.endMeasure();
11742                 }
11743             }
11744         }
11745     },
11746
11747     /**
11748      * Assigns this button's click handler
11749      * @param {Function} handler The function to call when the button is clicked
11750      * @param {Object} scope (optional) Scope for the function passed in
11751      */
11752     setHandler : function(handler, scope){
11753         this.handler = handler;
11754         this.scope = scope;  
11755     },
11756     
11757     /**
11758      * Sets this button's text
11759      * @param {String} text The button text
11760      */
11761     setText : function(text){
11762         this.text = text;
11763         if(this.el){
11764             this.el.child("td.x-btn-center button.x-btn-text").update(text);
11765         }
11766         this.autoWidth();
11767     },
11768     
11769     /**
11770      * Gets the text for this button
11771      * @return {String} The button text
11772      */
11773     getText : function(){
11774         return this.text;  
11775     },
11776     
11777     /**
11778      * Show this button
11779      */
11780     show: function(){
11781         this.hidden = false;
11782         if(this.el){
11783             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11784         }
11785     },
11786     
11787     /**
11788      * Hide this button
11789      */
11790     hide: function(){
11791         this.hidden = true;
11792         if(this.el){
11793             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11794         }
11795     },
11796     
11797     /**
11798      * Convenience function for boolean show/hide
11799      * @param {Boolean} visible True to show, false to hide
11800      */
11801     setVisible: function(visible){
11802         if(visible) {
11803             this.show();
11804         }else{
11805             this.hide();
11806         }
11807     },
11808     
11809     /**
11810      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11811      * @param {Boolean} state (optional) Force a particular state
11812      */
11813     toggle : function(state){
11814         state = state === undefined ? !this.pressed : state;
11815         if(state != this.pressed){
11816             if(state){
11817                 this.el.addClass("x-btn-pressed");
11818                 this.pressed = true;
11819                 this.fireEvent("toggle", this, true);
11820             }else{
11821                 this.el.removeClass("x-btn-pressed");
11822                 this.pressed = false;
11823                 this.fireEvent("toggle", this, false);
11824             }
11825             if(this.toggleHandler){
11826                 this.toggleHandler.call(this.scope || this, this, state);
11827             }
11828         }
11829     },
11830     
11831     /**
11832      * Focus the button
11833      */
11834     focus : function(){
11835         this.el.child('button:first').focus();
11836     },
11837     
11838     /**
11839      * Disable this button
11840      */
11841     disable : function(){
11842         if(this.el){
11843             this.el.addClass("x-btn-disabled");
11844         }
11845         this.disabled = true;
11846     },
11847     
11848     /**
11849      * Enable this button
11850      */
11851     enable : function(){
11852         if(this.el){
11853             this.el.removeClass("x-btn-disabled");
11854         }
11855         this.disabled = false;
11856     },
11857
11858     /**
11859      * Convenience function for boolean enable/disable
11860      * @param {Boolean} enabled True to enable, false to disable
11861      */
11862     setDisabled : function(v){
11863         this[v !== true ? "enable" : "disable"]();
11864     },
11865
11866     // private
11867     onClick : function(e){
11868         if(e){
11869             e.preventDefault();
11870         }
11871         if(e.button != 0){
11872             return;
11873         }
11874         if(!this.disabled){
11875             if(this.enableToggle){
11876                 this.toggle();
11877             }
11878             if(this.menu && !this.menu.isVisible()){
11879                 this.menu.show(this.el, this.menuAlign);
11880             }
11881             this.fireEvent("click", this, e);
11882             if(this.handler){
11883                 this.el.removeClass("x-btn-over");
11884                 this.handler.call(this.scope || this, this, e);
11885             }
11886         }
11887     },
11888     // private
11889     onMouseOver : function(e){
11890         if(!this.disabled){
11891             this.el.addClass("x-btn-over");
11892             this.fireEvent('mouseover', this, e);
11893         }
11894     },
11895     // private
11896     onMouseOut : function(e){
11897         if(!e.within(this.el,  true)){
11898             this.el.removeClass("x-btn-over");
11899             this.fireEvent('mouseout', this, e);
11900         }
11901     },
11902     // private
11903     onFocus : function(e){
11904         if(!this.disabled){
11905             this.el.addClass("x-btn-focus");
11906         }
11907     },
11908     // private
11909     onBlur : function(e){
11910         this.el.removeClass("x-btn-focus");
11911     },
11912     // private
11913     onMouseDown : function(e){
11914         if(!this.disabled && e.button == 0){
11915             this.el.addClass("x-btn-click");
11916             Roo.get(document).on('mouseup', this.onMouseUp, this);
11917         }
11918     },
11919     // private
11920     onMouseUp : function(e){
11921         if(e.button == 0){
11922             this.el.removeClass("x-btn-click");
11923             Roo.get(document).un('mouseup', this.onMouseUp, this);
11924         }
11925     },
11926     // private
11927     onMenuShow : function(e){
11928         this.el.addClass("x-btn-menu-active");
11929     },
11930     // private
11931     onMenuHide : function(e){
11932         this.el.removeClass("x-btn-menu-active");
11933     }   
11934 });
11935
11936 // Private utility class used by Button
11937 Roo.ButtonToggleMgr = function(){
11938    var groups = {};
11939    
11940    function toggleGroup(btn, state){
11941        if(state){
11942            var g = groups[btn.toggleGroup];
11943            for(var i = 0, l = g.length; i < l; i++){
11944                if(g[i] != btn){
11945                    g[i].toggle(false);
11946                }
11947            }
11948        }
11949    }
11950    
11951    return {
11952        register : function(btn){
11953            if(!btn.toggleGroup){
11954                return;
11955            }
11956            var g = groups[btn.toggleGroup];
11957            if(!g){
11958                g = groups[btn.toggleGroup] = [];
11959            }
11960            g.push(btn);
11961            btn.on("toggle", toggleGroup);
11962        },
11963        
11964        unregister : function(btn){
11965            if(!btn.toggleGroup){
11966                return;
11967            }
11968            var g = groups[btn.toggleGroup];
11969            if(g){
11970                g.remove(btn);
11971                btn.un("toggle", toggleGroup);
11972            }
11973        }
11974    };
11975 }();/*
11976  * Based on:
11977  * Ext JS Library 1.1.1
11978  * Copyright(c) 2006-2007, Ext JS, LLC.
11979  *
11980  * Originally Released Under LGPL - original licence link has changed is not relivant.
11981  *
11982  * Fork - LGPL
11983  * <script type="text/javascript">
11984  */
11985  
11986 /**
11987  * @class Roo.SplitButton
11988  * @extends Roo.Button
11989  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11990  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
11991  * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11992  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11993  * @cfg {String} arrowTooltip The title attribute of the arrow
11994  * @constructor
11995  * Create a new menu button
11996  * @param {String/HTMLElement/Element} renderTo The element to append the button to
11997  * @param {Object} config The config object
11998  */
11999 Roo.SplitButton = function(renderTo, config){
12000     Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12001     /**
12002      * @event arrowclick
12003      * Fires when this button's arrow is clicked
12004      * @param {SplitButton} this
12005      * @param {EventObject} e The click event
12006      */
12007     this.addEvents({"arrowclick":true});
12008 };
12009
12010 Roo.extend(Roo.SplitButton, Roo.Button, {
12011     render : function(renderTo){
12012         // this is one sweet looking template!
12013         var tpl = new Roo.Template(
12014             '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12015             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12016             '<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>',
12017             "</tbody></table></td><td>",
12018             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12019             '<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>',
12020             "</tbody></table></td></tr></table>"
12021         );
12022         var btn = tpl.append(renderTo, [this.text, this.type], true);
12023         var btnEl = btn.child("button");
12024         if(this.cls){
12025             btn.addClass(this.cls);
12026         }
12027         if(this.icon){
12028             btnEl.setStyle('background-image', 'url(' +this.icon +')');
12029         }
12030         if(this.iconCls){
12031             btnEl.addClass(this.iconCls);
12032             if(!this.cls){
12033                 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12034             }
12035         }
12036         this.el = btn;
12037         if(this.handleMouseEvents){
12038             btn.on("mouseover", this.onMouseOver, this);
12039             btn.on("mouseout", this.onMouseOut, this);
12040             btn.on("mousedown", this.onMouseDown, this);
12041             btn.on("mouseup", this.onMouseUp, this);
12042         }
12043         btn.on(this.clickEvent, this.onClick, this);
12044         if(this.tooltip){
12045             if(typeof this.tooltip == 'object'){
12046                 Roo.QuickTips.tips(Roo.apply({
12047                       target: btnEl.id
12048                 }, this.tooltip));
12049             } else {
12050                 btnEl.dom[this.tooltipType] = this.tooltip;
12051             }
12052         }
12053         if(this.arrowTooltip){
12054             btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12055         }
12056         if(this.hidden){
12057             this.hide();
12058         }
12059         if(this.disabled){
12060             this.disable();
12061         }
12062         if(this.pressed){
12063             this.el.addClass("x-btn-pressed");
12064         }
12065         if(Roo.isIE && !Roo.isIE7){
12066             this.autoWidth.defer(1, this);
12067         }else{
12068             this.autoWidth();
12069         }
12070         if(this.menu){
12071             this.menu.on("show", this.onMenuShow, this);
12072             this.menu.on("hide", this.onMenuHide, this);
12073         }
12074         this.fireEvent('render', this);
12075     },
12076
12077     // private
12078     autoWidth : function(){
12079         if(this.el){
12080             var tbl = this.el.child("table:first");
12081             var tbl2 = this.el.child("table:last");
12082             this.el.setWidth("auto");
12083             tbl.setWidth("auto");
12084             if(Roo.isIE7 && Roo.isStrict){
12085                 var ib = this.el.child('button:first');
12086                 if(ib && ib.getWidth() > 20){
12087                     ib.clip();
12088                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12089                 }
12090             }
12091             if(this.minWidth){
12092                 if(this.hidden){
12093                     this.el.beginMeasure();
12094                 }
12095                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12096                     tbl.setWidth(this.minWidth-tbl2.getWidth());
12097                 }
12098                 if(this.hidden){
12099                     this.el.endMeasure();
12100                 }
12101             }
12102             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12103         } 
12104     },
12105     /**
12106      * Sets this button's click handler
12107      * @param {Function} handler The function to call when the button is clicked
12108      * @param {Object} scope (optional) Scope for the function passed above
12109      */
12110     setHandler : function(handler, scope){
12111         this.handler = handler;
12112         this.scope = scope;  
12113     },
12114     
12115     /**
12116      * Sets this button's arrow click handler
12117      * @param {Function} handler The function to call when the arrow is clicked
12118      * @param {Object} scope (optional) Scope for the function passed above
12119      */
12120     setArrowHandler : function(handler, scope){
12121         this.arrowHandler = handler;
12122         this.scope = scope;  
12123     },
12124     
12125     /**
12126      * Focus the button
12127      */
12128     focus : function(){
12129         if(this.el){
12130             this.el.child("button:first").focus();
12131         }
12132     },
12133
12134     // private
12135     onClick : function(e){
12136         e.preventDefault();
12137         if(!this.disabled){
12138             if(e.getTarget(".x-btn-menu-arrow-wrap")){
12139                 if(this.menu && !this.menu.isVisible()){
12140                     this.menu.show(this.el, this.menuAlign);
12141                 }
12142                 this.fireEvent("arrowclick", this, e);
12143                 if(this.arrowHandler){
12144                     this.arrowHandler.call(this.scope || this, this, e);
12145                 }
12146             }else{
12147                 this.fireEvent("click", this, e);
12148                 if(this.handler){
12149                     this.handler.call(this.scope || this, this, e);
12150                 }
12151             }
12152         }
12153     },
12154     // private
12155     onMouseDown : function(e){
12156         if(!this.disabled){
12157             Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12158         }
12159     },
12160     // private
12161     onMouseUp : function(e){
12162         Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12163     }   
12164 });
12165
12166
12167 // backwards compat
12168 Roo.MenuButton = Roo.SplitButton;/*
12169  * Based on:
12170  * Ext JS Library 1.1.1
12171  * Copyright(c) 2006-2007, Ext JS, LLC.
12172  *
12173  * Originally Released Under LGPL - original licence link has changed is not relivant.
12174  *
12175  * Fork - LGPL
12176  * <script type="text/javascript">
12177  */
12178
12179 /**
12180  * @class Roo.Toolbar
12181  * Basic Toolbar class.
12182  * @constructor
12183  * Creates a new Toolbar
12184  * @param {Object} config The config object
12185  */ 
12186 Roo.Toolbar = function(container, buttons, config)
12187 {
12188     /// old consturctor format still supported..
12189     if(container instanceof Array){ // omit the container for later rendering
12190         buttons = container;
12191         config = buttons;
12192         container = null;
12193     }
12194     if (typeof(container) == 'object' && container.xtype) {
12195         config = container;
12196         container = config.container;
12197         buttons = config.buttons; // not really - use items!!
12198     }
12199     var xitems = [];
12200     if (config && config.items) {
12201         xitems = config.items;
12202         delete config.items;
12203     }
12204     Roo.apply(this, config);
12205     this.buttons = buttons;
12206     
12207     if(container){
12208         this.render(container);
12209     }
12210     Roo.each(xitems, function(b) {
12211         this.add(b);
12212     }, this);
12213     
12214 };
12215
12216 Roo.Toolbar.prototype = {
12217     /**
12218      * @cfg {Roo.data.Store} items
12219      * array of button configs or elements to add
12220      */
12221     
12222     /**
12223      * @cfg {String/HTMLElement/Element} container
12224      * The id or element that will contain the toolbar
12225      */
12226     // private
12227     render : function(ct){
12228         this.el = Roo.get(ct);
12229         if(this.cls){
12230             this.el.addClass(this.cls);
12231         }
12232         // using a table allows for vertical alignment
12233         // 100% width is needed by Safari...
12234         this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12235         this.tr = this.el.child("tr", true);
12236         var autoId = 0;
12237         this.items = new Roo.util.MixedCollection(false, function(o){
12238             return o.id || ("item" + (++autoId));
12239         });
12240         if(this.buttons){
12241             this.add.apply(this, this.buttons);
12242             delete this.buttons;
12243         }
12244     },
12245
12246     /**
12247      * Adds element(s) to the toolbar -- this function takes a variable number of 
12248      * arguments of mixed type and adds them to the toolbar.
12249      * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12250      * <ul>
12251      * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12252      * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12253      * <li>Field: Any form field (equivalent to {@link #addField})</li>
12254      * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12255      * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12256      * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12257      * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12258      * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12259      * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12260      * </ul>
12261      * @param {Mixed} arg2
12262      * @param {Mixed} etc.
12263      */
12264     add : function(){
12265         var a = arguments, l = a.length;
12266         for(var i = 0; i < l; i++){
12267             this._add(a[i]);
12268         }
12269     },
12270     // private..
12271     _add : function(el) {
12272         
12273         if (el.xtype) {
12274             el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12275         }
12276         
12277         if (el.applyTo){ // some kind of form field
12278             return this.addField(el);
12279         } 
12280         if (el.render){ // some kind of Toolbar.Item
12281             return this.addItem(el);
12282         }
12283         if (typeof el == "string"){ // string
12284             if(el == "separator" || el == "-"){
12285                 return this.addSeparator();
12286             }
12287             if (el == " "){
12288                 return this.addSpacer();
12289             }
12290             if(el == "->"){
12291                 return this.addFill();
12292             }
12293             return this.addText(el);
12294             
12295         }
12296         if(el.tagName){ // element
12297             return this.addElement(el);
12298         }
12299         if(typeof el == "object"){ // must be button config?
12300             return this.addButton(el);
12301         }
12302         // and now what?!?!
12303         return false;
12304         
12305     },
12306     
12307     /**
12308      * Add an Xtype element
12309      * @param {Object} xtype Xtype Object
12310      * @return {Object} created Object
12311      */
12312     addxtype : function(e){
12313         return this.add(e);  
12314     },
12315     
12316     /**
12317      * Returns the Element for this toolbar.
12318      * @return {Roo.Element}
12319      */
12320     getEl : function(){
12321         return this.el;  
12322     },
12323     
12324     /**
12325      * Adds a separator
12326      * @return {Roo.Toolbar.Item} The separator item
12327      */
12328     addSeparator : function(){
12329         return this.addItem(new Roo.Toolbar.Separator());
12330     },
12331
12332     /**
12333      * Adds a spacer element
12334      * @return {Roo.Toolbar.Spacer} The spacer item
12335      */
12336     addSpacer : function(){
12337         return this.addItem(new Roo.Toolbar.Spacer());
12338     },
12339
12340     /**
12341      * Adds a fill element that forces subsequent additions to the right side of the toolbar
12342      * @return {Roo.Toolbar.Fill} The fill item
12343      */
12344     addFill : function(){
12345         return this.addItem(new Roo.Toolbar.Fill());
12346     },
12347
12348     /**
12349      * Adds any standard HTML element to the toolbar
12350      * @param {String/HTMLElement/Element} el The element or id of the element to add
12351      * @return {Roo.Toolbar.Item} The element's item
12352      */
12353     addElement : function(el){
12354         return this.addItem(new Roo.Toolbar.Item(el));
12355     },
12356     /**
12357      * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12358      * @type Roo.util.MixedCollection  
12359      */
12360     items : false,
12361      
12362     /**
12363      * Adds any Toolbar.Item or subclass
12364      * @param {Roo.Toolbar.Item} item
12365      * @return {Roo.Toolbar.Item} The item
12366      */
12367     addItem : function(item){
12368         var td = this.nextBlock();
12369         item.render(td);
12370         this.items.add(item);
12371         return item;
12372     },
12373     
12374     /**
12375      * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12376      * @param {Object/Array} config A button config or array of configs
12377      * @return {Roo.Toolbar.Button/Array}
12378      */
12379     addButton : function(config){
12380         if(config instanceof Array){
12381             var buttons = [];
12382             for(var i = 0, len = config.length; i < len; i++) {
12383                 buttons.push(this.addButton(config[i]));
12384             }
12385             return buttons;
12386         }
12387         var b = config;
12388         if(!(config instanceof Roo.Toolbar.Button)){
12389             b = config.split ?
12390                 new Roo.Toolbar.SplitButton(config) :
12391                 new Roo.Toolbar.Button(config);
12392         }
12393         var td = this.nextBlock();
12394         b.render(td);
12395         this.items.add(b);
12396         return b;
12397     },
12398     
12399     /**
12400      * Adds text to the toolbar
12401      * @param {String} text The text to add
12402      * @return {Roo.Toolbar.Item} The element's item
12403      */
12404     addText : function(text){
12405         return this.addItem(new Roo.Toolbar.TextItem(text));
12406     },
12407     
12408     /**
12409      * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12410      * @param {Number} index The index where the item is to be inserted
12411      * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12412      * @return {Roo.Toolbar.Button/Item}
12413      */
12414     insertButton : function(index, item){
12415         if(item instanceof Array){
12416             var buttons = [];
12417             for(var i = 0, len = item.length; i < len; i++) {
12418                buttons.push(this.insertButton(index + i, item[i]));
12419             }
12420             return buttons;
12421         }
12422         if (!(item instanceof Roo.Toolbar.Button)){
12423            item = new Roo.Toolbar.Button(item);
12424         }
12425         var td = document.createElement("td");
12426         this.tr.insertBefore(td, this.tr.childNodes[index]);
12427         item.render(td);
12428         this.items.insert(index, item);
12429         return item;
12430     },
12431     
12432     /**
12433      * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12434      * @param {Object} config
12435      * @return {Roo.Toolbar.Item} The element's item
12436      */
12437     addDom : function(config, returnEl){
12438         var td = this.nextBlock();
12439         Roo.DomHelper.overwrite(td, config);
12440         var ti = new Roo.Toolbar.Item(td.firstChild);
12441         ti.render(td);
12442         this.items.add(ti);
12443         return ti;
12444     },
12445
12446     /**
12447      * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12448      * @type Roo.util.MixedCollection  
12449      */
12450     fields : false,
12451     
12452     /**
12453      * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12454      * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12455      * @param {Roo.form.Field} field
12456      * @return {Roo.ToolbarItem}
12457      */
12458      
12459       
12460     addField : function(field) {
12461         if (!this.fields) {
12462             var autoId = 0;
12463             this.fields = new Roo.util.MixedCollection(false, function(o){
12464                 return o.id || ("item" + (++autoId));
12465             });
12466
12467         }
12468         
12469         var td = this.nextBlock();
12470         field.render(td);
12471         var ti = new Roo.Toolbar.Item(td.firstChild);
12472         ti.render(td);
12473         this.items.add(ti);
12474         this.fields.add(field);
12475         return ti;
12476     },
12477     /**
12478      * Hide the toolbar
12479      * @method hide
12480      */
12481      
12482       
12483     hide : function()
12484     {
12485         this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12486         this.el.child('div').hide();
12487     },
12488     /**
12489      * Show the toolbar
12490      * @method show
12491      */
12492     show : function()
12493     {
12494         this.el.child('div').show();
12495     },
12496       
12497     // private
12498     nextBlock : function(){
12499         var td = document.createElement("td");
12500         this.tr.appendChild(td);
12501         return td;
12502     },
12503
12504     // private
12505     destroy : function(){
12506         if(this.items){ // rendered?
12507             Roo.destroy.apply(Roo, this.items.items);
12508         }
12509         if(this.fields){ // rendered?
12510             Roo.destroy.apply(Roo, this.fields.items);
12511         }
12512         Roo.Element.uncache(this.el, this.tr);
12513     }
12514 };
12515
12516 /**
12517  * @class Roo.Toolbar.Item
12518  * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12519  * @constructor
12520  * Creates a new Item
12521  * @param {HTMLElement} el 
12522  */
12523 Roo.Toolbar.Item = function(el){
12524     this.el = Roo.getDom(el);
12525     this.id = Roo.id(this.el);
12526     this.hidden = false;
12527 };
12528
12529 Roo.Toolbar.Item.prototype = {
12530     
12531     /**
12532      * Get this item's HTML Element
12533      * @return {HTMLElement}
12534      */
12535     getEl : function(){
12536        return this.el;  
12537     },
12538
12539     // private
12540     render : function(td){
12541         this.td = td;
12542         td.appendChild(this.el);
12543     },
12544     
12545     /**
12546      * Removes and destroys this item.
12547      */
12548     destroy : function(){
12549         this.td.parentNode.removeChild(this.td);
12550     },
12551     
12552     /**
12553      * Shows this item.
12554      */
12555     show: function(){
12556         this.hidden = false;
12557         this.td.style.display = "";
12558     },
12559     
12560     /**
12561      * Hides this item.
12562      */
12563     hide: function(){
12564         this.hidden = true;
12565         this.td.style.display = "none";
12566     },
12567     
12568     /**
12569      * Convenience function for boolean show/hide.
12570      * @param {Boolean} visible true to show/false to hide
12571      */
12572     setVisible: function(visible){
12573         if(visible) {
12574             this.show();
12575         }else{
12576             this.hide();
12577         }
12578     },
12579     
12580     /**
12581      * Try to focus this item.
12582      */
12583     focus : function(){
12584         Roo.fly(this.el).focus();
12585     },
12586     
12587     /**
12588      * Disables this item.
12589      */
12590     disable : function(){
12591         Roo.fly(this.td).addClass("x-item-disabled");
12592         this.disabled = true;
12593         this.el.disabled = true;
12594     },
12595     
12596     /**
12597      * Enables this item.
12598      */
12599     enable : function(){
12600         Roo.fly(this.td).removeClass("x-item-disabled");
12601         this.disabled = false;
12602         this.el.disabled = false;
12603     }
12604 };
12605
12606
12607 /**
12608  * @class Roo.Toolbar.Separator
12609  * @extends Roo.Toolbar.Item
12610  * A simple toolbar separator class
12611  * @constructor
12612  * Creates a new Separator
12613  */
12614 Roo.Toolbar.Separator = function(){
12615     var s = document.createElement("span");
12616     s.className = "ytb-sep";
12617     Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12618 };
12619 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12620     enable:Roo.emptyFn,
12621     disable:Roo.emptyFn,
12622     focus:Roo.emptyFn
12623 });
12624
12625 /**
12626  * @class Roo.Toolbar.Spacer
12627  * @extends Roo.Toolbar.Item
12628  * A simple element that adds extra horizontal space to a toolbar.
12629  * @constructor
12630  * Creates a new Spacer
12631  */
12632 Roo.Toolbar.Spacer = function(){
12633     var s = document.createElement("div");
12634     s.className = "ytb-spacer";
12635     Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12636 };
12637 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12638     enable:Roo.emptyFn,
12639     disable:Roo.emptyFn,
12640     focus:Roo.emptyFn
12641 });
12642
12643 /**
12644  * @class Roo.Toolbar.Fill
12645  * @extends Roo.Toolbar.Spacer
12646  * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12647  * @constructor
12648  * Creates a new Spacer
12649  */
12650 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12651     // private
12652     render : function(td){
12653         td.style.width = '100%';
12654         Roo.Toolbar.Fill.superclass.render.call(this, td);
12655     }
12656 });
12657
12658 /**
12659  * @class Roo.Toolbar.TextItem
12660  * @extends Roo.Toolbar.Item
12661  * A simple class that renders text directly into a toolbar.
12662  * @constructor
12663  * Creates a new TextItem
12664  * @param {String} text
12665  */
12666 Roo.Toolbar.TextItem = function(text){
12667     if (typeof(text) == 'object') {
12668         text = text.text;
12669     }
12670     var s = document.createElement("span");
12671     s.className = "ytb-text";
12672     s.innerHTML = text;
12673     Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12674 };
12675 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12676     enable:Roo.emptyFn,
12677     disable:Roo.emptyFn,
12678     focus:Roo.emptyFn
12679 });
12680
12681 /**
12682  * @class Roo.Toolbar.Button
12683  * @extends Roo.Button
12684  * A button that renders into a toolbar.
12685  * @constructor
12686  * Creates a new Button
12687  * @param {Object} config A standard {@link Roo.Button} config object
12688  */
12689 Roo.Toolbar.Button = function(config){
12690     Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12691 };
12692 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12693     render : function(td){
12694         this.td = td;
12695         Roo.Toolbar.Button.superclass.render.call(this, td);
12696     },
12697     
12698     /**
12699      * Removes and destroys this button
12700      */
12701     destroy : function(){
12702         Roo.Toolbar.Button.superclass.destroy.call(this);
12703         this.td.parentNode.removeChild(this.td);
12704     },
12705     
12706     /**
12707      * Shows this button
12708      */
12709     show: function(){
12710         this.hidden = false;
12711         this.td.style.display = "";
12712     },
12713     
12714     /**
12715      * Hides this button
12716      */
12717     hide: function(){
12718         this.hidden = true;
12719         this.td.style.display = "none";
12720     },
12721
12722     /**
12723      * Disables this item
12724      */
12725     disable : function(){
12726         Roo.fly(this.td).addClass("x-item-disabled");
12727         this.disabled = true;
12728     },
12729
12730     /**
12731      * Enables this item
12732      */
12733     enable : function(){
12734         Roo.fly(this.td).removeClass("x-item-disabled");
12735         this.disabled = false;
12736     }
12737 });
12738 // backwards compat
12739 Roo.ToolbarButton = Roo.Toolbar.Button;
12740
12741 /**
12742  * @class Roo.Toolbar.SplitButton
12743  * @extends Roo.SplitButton
12744  * A menu button that renders into a toolbar.
12745  * @constructor
12746  * Creates a new SplitButton
12747  * @param {Object} config A standard {@link Roo.SplitButton} config object
12748  */
12749 Roo.Toolbar.SplitButton = function(config){
12750     Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12751 };
12752 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12753     render : function(td){
12754         this.td = td;
12755         Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12756     },
12757     
12758     /**
12759      * Removes and destroys this button
12760      */
12761     destroy : function(){
12762         Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12763         this.td.parentNode.removeChild(this.td);
12764     },
12765     
12766     /**
12767      * Shows this button
12768      */
12769     show: function(){
12770         this.hidden = false;
12771         this.td.style.display = "";
12772     },
12773     
12774     /**
12775      * Hides this button
12776      */
12777     hide: function(){
12778         this.hidden = true;
12779         this.td.style.display = "none";
12780     }
12781 });
12782
12783 // backwards compat
12784 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12785  * Based on:
12786  * Ext JS Library 1.1.1
12787  * Copyright(c) 2006-2007, Ext JS, LLC.
12788  *
12789  * Originally Released Under LGPL - original licence link has changed is not relivant.
12790  *
12791  * Fork - LGPL
12792  * <script type="text/javascript">
12793  */
12794  
12795 /**
12796  * @class Roo.PagingToolbar
12797  * @extends Roo.Toolbar
12798  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12799  * @constructor
12800  * Create a new PagingToolbar
12801  * @param {Object} config The config object
12802  */
12803 Roo.PagingToolbar = function(el, ds, config)
12804 {
12805     // old args format still supported... - xtype is prefered..
12806     if (typeof(el) == 'object' && el.xtype) {
12807         // created from xtype...
12808         config = el;
12809         ds = el.dataSource;
12810         el = config.container;
12811     }
12812     var items = [];
12813     if (config.items) {
12814         items = config.items;
12815         config.items = [];
12816     }
12817     
12818     Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12819     this.ds = ds;
12820     this.cursor = 0;
12821     this.renderButtons(this.el);
12822     this.bind(ds);
12823     
12824     // supprot items array.
12825    
12826     Roo.each(items, function(e) {
12827         this.add(Roo.factory(e));
12828     },this);
12829     
12830 };
12831
12832 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12833     /**
12834      * @cfg {Roo.data.Store} dataSource
12835      * The underlying data store providing the paged data
12836      */
12837     /**
12838      * @cfg {String/HTMLElement/Element} container
12839      * container The id or element that will contain the toolbar
12840      */
12841     /**
12842      * @cfg {Boolean} displayInfo
12843      * True to display the displayMsg (defaults to false)
12844      */
12845     /**
12846      * @cfg {Number} pageSize
12847      * The number of records to display per page (defaults to 20)
12848      */
12849     pageSize: 20,
12850     /**
12851      * @cfg {String} displayMsg
12852      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12853      */
12854     displayMsg : 'Displaying {0} - {1} of {2}',
12855     /**
12856      * @cfg {String} emptyMsg
12857      * The message to display when no records are found (defaults to "No data to display")
12858      */
12859     emptyMsg : 'No data to display',
12860     /**
12861      * Customizable piece of the default paging text (defaults to "Page")
12862      * @type String
12863      */
12864     beforePageText : "Page",
12865     /**
12866      * Customizable piece of the default paging text (defaults to "of %0")
12867      * @type String
12868      */
12869     afterPageText : "of {0}",
12870     /**
12871      * Customizable piece of the default paging text (defaults to "First Page")
12872      * @type String
12873      */
12874     firstText : "First Page",
12875     /**
12876      * Customizable piece of the default paging text (defaults to "Previous Page")
12877      * @type String
12878      */
12879     prevText : "Previous Page",
12880     /**
12881      * Customizable piece of the default paging text (defaults to "Next Page")
12882      * @type String
12883      */
12884     nextText : "Next Page",
12885     /**
12886      * Customizable piece of the default paging text (defaults to "Last Page")
12887      * @type String
12888      */
12889     lastText : "Last Page",
12890     /**
12891      * Customizable piece of the default paging text (defaults to "Refresh")
12892      * @type String
12893      */
12894     refreshText : "Refresh",
12895
12896     // private
12897     renderButtons : function(el){
12898         Roo.PagingToolbar.superclass.render.call(this, el);
12899         this.first = this.addButton({
12900             tooltip: this.firstText,
12901             cls: "x-btn-icon x-grid-page-first",
12902             disabled: true,
12903             handler: this.onClick.createDelegate(this, ["first"])
12904         });
12905         this.prev = this.addButton({
12906             tooltip: this.prevText,
12907             cls: "x-btn-icon x-grid-page-prev",
12908             disabled: true,
12909             handler: this.onClick.createDelegate(this, ["prev"])
12910         });
12911         //this.addSeparator();
12912         this.add(this.beforePageText);
12913         this.field = Roo.get(this.addDom({
12914            tag: "input",
12915            type: "text",
12916            size: "3",
12917            value: "1",
12918            cls: "x-grid-page-number"
12919         }).el);
12920         this.field.on("keydown", this.onPagingKeydown, this);
12921         this.field.on("focus", function(){this.dom.select();});
12922         this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12923         this.field.setHeight(18);
12924         //this.addSeparator();
12925         this.next = this.addButton({
12926             tooltip: this.nextText,
12927             cls: "x-btn-icon x-grid-page-next",
12928             disabled: true,
12929             handler: this.onClick.createDelegate(this, ["next"])
12930         });
12931         this.last = this.addButton({
12932             tooltip: this.lastText,
12933             cls: "x-btn-icon x-grid-page-last",
12934             disabled: true,
12935             handler: this.onClick.createDelegate(this, ["last"])
12936         });
12937         //this.addSeparator();
12938         this.loading = this.addButton({
12939             tooltip: this.refreshText,
12940             cls: "x-btn-icon x-grid-loading",
12941             handler: this.onClick.createDelegate(this, ["refresh"])
12942         });
12943
12944         if(this.displayInfo){
12945             this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12946         }
12947     },
12948
12949     // private
12950     updateInfo : function(){
12951         if(this.displayEl){
12952             var count = this.ds.getCount();
12953             var msg = count == 0 ?
12954                 this.emptyMsg :
12955                 String.format(
12956                     this.displayMsg,
12957                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
12958                 );
12959             this.displayEl.update(msg);
12960         }
12961     },
12962
12963     // private
12964     onLoad : function(ds, r, o){
12965        this.cursor = o.params ? o.params.start : 0;
12966        var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12967
12968        this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12969        this.field.dom.value = ap;
12970        this.first.setDisabled(ap == 1);
12971        this.prev.setDisabled(ap == 1);
12972        this.next.setDisabled(ap == ps);
12973        this.last.setDisabled(ap == ps);
12974        this.loading.enable();
12975        this.updateInfo();
12976     },
12977
12978     // private
12979     getPageData : function(){
12980         var total = this.ds.getTotalCount();
12981         return {
12982             total : total,
12983             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12984             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12985         };
12986     },
12987
12988     // private
12989     onLoadError : function(){
12990         this.loading.enable();
12991     },
12992
12993     // private
12994     onPagingKeydown : function(e){
12995         var k = e.getKey();
12996         var d = this.getPageData();
12997         if(k == e.RETURN){
12998             var v = this.field.dom.value, pageNum;
12999             if(!v || isNaN(pageNum = parseInt(v, 10))){
13000                 this.field.dom.value = d.activePage;
13001                 return;
13002             }
13003             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13004             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13005             e.stopEvent();
13006         }
13007         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))
13008         {
13009           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13010           this.field.dom.value = pageNum;
13011           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13012           e.stopEvent();
13013         }
13014         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13015         {
13016           var v = this.field.dom.value, pageNum; 
13017           var increment = (e.shiftKey) ? 10 : 1;
13018           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13019             increment *= -1;
13020           if(!v || isNaN(pageNum = parseInt(v, 10))) {
13021             this.field.dom.value = d.activePage;
13022             return;
13023           }
13024           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13025           {
13026             this.field.dom.value = parseInt(v, 10) + increment;
13027             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13028             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13029           }
13030           e.stopEvent();
13031         }
13032     },
13033
13034     // private
13035     beforeLoad : function(){
13036         if(this.loading){
13037             this.loading.disable();
13038         }
13039     },
13040
13041     // private
13042     onClick : function(which){
13043         var ds = this.ds;
13044         switch(which){
13045             case "first":
13046                 ds.load({params:{start: 0, limit: this.pageSize}});
13047             break;
13048             case "prev":
13049                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13050             break;
13051             case "next":
13052                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13053             break;
13054             case "last":
13055                 var total = ds.getTotalCount();
13056                 var extra = total % this.pageSize;
13057                 var lastStart = extra ? (total - extra) : total-this.pageSize;
13058                 ds.load({params:{start: lastStart, limit: this.pageSize}});
13059             break;
13060             case "refresh":
13061                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13062             break;
13063         }
13064     },
13065
13066     /**
13067      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13068      * @param {Roo.data.Store} store The data store to unbind
13069      */
13070     unbind : function(ds){
13071         ds.un("beforeload", this.beforeLoad, this);
13072         ds.un("load", this.onLoad, this);
13073         ds.un("loadexception", this.onLoadError, this);
13074         ds.un("remove", this.updateInfo, this);
13075         ds.un("add", this.updateInfo, this);
13076         this.ds = undefined;
13077     },
13078
13079     /**
13080      * Binds the paging toolbar to the specified {@link Roo.data.Store}
13081      * @param {Roo.data.Store} store The data store to bind
13082      */
13083     bind : function(ds){
13084         ds.on("beforeload", this.beforeLoad, this);
13085         ds.on("load", this.onLoad, this);
13086         ds.on("loadexception", this.onLoadError, this);
13087         ds.on("remove", this.updateInfo, this);
13088         ds.on("add", this.updateInfo, this);
13089         this.ds = ds;
13090     }
13091 });/*
13092  * Based on:
13093  * Ext JS Library 1.1.1
13094  * Copyright(c) 2006-2007, Ext JS, LLC.
13095  *
13096  * Originally Released Under LGPL - original licence link has changed is not relivant.
13097  *
13098  * Fork - LGPL
13099  * <script type="text/javascript">
13100  */
13101
13102 /**
13103  * @class Roo.Resizable
13104  * @extends Roo.util.Observable
13105  * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13106  * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13107  * 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
13108  * the element will be wrapped for you automatically.</p>
13109  * <p>Here is the list of valid resize handles:</p>
13110  * <pre>
13111 Value   Description
13112 ------  -------------------
13113  'n'     north
13114  's'     south
13115  'e'     east
13116  'w'     west
13117  'nw'    northwest
13118  'sw'    southwest
13119  'se'    southeast
13120  'ne'    northeast
13121  'hd'    horizontal drag
13122  'all'   all
13123 </pre>
13124  * <p>Here's an example showing the creation of a typical Resizable:</p>
13125  * <pre><code>
13126 var resizer = new Roo.Resizable("element-id", {
13127     handles: 'all',
13128     minWidth: 200,
13129     minHeight: 100,
13130     maxWidth: 500,
13131     maxHeight: 400,
13132     pinned: true
13133 });
13134 resizer.on("resize", myHandler);
13135 </code></pre>
13136  * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13137  * resizer.east.setDisplayed(false);</p>
13138  * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13139  * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13140  * resize operation's new size (defaults to [0, 0])
13141  * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13142  * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13143  * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13144  * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13145  * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13146  * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13147  * @cfg {Number} width The width of the element in pixels (defaults to null)
13148  * @cfg {Number} height The height of the element in pixels (defaults to null)
13149  * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13150  * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13151  * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13152  * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13153  * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  The old style of adding multi-direction resize handles, deprecated
13154  * in favor of the handles config option (defaults to false)
13155  * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13156  * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13157  * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13158  * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13159  * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13160  * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13161  * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13162  * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13163  * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13164  * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13165  * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13166  * @constructor
13167  * Create a new resizable component
13168  * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13169  * @param {Object} config configuration options
13170   */
13171 Roo.Resizable = function(el, config)
13172 {
13173     this.el = Roo.get(el);
13174
13175     if(config && config.wrap){
13176         config.resizeChild = this.el;
13177         this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13178         this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13179         this.el.setStyle("overflow", "hidden");
13180         this.el.setPositioning(config.resizeChild.getPositioning());
13181         config.resizeChild.clearPositioning();
13182         if(!config.width || !config.height){
13183             var csize = config.resizeChild.getSize();
13184             this.el.setSize(csize.width, csize.height);
13185         }
13186         if(config.pinned && !config.adjustments){
13187             config.adjustments = "auto";
13188         }
13189     }
13190
13191     this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13192     this.proxy.unselectable();
13193     this.proxy.enableDisplayMode('block');
13194
13195     Roo.apply(this, config);
13196
13197     if(this.pinned){
13198         this.disableTrackOver = true;
13199         this.el.addClass("x-resizable-pinned");
13200     }
13201     // if the element isn't positioned, make it relative
13202     var position = this.el.getStyle("position");
13203     if(position != "absolute" && position != "fixed"){
13204         this.el.setStyle("position", "relative");
13205     }
13206     if(!this.handles){ // no handles passed, must be legacy style
13207         this.handles = 's,e,se';
13208         if(this.multiDirectional){
13209             this.handles += ',n,w';
13210         }
13211     }
13212     if(this.handles == "all"){
13213         this.handles = "n s e w ne nw se sw";
13214     }
13215     var hs = this.handles.split(/\s*?[,;]\s*?| /);
13216     var ps = Roo.Resizable.positions;
13217     for(var i = 0, len = hs.length; i < len; i++){
13218         if(hs[i] && ps[hs[i]]){
13219             var pos = ps[hs[i]];
13220             this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13221         }
13222     }
13223     // legacy
13224     this.corner = this.southeast;
13225     
13226     // updateBox = the box can move..
13227     if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13228         this.updateBox = true;
13229     }
13230
13231     this.activeHandle = null;
13232
13233     if(this.resizeChild){
13234         if(typeof this.resizeChild == "boolean"){
13235             this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13236         }else{
13237             this.resizeChild = Roo.get(this.resizeChild, true);
13238         }
13239     }
13240     
13241     if(this.adjustments == "auto"){
13242         var rc = this.resizeChild;
13243         var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13244         if(rc && (hw || hn)){
13245             rc.position("relative");
13246             rc.setLeft(hw ? hw.el.getWidth() : 0);
13247             rc.setTop(hn ? hn.el.getHeight() : 0);
13248         }
13249         this.adjustments = [
13250             (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13251             (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13252         ];
13253     }
13254
13255     if(this.draggable){
13256         this.dd = this.dynamic ?
13257             this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13258         this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13259     }
13260
13261     // public events
13262     this.addEvents({
13263         /**
13264          * @event beforeresize
13265          * Fired before resize is allowed. Set enabled to false to cancel resize.
13266          * @param {Roo.Resizable} this
13267          * @param {Roo.EventObject} e The mousedown event
13268          */
13269         "beforeresize" : true,
13270         /**
13271          * @event resize
13272          * Fired after a resize.
13273          * @param {Roo.Resizable} this
13274          * @param {Number} width The new width
13275          * @param {Number} height The new height
13276          * @param {Roo.EventObject} e The mouseup event
13277          */
13278         "resize" : true
13279     });
13280
13281     if(this.width !== null && this.height !== null){
13282         this.resizeTo(this.width, this.height);
13283     }else{
13284         this.updateChildSize();
13285     }
13286     if(Roo.isIE){
13287         this.el.dom.style.zoom = 1;
13288     }
13289     Roo.Resizable.superclass.constructor.call(this);
13290 };
13291
13292 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13293         resizeChild : false,
13294         adjustments : [0, 0],
13295         minWidth : 5,
13296         minHeight : 5,
13297         maxWidth : 10000,
13298         maxHeight : 10000,
13299         enabled : true,
13300         animate : false,
13301         duration : .35,
13302         dynamic : false,
13303         handles : false,
13304         multiDirectional : false,
13305         disableTrackOver : false,
13306         easing : 'easeOutStrong',
13307         widthIncrement : 0,
13308         heightIncrement : 0,
13309         pinned : false,
13310         width : null,
13311         height : null,
13312         preserveRatio : false,
13313         transparent: false,
13314         minX: 0,
13315         minY: 0,
13316         draggable: false,
13317
13318         /**
13319          * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13320          */
13321         constrainTo: undefined,
13322         /**
13323          * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13324          */
13325         resizeRegion: undefined,
13326
13327
13328     /**
13329      * Perform a manual resize
13330      * @param {Number} width
13331      * @param {Number} height
13332      */
13333     resizeTo : function(width, height){
13334         this.el.setSize(width, height);
13335         this.updateChildSize();
13336         this.fireEvent("resize", this, width, height, null);
13337     },
13338
13339     // private
13340     startSizing : function(e, handle){
13341         this.fireEvent("beforeresize", this, e);
13342         if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13343
13344             if(!this.overlay){
13345                 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: "&#160;"});
13346                 this.overlay.unselectable();
13347                 this.overlay.enableDisplayMode("block");
13348                 this.overlay.on("mousemove", this.onMouseMove, this);
13349                 this.overlay.on("mouseup", this.onMouseUp, this);
13350             }
13351             this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13352
13353             this.resizing = true;
13354             this.startBox = this.el.getBox();
13355             this.startPoint = e.getXY();
13356             this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13357                             (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13358
13359             this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13360             this.overlay.show();
13361
13362             if(this.constrainTo) {
13363                 var ct = Roo.get(this.constrainTo);
13364                 this.resizeRegion = ct.getRegion().adjust(
13365                     ct.getFrameWidth('t'),
13366                     ct.getFrameWidth('l'),
13367                     -ct.getFrameWidth('b'),
13368                     -ct.getFrameWidth('r')
13369                 );
13370             }
13371
13372             this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13373             this.proxy.show();
13374             this.proxy.setBox(this.startBox);
13375             if(!this.dynamic){
13376                 this.proxy.setStyle('visibility', 'visible');
13377             }
13378         }
13379     },
13380
13381     // private
13382     onMouseDown : function(handle, e){
13383         if(this.enabled){
13384             e.stopEvent();
13385             this.activeHandle = handle;
13386             this.startSizing(e, handle);
13387         }
13388     },
13389
13390     // private
13391     onMouseUp : function(e){
13392         var size = this.resizeElement();
13393         this.resizing = false;
13394         this.handleOut();
13395         this.overlay.hide();
13396         this.proxy.hide();
13397         this.fireEvent("resize", this, size.width, size.height, e);
13398     },
13399
13400     // private
13401     updateChildSize : function(){
13402         if(this.resizeChild){
13403             var el = this.el;
13404             var child = this.resizeChild;
13405             var adj = this.adjustments;
13406             if(el.dom.offsetWidth){
13407                 var b = el.getSize(true);
13408                 child.setSize(b.width+adj[0], b.height+adj[1]);
13409             }
13410             // Second call here for IE
13411             // The first call enables instant resizing and
13412             // the second call corrects scroll bars if they
13413             // exist
13414             if(Roo.isIE){
13415                 setTimeout(function(){
13416                     if(el.dom.offsetWidth){
13417                         var b = el.getSize(true);
13418                         child.setSize(b.width+adj[0], b.height+adj[1]);
13419                     }
13420                 }, 10);
13421             }
13422         }
13423     },
13424
13425     // private
13426     snap : function(value, inc, min){
13427         if(!inc || !value) return value;
13428         var newValue = value;
13429         var m = value % inc;
13430         if(m > 0){
13431             if(m > (inc/2)){
13432                 newValue = value + (inc-m);
13433             }else{
13434                 newValue = value - m;
13435             }
13436         }
13437         return Math.max(min, newValue);
13438     },
13439
13440     // private
13441     resizeElement : function(){
13442         var box = this.proxy.getBox();
13443         if(this.updateBox){
13444             this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13445         }else{
13446             this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13447         }
13448         this.updateChildSize();
13449         if(!this.dynamic){
13450             this.proxy.hide();
13451         }
13452         return box;
13453     },
13454
13455     // private
13456     constrain : function(v, diff, m, mx){
13457         if(v - diff < m){
13458             diff = v - m;
13459         }else if(v - diff > mx){
13460             diff = mx - v;
13461         }
13462         return diff;
13463     },
13464
13465     // private
13466     onMouseMove : function(e){
13467         if(this.enabled){
13468             try{// try catch so if something goes wrong the user doesn't get hung
13469
13470             if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13471                 return;
13472             }
13473
13474             //var curXY = this.startPoint;
13475             var curSize = this.curSize || this.startBox;
13476             var x = this.startBox.x, y = this.startBox.y;
13477             var ox = x, oy = y;
13478             var w = curSize.width, h = curSize.height;
13479             var ow = w, oh = h;
13480             var mw = this.minWidth, mh = this.minHeight;
13481             var mxw = this.maxWidth, mxh = this.maxHeight;
13482             var wi = this.widthIncrement;
13483             var hi = this.heightIncrement;
13484
13485             var eventXY = e.getXY();
13486             var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13487             var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13488
13489             var pos = this.activeHandle.position;
13490
13491             switch(pos){
13492                 case "east":
13493                     w += diffX;
13494                     w = Math.min(Math.max(mw, w), mxw);
13495                     break;
13496              
13497                 case "south":
13498                     h += diffY;
13499                     h = Math.min(Math.max(mh, h), mxh);
13500                     break;
13501                 case "southeast":
13502                     w += diffX;
13503                     h += diffY;
13504                     w = Math.min(Math.max(mw, w), mxw);
13505                     h = Math.min(Math.max(mh, h), mxh);
13506                     break;
13507                 case "north":
13508                     diffY = this.constrain(h, diffY, mh, mxh);
13509                     y += diffY;
13510                     h -= diffY;
13511                     break;
13512                 case "hdrag":
13513                     
13514                     if (wi) {
13515                         var adiffX = Math.abs(diffX);
13516                         var sub = (adiffX % wi); // how much 
13517                         if (sub > (wi/2)) { // far enough to snap
13518                             diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13519                         } else {
13520                             // remove difference.. 
13521                             diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13522                         }
13523                     }
13524                     x += diffX;
13525                     x = Math.max(this.minX, x);
13526                     break;
13527                 case "west":
13528                     diffX = this.constrain(w, diffX, mw, mxw);
13529                     x += diffX;
13530                     w -= diffX;
13531                     break;
13532                 case "northeast":
13533                     w += diffX;
13534                     w = Math.min(Math.max(mw, w), mxw);
13535                     diffY = this.constrain(h, diffY, mh, mxh);
13536                     y += diffY;
13537                     h -= diffY;
13538                     break;
13539                 case "northwest":
13540                     diffX = this.constrain(w, diffX, mw, mxw);
13541                     diffY = this.constrain(h, diffY, mh, mxh);
13542                     y += diffY;
13543                     h -= diffY;
13544                     x += diffX;
13545                     w -= diffX;
13546                     break;
13547                case "southwest":
13548                     diffX = this.constrain(w, diffX, mw, mxw);
13549                     h += diffY;
13550                     h = Math.min(Math.max(mh, h), mxh);
13551                     x += diffX;
13552                     w -= diffX;
13553                     break;
13554             }
13555
13556             var sw = this.snap(w, wi, mw);
13557             var sh = this.snap(h, hi, mh);
13558             if(sw != w || sh != h){
13559                 switch(pos){
13560                     case "northeast":
13561                         y -= sh - h;
13562                     break;
13563                     case "north":
13564                         y -= sh - h;
13565                         break;
13566                     case "southwest":
13567                         x -= sw - w;
13568                     break;
13569                     case "west":
13570                         x -= sw - w;
13571                         break;
13572                     case "northwest":
13573                         x -= sw - w;
13574                         y -= sh - h;
13575                     break;
13576                 }
13577                 w = sw;
13578                 h = sh;
13579             }
13580
13581             if(this.preserveRatio){
13582                 switch(pos){
13583                     case "southeast":
13584                     case "east":
13585                         h = oh * (w/ow);
13586                         h = Math.min(Math.max(mh, h), mxh);
13587                         w = ow * (h/oh);
13588                        break;
13589                     case "south":
13590                         w = ow * (h/oh);
13591                         w = Math.min(Math.max(mw, w), mxw);
13592                         h = oh * (w/ow);
13593                         break;
13594                     case "northeast":
13595                         w = ow * (h/oh);
13596                         w = Math.min(Math.max(mw, w), mxw);
13597                         h = oh * (w/ow);
13598                     break;
13599                     case "north":
13600                         var tw = w;
13601                         w = ow * (h/oh);
13602                         w = Math.min(Math.max(mw, w), mxw);
13603                         h = oh * (w/ow);
13604                         x += (tw - w) / 2;
13605                         break;
13606                     case "southwest":
13607                         h = oh * (w/ow);
13608                         h = Math.min(Math.max(mh, h), mxh);
13609                         var tw = w;
13610                         w = ow * (h/oh);
13611                         x += tw - w;
13612                         break;
13613                     case "west":
13614                         var th = h;
13615                         h = oh * (w/ow);
13616                         h = Math.min(Math.max(mh, h), mxh);
13617                         y += (th - h) / 2;
13618                         var tw = w;
13619                         w = ow * (h/oh);
13620                         x += tw - w;
13621                        break;
13622                     case "northwest":
13623                         var tw = w;
13624                         var th = h;
13625                         h = oh * (w/ow);
13626                         h = Math.min(Math.max(mh, h), mxh);
13627                         w = ow * (h/oh);
13628                         y += th - h;
13629                         x += tw - w;
13630                        break;
13631
13632                 }
13633             }
13634             if (pos == 'hdrag') {
13635                 w = ow;
13636             }
13637             this.proxy.setBounds(x, y, w, h);
13638             if(this.dynamic){
13639                 this.resizeElement();
13640             }
13641             }catch(e){}
13642         }
13643     },
13644
13645     // private
13646     handleOver : function(){
13647         if(this.enabled){
13648             this.el.addClass("x-resizable-over");
13649         }
13650     },
13651
13652     // private
13653     handleOut : function(){
13654         if(!this.resizing){
13655             this.el.removeClass("x-resizable-over");
13656         }
13657     },
13658
13659     /**
13660      * Returns the element this component is bound to.
13661      * @return {Roo.Element}
13662      */
13663     getEl : function(){
13664         return this.el;
13665     },
13666
13667     /**
13668      * Returns the resizeChild element (or null).
13669      * @return {Roo.Element}
13670      */
13671     getResizeChild : function(){
13672         return this.resizeChild;
13673     },
13674
13675     /**
13676      * Destroys this resizable. If the element was wrapped and
13677      * removeEl is not true then the element remains.
13678      * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13679      */
13680     destroy : function(removeEl){
13681         this.proxy.remove();
13682         if(this.overlay){
13683             this.overlay.removeAllListeners();
13684             this.overlay.remove();
13685         }
13686         var ps = Roo.Resizable.positions;
13687         for(var k in ps){
13688             if(typeof ps[k] != "function" && this[ps[k]]){
13689                 var h = this[ps[k]];
13690                 h.el.removeAllListeners();
13691                 h.el.remove();
13692             }
13693         }
13694         if(removeEl){
13695             this.el.update("");
13696             this.el.remove();
13697         }
13698     }
13699 });
13700
13701 // private
13702 // hash to map config positions to true positions
13703 Roo.Resizable.positions = {
13704     n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast", 
13705     hd: "hdrag"
13706 };
13707
13708 // private
13709 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13710     if(!this.tpl){
13711         // only initialize the template if resizable is used
13712         var tpl = Roo.DomHelper.createTemplate(
13713             {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13714         );
13715         tpl.compile();
13716         Roo.Resizable.Handle.prototype.tpl = tpl;
13717     }
13718     this.position = pos;
13719     this.rz = rz;
13720     // show north drag fro topdra
13721     var handlepos = pos == 'hdrag' ? 'north' : pos;
13722     
13723     this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13724     if (pos == 'hdrag') {
13725         this.el.setStyle('cursor', 'pointer');
13726     }
13727     this.el.unselectable();
13728     if(transparent){
13729         this.el.setOpacity(0);
13730     }
13731     this.el.on("mousedown", this.onMouseDown, this);
13732     if(!disableTrackOver){
13733         this.el.on("mouseover", this.onMouseOver, this);
13734         this.el.on("mouseout", this.onMouseOut, this);
13735     }
13736 };
13737
13738 // private
13739 Roo.Resizable.Handle.prototype = {
13740     afterResize : function(rz){
13741         // do nothing
13742     },
13743     // private
13744     onMouseDown : function(e){
13745         this.rz.onMouseDown(this, e);
13746     },
13747     // private
13748     onMouseOver : function(e){
13749         this.rz.handleOver(this, e);
13750     },
13751     // private
13752     onMouseOut : function(e){
13753         this.rz.handleOut(this, e);
13754     }
13755 };/*
13756  * Based on:
13757  * Ext JS Library 1.1.1
13758  * Copyright(c) 2006-2007, Ext JS, LLC.
13759  *
13760  * Originally Released Under LGPL - original licence link has changed is not relivant.
13761  *
13762  * Fork - LGPL
13763  * <script type="text/javascript">
13764  */
13765
13766 /**
13767  * @class Roo.Editor
13768  * @extends Roo.Component
13769  * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13770  * @constructor
13771  * Create a new Editor
13772  * @param {Roo.form.Field} field The Field object (or descendant)
13773  * @param {Object} config The config object
13774  */
13775 Roo.Editor = function(field, config){
13776     Roo.Editor.superclass.constructor.call(this, config);
13777     this.field = field;
13778     this.addEvents({
13779         /**
13780              * @event beforestartedit
13781              * Fires when editing is initiated, but before the value changes.  Editing can be canceled by returning
13782              * false from the handler of this event.
13783              * @param {Editor} this
13784              * @param {Roo.Element} boundEl The underlying element bound to this editor
13785              * @param {Mixed} value The field value being set
13786              */
13787         "beforestartedit" : true,
13788         /**
13789              * @event startedit
13790              * Fires when this editor is displayed
13791              * @param {Roo.Element} boundEl The underlying element bound to this editor
13792              * @param {Mixed} value The starting field value
13793              */
13794         "startedit" : true,
13795         /**
13796              * @event beforecomplete
13797              * Fires after a change has been made to the field, but before the change is reflected in the underlying
13798              * field.  Saving the change to the field can be canceled by returning false from the handler of this event.
13799              * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13800              * event will not fire since no edit actually occurred.
13801              * @param {Editor} this
13802              * @param {Mixed} value The current field value
13803              * @param {Mixed} startValue The original field value
13804              */
13805         "beforecomplete" : true,
13806         /**
13807              * @event complete
13808              * Fires after editing is complete and any changed value has been written to the underlying field.
13809              * @param {Editor} this
13810              * @param {Mixed} value The current field value
13811              * @param {Mixed} startValue The original field value
13812              */
13813         "complete" : true,
13814         /**
13815          * @event specialkey
13816          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
13817          * {@link Roo.EventObject#getKey} to determine which key was pressed.
13818          * @param {Roo.form.Field} this
13819          * @param {Roo.EventObject} e The event object
13820          */
13821         "specialkey" : true
13822     });
13823 };
13824
13825 Roo.extend(Roo.Editor, Roo.Component, {
13826     /**
13827      * @cfg {Boolean/String} autosize
13828      * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13829      * or "height" to adopt the height only (defaults to false)
13830      */
13831     /**
13832      * @cfg {Boolean} revertInvalid
13833      * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13834      * validation fails (defaults to true)
13835      */
13836     /**
13837      * @cfg {Boolean} ignoreNoChange
13838      * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13839      * the value has not changed (defaults to false).  Applies only to string values - edits for other data types
13840      * will never be ignored.
13841      */
13842     /**
13843      * @cfg {Boolean} hideEl
13844      * False to keep the bound element visible while the editor is displayed (defaults to true)
13845      */
13846     /**
13847      * @cfg {Mixed} value
13848      * The data value of the underlying field (defaults to "")
13849      */
13850     value : "",
13851     /**
13852      * @cfg {String} alignment
13853      * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13854      */
13855     alignment: "c-c?",
13856     /**
13857      * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13858      * for bottom-right shadow (defaults to "frame")
13859      */
13860     shadow : "frame",
13861     /**
13862      * @cfg {Boolean} constrain True to constrain the editor to the viewport
13863      */
13864     constrain : false,
13865     /**
13866      * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13867      */
13868     completeOnEnter : false,
13869     /**
13870      * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13871      */
13872     cancelOnEsc : false,
13873     /**
13874      * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13875      */
13876     updateEl : false,
13877
13878     // private
13879     onRender : function(ct, position){
13880         this.el = new Roo.Layer({
13881             shadow: this.shadow,
13882             cls: "x-editor",
13883             parentEl : ct,
13884             shim : this.shim,
13885             shadowOffset:4,
13886             id: this.id,
13887             constrain: this.constrain
13888         });
13889         this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13890         if(this.field.msgTarget != 'title'){
13891             this.field.msgTarget = 'qtip';
13892         }
13893         this.field.render(this.el);
13894         if(Roo.isGecko){
13895             this.field.el.dom.setAttribute('autocomplete', 'off');
13896         }
13897         this.field.on("specialkey", this.onSpecialKey, this);
13898         if(this.swallowKeys){
13899             this.field.el.swallowEvent(['keydown','keypress']);
13900         }
13901         this.field.show();
13902         this.field.on("blur", this.onBlur, this);
13903         if(this.field.grow){
13904             this.field.on("autosize", this.el.sync,  this.el, {delay:1});
13905         }
13906     },
13907
13908     onSpecialKey : function(field, e){
13909         //Roo.log('editor onSpecialKey');
13910         if(this.completeOnEnter && e.getKey() == e.ENTER){
13911             e.stopEvent();
13912             this.completeEdit();
13913         }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13914             this.cancelEdit();
13915         }else{
13916             this.fireEvent('specialkey', field, e);
13917         }
13918     },
13919
13920     /**
13921      * Starts the editing process and shows the editor.
13922      * @param {String/HTMLElement/Element} el The element to edit
13923      * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13924       * to the innerHTML of el.
13925      */
13926     startEdit : function(el, value){
13927         if(this.editing){
13928             this.completeEdit();
13929         }
13930         this.boundEl = Roo.get(el);
13931         var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13932         if(!this.rendered){
13933             this.render(this.parentEl || document.body);
13934         }
13935         if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13936             return;
13937         }
13938         this.startValue = v;
13939         this.field.setValue(v);
13940         if(this.autoSize){
13941             var sz = this.boundEl.getSize();
13942             switch(this.autoSize){
13943                 case "width":
13944                 this.setSize(sz.width,  "");
13945                 break;
13946                 case "height":
13947                 this.setSize("",  sz.height);
13948                 break;
13949                 default:
13950                 this.setSize(sz.width,  sz.height);
13951             }
13952         }
13953         this.el.alignTo(this.boundEl, this.alignment);
13954         this.editing = true;
13955         if(Roo.QuickTips){
13956             Roo.QuickTips.disable();
13957         }
13958         this.show();
13959     },
13960
13961     /**
13962      * Sets the height and width of this editor.
13963      * @param {Number} width The new width
13964      * @param {Number} height The new height
13965      */
13966     setSize : function(w, h){
13967         this.field.setSize(w, h);
13968         if(this.el){
13969             this.el.sync();
13970         }
13971     },
13972
13973     /**
13974      * Realigns the editor to the bound field based on the current alignment config value.
13975      */
13976     realign : function(){
13977         this.el.alignTo(this.boundEl, this.alignment);
13978     },
13979
13980     /**
13981      * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13982      * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13983      */
13984     completeEdit : function(remainVisible){
13985         if(!this.editing){
13986             return;
13987         }
13988         var v = this.getValue();
13989         if(this.revertInvalid !== false && !this.field.isValid()){
13990             v = this.startValue;
13991             this.cancelEdit(true);
13992         }
13993         if(String(v) === String(this.startValue) && this.ignoreNoChange){
13994             this.editing = false;
13995             this.hide();
13996             return;
13997         }
13998         if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13999             this.editing = false;
14000             if(this.updateEl && this.boundEl){
14001                 this.boundEl.update(v);
14002             }
14003             if(remainVisible !== true){
14004                 this.hide();
14005             }
14006             this.fireEvent("complete", this, v, this.startValue);
14007         }
14008     },
14009
14010     // private
14011     onShow : function(){
14012         this.el.show();
14013         if(this.hideEl !== false){
14014             this.boundEl.hide();
14015         }
14016         this.field.show();
14017         if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14018             this.fixIEFocus = true;
14019             this.deferredFocus.defer(50, this);
14020         }else{
14021             this.field.focus();
14022         }
14023         this.fireEvent("startedit", this.boundEl, this.startValue);
14024     },
14025
14026     deferredFocus : function(){
14027         if(this.editing){
14028             this.field.focus();
14029         }
14030     },
14031
14032     /**
14033      * Cancels the editing process and hides the editor without persisting any changes.  The field value will be
14034      * reverted to the original starting value.
14035      * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14036      * cancel (defaults to false)
14037      */
14038     cancelEdit : function(remainVisible){
14039         if(this.editing){
14040             this.setValue(this.startValue);
14041             if(remainVisible !== true){
14042                 this.hide();
14043             }
14044         }
14045     },
14046
14047     // private
14048     onBlur : function(){
14049         if(this.allowBlur !== true && this.editing){
14050             this.completeEdit();
14051         }
14052     },
14053
14054     // private
14055     onHide : function(){
14056         if(this.editing){
14057             this.completeEdit();
14058             return;
14059         }
14060         this.field.blur();
14061         if(this.field.collapse){
14062             this.field.collapse();
14063         }
14064         this.el.hide();
14065         if(this.hideEl !== false){
14066             this.boundEl.show();
14067         }
14068         if(Roo.QuickTips){
14069             Roo.QuickTips.enable();
14070         }
14071     },
14072
14073     /**
14074      * Sets the data value of the editor
14075      * @param {Mixed} value Any valid value supported by the underlying field
14076      */
14077     setValue : function(v){
14078         this.field.setValue(v);
14079     },
14080
14081     /**
14082      * Gets the data value of the editor
14083      * @return {Mixed} The data value
14084      */
14085     getValue : function(){
14086         return this.field.getValue();
14087     }
14088 });/*
14089  * Based on:
14090  * Ext JS Library 1.1.1
14091  * Copyright(c) 2006-2007, Ext JS, LLC.
14092  *
14093  * Originally Released Under LGPL - original licence link has changed is not relivant.
14094  *
14095  * Fork - LGPL
14096  * <script type="text/javascript">
14097  */
14098  
14099 /**
14100  * @class Roo.BasicDialog
14101  * @extends Roo.util.Observable
14102  * Lightweight Dialog Class.  The code below shows the creation of a typical dialog using existing HTML markup:
14103  * <pre><code>
14104 var dlg = new Roo.BasicDialog("my-dlg", {
14105     height: 200,
14106     width: 300,
14107     minHeight: 100,
14108     minWidth: 150,
14109     modal: true,
14110     proxyDrag: true,
14111     shadow: true
14112 });
14113 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14114 dlg.addButton('OK', dlg.hide, dlg);    // Could call a save function instead of hiding
14115 dlg.addButton('Cancel', dlg.hide, dlg);
14116 dlg.show();
14117 </code></pre>
14118   <b>A Dialog should always be a direct child of the body element.</b>
14119  * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14120  * @cfg {String} title Default text to display in the title bar (defaults to null)
14121  * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
14122  * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
14123  * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14124  * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14125  * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14126  * (defaults to null with no animation)
14127  * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14128  * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14129  * property for valid values (defaults to 'all')
14130  * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14131  * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14132  * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14133  * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14134  * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14135  * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14136  * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14137  * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14138  * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14139  * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14140  * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14141  * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14142  * draggable = true (defaults to false)
14143  * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14144  * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14145  * shadow (defaults to false)
14146  * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14147  * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14148  * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14149  * @cfg {Array} buttons Array of buttons
14150  * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14151  * @constructor
14152  * Create a new BasicDialog.
14153  * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14154  * @param {Object} config Configuration options
14155  */
14156 Roo.BasicDialog = function(el, config){
14157     this.el = Roo.get(el);
14158     var dh = Roo.DomHelper;
14159     if(!this.el && config && config.autoCreate){
14160         if(typeof config.autoCreate == "object"){
14161             if(!config.autoCreate.id){
14162                 config.autoCreate.id = el;
14163             }
14164             this.el = dh.append(document.body,
14165                         config.autoCreate, true);
14166         }else{
14167             this.el = dh.append(document.body,
14168                         {tag: "div", id: el, style:'visibility:hidden;'}, true);
14169         }
14170     }
14171     el = this.el;
14172     el.setDisplayed(true);
14173     el.hide = this.hideAction;
14174     this.id = el.id;
14175     el.addClass("x-dlg");
14176
14177     Roo.apply(this, config);
14178
14179     this.proxy = el.createProxy("x-dlg-proxy");
14180     this.proxy.hide = this.hideAction;
14181     this.proxy.setOpacity(.5);
14182     this.proxy.hide();
14183
14184     if(config.width){
14185         el.setWidth(config.width);
14186     }
14187     if(config.height){
14188         el.setHeight(config.height);
14189     }
14190     this.size = el.getSize();
14191     if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14192         this.xy = [config.x,config.y];
14193     }else{
14194         this.xy = el.getCenterXY(true);
14195     }
14196     /** The header element @type Roo.Element */
14197     this.header = el.child("> .x-dlg-hd");
14198     /** The body element @type Roo.Element */
14199     this.body = el.child("> .x-dlg-bd");
14200     /** The footer element @type Roo.Element */
14201     this.footer = el.child("> .x-dlg-ft");
14202
14203     if(!this.header){
14204         this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: "&#160;"}, this.body ? this.body.dom : null);
14205     }
14206     if(!this.body){
14207         this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14208     }
14209
14210     this.header.unselectable();
14211     if(this.title){
14212         this.header.update(this.title);
14213     }
14214     // this element allows the dialog to be focused for keyboard event
14215     this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14216     this.focusEl.swallowEvent("click", true);
14217
14218     this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14219
14220     // wrap the body and footer for special rendering
14221     this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14222     if(this.footer){
14223         this.bwrap.dom.appendChild(this.footer.dom);
14224     }
14225
14226     this.bg = this.el.createChild({
14227         tag: "div", cls:"x-dlg-bg",
14228         html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center">&#160;</div></div></div>'
14229     });
14230     this.centerBg = this.bg.child("div.x-dlg-bg-center");
14231
14232
14233     if(this.autoScroll !== false && !this.autoTabs){
14234         this.body.setStyle("overflow", "auto");
14235     }
14236
14237     this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14238
14239     if(this.closable !== false){
14240         this.el.addClass("x-dlg-closable");
14241         this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14242         this.close.on("click", this.closeClick, this);
14243         this.close.addClassOnOver("x-dlg-close-over");
14244     }
14245     if(this.collapsible !== false){
14246         this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14247         this.collapseBtn.on("click", this.collapseClick, this);
14248         this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14249         this.header.on("dblclick", this.collapseClick, this);
14250     }
14251     if(this.resizable !== false){
14252         this.el.addClass("x-dlg-resizable");
14253         this.resizer = new Roo.Resizable(el, {
14254             minWidth: this.minWidth || 80,
14255             minHeight:this.minHeight || 80,
14256             handles: this.resizeHandles || "all",
14257             pinned: true
14258         });
14259         this.resizer.on("beforeresize", this.beforeResize, this);
14260         this.resizer.on("resize", this.onResize, this);
14261     }
14262     if(this.draggable !== false){
14263         el.addClass("x-dlg-draggable");
14264         if (!this.proxyDrag) {
14265             var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14266         }
14267         else {
14268             var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14269         }
14270         dd.setHandleElId(this.header.id);
14271         dd.endDrag = this.endMove.createDelegate(this);
14272         dd.startDrag = this.startMove.createDelegate(this);
14273         dd.onDrag = this.onDrag.createDelegate(this);
14274         dd.scroll = false;
14275         this.dd = dd;
14276     }
14277     if(this.modal){
14278         this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14279         this.mask.enableDisplayMode("block");
14280         this.mask.hide();
14281         this.el.addClass("x-dlg-modal");
14282     }
14283     if(this.shadow){
14284         this.shadow = new Roo.Shadow({
14285             mode : typeof this.shadow == "string" ? this.shadow : "sides",
14286             offset : this.shadowOffset
14287         });
14288     }else{
14289         this.shadowOffset = 0;
14290     }
14291     if(Roo.useShims && this.shim !== false){
14292         this.shim = this.el.createShim();
14293         this.shim.hide = this.hideAction;
14294         this.shim.hide();
14295     }else{
14296         this.shim = false;
14297     }
14298     if(this.autoTabs){
14299         this.initTabs();
14300     }
14301     if (this.buttons) { 
14302         var bts= this.buttons;
14303         this.buttons = [];
14304         Roo.each(bts, function(b) {
14305             this.addButton(b);
14306         }, this);
14307     }
14308     
14309     
14310     this.addEvents({
14311         /**
14312          * @event keydown
14313          * Fires when a key is pressed
14314          * @param {Roo.BasicDialog} this
14315          * @param {Roo.EventObject} e
14316          */
14317         "keydown" : true,
14318         /**
14319          * @event move
14320          * Fires when this dialog is moved by the user.
14321          * @param {Roo.BasicDialog} this
14322          * @param {Number} x The new page X
14323          * @param {Number} y The new page Y
14324          */
14325         "move" : true,
14326         /**
14327          * @event resize
14328          * Fires when this dialog is resized by the user.
14329          * @param {Roo.BasicDialog} this
14330          * @param {Number} width The new width
14331          * @param {Number} height The new height
14332          */
14333         "resize" : true,
14334         /**
14335          * @event beforehide
14336          * Fires before this dialog is hidden.
14337          * @param {Roo.BasicDialog} this
14338          */
14339         "beforehide" : true,
14340         /**
14341          * @event hide
14342          * Fires when this dialog is hidden.
14343          * @param {Roo.BasicDialog} this
14344          */
14345         "hide" : true,
14346         /**
14347          * @event beforeshow
14348          * Fires before this dialog is shown.
14349          * @param {Roo.BasicDialog} this
14350          */
14351         "beforeshow" : true,
14352         /**
14353          * @event show
14354          * Fires when this dialog is shown.
14355          * @param {Roo.BasicDialog} this
14356          */
14357         "show" : true
14358     });
14359     el.on("keydown", this.onKeyDown, this);
14360     el.on("mousedown", this.toFront, this);
14361     Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14362     this.el.hide();
14363     Roo.DialogManager.register(this);
14364     Roo.BasicDialog.superclass.constructor.call(this);
14365 };
14366
14367 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14368     shadowOffset: Roo.isIE ? 6 : 5,
14369     minHeight: 80,
14370     minWidth: 200,
14371     minButtonWidth: 75,
14372     defaultButton: null,
14373     buttonAlign: "right",
14374     tabTag: 'div',
14375     firstShow: true,
14376
14377     /**
14378      * Sets the dialog title text
14379      * @param {String} text The title text to display
14380      * @return {Roo.BasicDialog} this
14381      */
14382     setTitle : function(text){
14383         this.header.update(text);
14384         return this;
14385     },
14386
14387     // private
14388     closeClick : function(){
14389         this.hide();
14390     },
14391
14392     // private
14393     collapseClick : function(){
14394         this[this.collapsed ? "expand" : "collapse"]();
14395     },
14396
14397     /**
14398      * Collapses the dialog to its minimized state (only the title bar is visible).
14399      * Equivalent to the user clicking the collapse dialog button.
14400      */
14401     collapse : function(){
14402         if(!this.collapsed){
14403             this.collapsed = true;
14404             this.el.addClass("x-dlg-collapsed");
14405             this.restoreHeight = this.el.getHeight();
14406             this.resizeTo(this.el.getWidth(), this.header.getHeight());
14407         }
14408     },
14409
14410     /**
14411      * Expands a collapsed dialog back to its normal state.  Equivalent to the user
14412      * clicking the expand dialog button.
14413      */
14414     expand : function(){
14415         if(this.collapsed){
14416             this.collapsed = false;
14417             this.el.removeClass("x-dlg-collapsed");
14418             this.resizeTo(this.el.getWidth(), this.restoreHeight);
14419         }
14420     },
14421
14422     /**
14423      * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14424      * @return {Roo.TabPanel} The tabs component
14425      */
14426     initTabs : function(){
14427         var tabs = this.getTabs();
14428         while(tabs.getTab(0)){
14429             tabs.removeTab(0);
14430         }
14431         this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14432             var dom = el.dom;
14433             tabs.addTab(Roo.id(dom), dom.title);
14434             dom.title = "";
14435         });
14436         tabs.activate(0);
14437         return tabs;
14438     },
14439
14440     // private
14441     beforeResize : function(){
14442         this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14443     },
14444
14445     // private
14446     onResize : function(){
14447         this.refreshSize();
14448         this.syncBodyHeight();
14449         this.adjustAssets();
14450         this.focus();
14451         this.fireEvent("resize", this, this.size.width, this.size.height);
14452     },
14453
14454     // private
14455     onKeyDown : function(e){
14456         if(this.isVisible()){
14457             this.fireEvent("keydown", this, e);
14458         }
14459     },
14460
14461     /**
14462      * Resizes the dialog.
14463      * @param {Number} width
14464      * @param {Number} height
14465      * @return {Roo.BasicDialog} this
14466      */
14467     resizeTo : function(width, height){
14468         this.el.setSize(width, height);
14469         this.size = {width: width, height: height};
14470         this.syncBodyHeight();
14471         if(this.fixedcenter){
14472             this.center();
14473         }
14474         if(this.isVisible()){
14475             this.constrainXY();
14476             this.adjustAssets();
14477         }
14478         this.fireEvent("resize", this, width, height);
14479         return this;
14480     },
14481
14482
14483     /**
14484      * Resizes the dialog to fit the specified content size.
14485      * @param {Number} width
14486      * @param {Number} height
14487      * @return {Roo.BasicDialog} this
14488      */
14489     setContentSize : function(w, h){
14490         h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14491         w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14492         //if(!this.el.isBorderBox()){
14493             h +=  this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14494             w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14495         //}
14496         if(this.tabs){
14497             h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14498             w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14499         }
14500         this.resizeTo(w, h);
14501         return this;
14502     },
14503
14504     /**
14505      * Adds a key listener for when this dialog is displayed.  This allows you to hook in a function that will be
14506      * executed in response to a particular key being pressed while the dialog is active.
14507      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14508      *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14509      * @param {Function} fn The function to call
14510      * @param {Object} scope (optional) The scope of the function
14511      * @return {Roo.BasicDialog} this
14512      */
14513     addKeyListener : function(key, fn, scope){
14514         var keyCode, shift, ctrl, alt;
14515         if(typeof key == "object" && !(key instanceof Array)){
14516             keyCode = key["key"];
14517             shift = key["shift"];
14518             ctrl = key["ctrl"];
14519             alt = key["alt"];
14520         }else{
14521             keyCode = key;
14522         }
14523         var handler = function(dlg, e){
14524             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14525                 var k = e.getKey();
14526                 if(keyCode instanceof Array){
14527                     for(var i = 0, len = keyCode.length; i < len; i++){
14528                         if(keyCode[i] == k){
14529                           fn.call(scope || window, dlg, k, e);
14530                           return;
14531                         }
14532                     }
14533                 }else{
14534                     if(k == keyCode){
14535                         fn.call(scope || window, dlg, k, e);
14536                     }
14537                 }
14538             }
14539         };
14540         this.on("keydown", handler);
14541         return this;
14542     },
14543
14544     /**
14545      * Returns the TabPanel component (creates it if it doesn't exist).
14546      * Note: If you wish to simply check for the existence of tabs without creating them,
14547      * check for a null 'tabs' property.
14548      * @return {Roo.TabPanel} The tabs component
14549      */
14550     getTabs : function(){
14551         if(!this.tabs){
14552             this.el.addClass("x-dlg-auto-tabs");
14553             this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14554             this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14555         }
14556         return this.tabs;
14557     },
14558
14559     /**
14560      * Adds a button to the footer section of the dialog.
14561      * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14562      * object or a valid Roo.DomHelper element config
14563      * @param {Function} handler The function called when the button is clicked
14564      * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14565      * @return {Roo.Button} The new button
14566      */
14567     addButton : function(config, handler, scope){
14568         var dh = Roo.DomHelper;
14569         if(!this.footer){
14570             this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14571         }
14572         if(!this.btnContainer){
14573             var tb = this.footer.createChild({
14574
14575                 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14576                 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14577             }, null, true);
14578             this.btnContainer = tb.firstChild.firstChild.firstChild;
14579         }
14580         var bconfig = {
14581             handler: handler,
14582             scope: scope,
14583             minWidth: this.minButtonWidth,
14584             hideParent:true
14585         };
14586         if(typeof config == "string"){
14587             bconfig.text = config;
14588         }else{
14589             if(config.tag){
14590                 bconfig.dhconfig = config;
14591             }else{
14592                 Roo.apply(bconfig, config);
14593             }
14594         }
14595         var fc = false;
14596         if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14597             bconfig.position = Math.max(0, bconfig.position);
14598             fc = this.btnContainer.childNodes[bconfig.position];
14599         }
14600          
14601         var btn = new Roo.Button(
14602             fc ? 
14603                 this.btnContainer.insertBefore(document.createElement("td"),fc)
14604                 : this.btnContainer.appendChild(document.createElement("td")),
14605             //Roo.get(this.btnContainer).createChild( { tag: 'td'},  fc ),
14606             bconfig
14607         );
14608         this.syncBodyHeight();
14609         if(!this.buttons){
14610             /**
14611              * Array of all the buttons that have been added to this dialog via addButton
14612              * @type Array
14613              */
14614             this.buttons = [];
14615         }
14616         this.buttons.push(btn);
14617         return btn;
14618     },
14619
14620     /**
14621      * Sets the default button to be focused when the dialog is displayed.
14622      * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14623      * @return {Roo.BasicDialog} this
14624      */
14625     setDefaultButton : function(btn){
14626         this.defaultButton = btn;
14627         return this;
14628     },
14629
14630     // private
14631     getHeaderFooterHeight : function(safe){
14632         var height = 0;
14633         if(this.header){
14634            height += this.header.getHeight();
14635         }
14636         if(this.footer){
14637            var fm = this.footer.getMargins();
14638             height += (this.footer.getHeight()+fm.top+fm.bottom);
14639         }
14640         height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14641         height += this.centerBg.getPadding("tb");
14642         return height;
14643     },
14644
14645     // private
14646     syncBodyHeight : function(){
14647         var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14648         var height = this.size.height - this.getHeaderFooterHeight(false);
14649         bd.setHeight(height-bd.getMargins("tb"));
14650         var hh = this.header.getHeight();
14651         var h = this.size.height-hh;
14652         cb.setHeight(h);
14653         bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14654         bw.setHeight(h-cb.getPadding("tb"));
14655         bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14656         bd.setWidth(bw.getWidth(true));
14657         if(this.tabs){
14658             this.tabs.syncHeight();
14659             if(Roo.isIE){
14660                 this.tabs.el.repaint();
14661             }
14662         }
14663     },
14664
14665     /**
14666      * Restores the previous state of the dialog if Roo.state is configured.
14667      * @return {Roo.BasicDialog} this
14668      */
14669     restoreState : function(){
14670         var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14671         if(box && box.width){
14672             this.xy = [box.x, box.y];
14673             this.resizeTo(box.width, box.height);
14674         }
14675         return this;
14676     },
14677
14678     // private
14679     beforeShow : function(){
14680         this.expand();
14681         if(this.fixedcenter){
14682             this.xy = this.el.getCenterXY(true);
14683         }
14684         if(this.modal){
14685             Roo.get(document.body).addClass("x-body-masked");
14686             this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14687             this.mask.show();
14688         }
14689         this.constrainXY();
14690     },
14691
14692     // private
14693     animShow : function(){
14694         var b = Roo.get(this.animateTarget).getBox();
14695         this.proxy.setSize(b.width, b.height);
14696         this.proxy.setLocation(b.x, b.y);
14697         this.proxy.show();
14698         this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14699                     true, .35, this.showEl.createDelegate(this));
14700     },
14701
14702     /**
14703      * Shows the dialog.
14704      * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14705      * @return {Roo.BasicDialog} this
14706      */
14707     show : function(animateTarget){
14708         if (this.fireEvent("beforeshow", this) === false){
14709             return;
14710         }
14711         if(this.syncHeightBeforeShow){
14712             this.syncBodyHeight();
14713         }else if(this.firstShow){
14714             this.firstShow = false;
14715             this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14716         }
14717         this.animateTarget = animateTarget || this.animateTarget;
14718         if(!this.el.isVisible()){
14719             this.beforeShow();
14720             if(this.animateTarget && Roo.get(this.animateTarget)){
14721                 this.animShow();
14722             }else{
14723                 this.showEl();
14724             }
14725         }
14726         return this;
14727     },
14728
14729     // private
14730     showEl : function(){
14731         this.proxy.hide();
14732         this.el.setXY(this.xy);
14733         this.el.show();
14734         this.adjustAssets(true);
14735         this.toFront();
14736         this.focus();
14737         // IE peekaboo bug - fix found by Dave Fenwick
14738         if(Roo.isIE){
14739             this.el.repaint();
14740         }
14741         this.fireEvent("show", this);
14742     },
14743
14744     /**
14745      * Focuses the dialog.  If a defaultButton is set, it will receive focus, otherwise the
14746      * dialog itself will receive focus.
14747      */
14748     focus : function(){
14749         if(this.defaultButton){
14750             this.defaultButton.focus();
14751         }else{
14752             this.focusEl.focus();
14753         }
14754     },
14755
14756     // private
14757     constrainXY : function(){
14758         if(this.constraintoviewport !== false){
14759             if(!this.viewSize){
14760                 if(this.container){
14761                     var s = this.container.getSize();
14762                     this.viewSize = [s.width, s.height];
14763                 }else{
14764                     this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14765                 }
14766             }
14767             var s = Roo.get(this.container||document).getScroll();
14768
14769             var x = this.xy[0], y = this.xy[1];
14770             var w = this.size.width, h = this.size.height;
14771             var vw = this.viewSize[0], vh = this.viewSize[1];
14772             // only move it if it needs it
14773             var moved = false;
14774             // first validate right/bottom
14775             if(x + w > vw+s.left){
14776                 x = vw - w;
14777                 moved = true;
14778             }
14779             if(y + h > vh+s.top){
14780                 y = vh - h;
14781                 moved = true;
14782             }
14783             // then make sure top/left isn't negative
14784             if(x < s.left){
14785                 x = s.left;
14786                 moved = true;
14787             }
14788             if(y < s.top){
14789                 y = s.top;
14790                 moved = true;
14791             }
14792             if(moved){
14793                 // cache xy
14794                 this.xy = [x, y];
14795                 if(this.isVisible()){
14796                     this.el.setLocation(x, y);
14797                     this.adjustAssets();
14798                 }
14799             }
14800         }
14801     },
14802
14803     // private
14804     onDrag : function(){
14805         if(!this.proxyDrag){
14806             this.xy = this.el.getXY();
14807             this.adjustAssets();
14808         }
14809     },
14810
14811     // private
14812     adjustAssets : function(doShow){
14813         var x = this.xy[0], y = this.xy[1];
14814         var w = this.size.width, h = this.size.height;
14815         if(doShow === true){
14816             if(this.shadow){
14817                 this.shadow.show(this.el);
14818             }
14819             if(this.shim){
14820                 this.shim.show();
14821             }
14822         }
14823         if(this.shadow && this.shadow.isVisible()){
14824             this.shadow.show(this.el);
14825         }
14826         if(this.shim && this.shim.isVisible()){
14827             this.shim.setBounds(x, y, w, h);
14828         }
14829     },
14830
14831     // private
14832     adjustViewport : function(w, h){
14833         if(!w || !h){
14834             w = Roo.lib.Dom.getViewWidth();
14835             h = Roo.lib.Dom.getViewHeight();
14836         }
14837         // cache the size
14838         this.viewSize = [w, h];
14839         if(this.modal && this.mask.isVisible()){
14840             this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14841             this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14842         }
14843         if(this.isVisible()){
14844             this.constrainXY();
14845         }
14846     },
14847
14848     /**
14849      * Destroys this dialog and all its supporting elements (including any tabs, shim,
14850      * shadow, proxy, mask, etc.)  Also removes all event listeners.
14851      * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14852      */
14853     destroy : function(removeEl){
14854         if(this.isVisible()){
14855             this.animateTarget = null;
14856             this.hide();
14857         }
14858         Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14859         if(this.tabs){
14860             this.tabs.destroy(removeEl);
14861         }
14862         Roo.destroy(
14863              this.shim,
14864              this.proxy,
14865              this.resizer,
14866              this.close,
14867              this.mask
14868         );
14869         if(this.dd){
14870             this.dd.unreg();
14871         }
14872         if(this.buttons){
14873            for(var i = 0, len = this.buttons.length; i < len; i++){
14874                this.buttons[i].destroy();
14875            }
14876         }
14877         this.el.removeAllListeners();
14878         if(removeEl === true){
14879             this.el.update("");
14880             this.el.remove();
14881         }
14882         Roo.DialogManager.unregister(this);
14883     },
14884
14885     // private
14886     startMove : function(){
14887         if(this.proxyDrag){
14888             this.proxy.show();
14889         }
14890         if(this.constraintoviewport !== false){
14891             this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14892         }
14893     },
14894
14895     // private
14896     endMove : function(){
14897         if(!this.proxyDrag){
14898             Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14899         }else{
14900             Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14901             this.proxy.hide();
14902         }
14903         this.refreshSize();
14904         this.adjustAssets();
14905         this.focus();
14906         this.fireEvent("move", this, this.xy[0], this.xy[1]);
14907     },
14908
14909     /**
14910      * Brings this dialog to the front of any other visible dialogs
14911      * @return {Roo.BasicDialog} this
14912      */
14913     toFront : function(){
14914         Roo.DialogManager.bringToFront(this);
14915         return this;
14916     },
14917
14918     /**
14919      * Sends this dialog to the back (under) of any other visible dialogs
14920      * @return {Roo.BasicDialog} this
14921      */
14922     toBack : function(){
14923         Roo.DialogManager.sendToBack(this);
14924         return this;
14925     },
14926
14927     /**
14928      * Centers this dialog in the viewport
14929      * @return {Roo.BasicDialog} this
14930      */
14931     center : function(){
14932         var xy = this.el.getCenterXY(true);
14933         this.moveTo(xy[0], xy[1]);
14934         return this;
14935     },
14936
14937     /**
14938      * Moves the dialog's top-left corner to the specified point
14939      * @param {Number} x
14940      * @param {Number} y
14941      * @return {Roo.BasicDialog} this
14942      */
14943     moveTo : function(x, y){
14944         this.xy = [x,y];
14945         if(this.isVisible()){
14946             this.el.setXY(this.xy);
14947             this.adjustAssets();
14948         }
14949         return this;
14950     },
14951
14952     /**
14953      * Aligns the dialog to the specified element
14954      * @param {String/HTMLElement/Roo.Element} element The element to align to.
14955      * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14956      * @param {Array} offsets (optional) Offset the positioning by [x, y]
14957      * @return {Roo.BasicDialog} this
14958      */
14959     alignTo : function(element, position, offsets){
14960         this.xy = this.el.getAlignToXY(element, position, offsets);
14961         if(this.isVisible()){
14962             this.el.setXY(this.xy);
14963             this.adjustAssets();
14964         }
14965         return this;
14966     },
14967
14968     /**
14969      * Anchors an element to another element and realigns it when the window is resized.
14970      * @param {String/HTMLElement/Roo.Element} element The element to align to.
14971      * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14972      * @param {Array} offsets (optional) Offset the positioning by [x, y]
14973      * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14974      * is a number, it is used as the buffer delay (defaults to 50ms).
14975      * @return {Roo.BasicDialog} this
14976      */
14977     anchorTo : function(el, alignment, offsets, monitorScroll){
14978         var action = function(){
14979             this.alignTo(el, alignment, offsets);
14980         };
14981         Roo.EventManager.onWindowResize(action, this);
14982         var tm = typeof monitorScroll;
14983         if(tm != 'undefined'){
14984             Roo.EventManager.on(window, 'scroll', action, this,
14985                 {buffer: tm == 'number' ? monitorScroll : 50});
14986         }
14987         action.call(this);
14988         return this;
14989     },
14990
14991     /**
14992      * Returns true if the dialog is visible
14993      * @return {Boolean}
14994      */
14995     isVisible : function(){
14996         return this.el.isVisible();
14997     },
14998
14999     // private
15000     animHide : function(callback){
15001         var b = Roo.get(this.animateTarget).getBox();
15002         this.proxy.show();
15003         this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15004         this.el.hide();
15005         this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15006                     this.hideEl.createDelegate(this, [callback]));
15007     },
15008
15009     /**
15010      * Hides the dialog.
15011      * @param {Function} callback (optional) Function to call when the dialog is hidden
15012      * @return {Roo.BasicDialog} this
15013      */
15014     hide : function(callback){
15015         if (this.fireEvent("beforehide", this) === false){
15016             return;
15017         }
15018         if(this.shadow){
15019             this.shadow.hide();
15020         }
15021         if(this.shim) {
15022           this.shim.hide();
15023         }
15024         // sometimes animateTarget seems to get set.. causing problems...
15025         // this just double checks..
15026         if(this.animateTarget && Roo.get(this.animateTarget)) {
15027            this.animHide(callback);
15028         }else{
15029             this.el.hide();
15030             this.hideEl(callback);
15031         }
15032         return this;
15033     },
15034
15035     // private
15036     hideEl : function(callback){
15037         this.proxy.hide();
15038         if(this.modal){
15039             this.mask.hide();
15040             Roo.get(document.body).removeClass("x-body-masked");
15041         }
15042         this.fireEvent("hide", this);
15043         if(typeof callback == "function"){
15044             callback();
15045         }
15046     },
15047
15048     // private
15049     hideAction : function(){
15050         this.setLeft("-10000px");
15051         this.setTop("-10000px");
15052         this.setStyle("visibility", "hidden");
15053     },
15054
15055     // private
15056     refreshSize : function(){
15057         this.size = this.el.getSize();
15058         this.xy = this.el.getXY();
15059         Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15060     },
15061
15062     // private
15063     // z-index is managed by the DialogManager and may be overwritten at any time
15064     setZIndex : function(index){
15065         if(this.modal){
15066             this.mask.setStyle("z-index", index);
15067         }
15068         if(this.shim){
15069             this.shim.setStyle("z-index", ++index);
15070         }
15071         if(this.shadow){
15072             this.shadow.setZIndex(++index);
15073         }
15074         this.el.setStyle("z-index", ++index);
15075         if(this.proxy){
15076             this.proxy.setStyle("z-index", ++index);
15077         }
15078         if(this.resizer){
15079             this.resizer.proxy.setStyle("z-index", ++index);
15080         }
15081
15082         this.lastZIndex = index;
15083     },
15084
15085     /**
15086      * Returns the element for this dialog
15087      * @return {Roo.Element} The underlying dialog Element
15088      */
15089     getEl : function(){
15090         return this.el;
15091     }
15092 });
15093
15094 /**
15095  * @class Roo.DialogManager
15096  * Provides global access to BasicDialogs that have been created and
15097  * support for z-indexing (layering) multiple open dialogs.
15098  */
15099 Roo.DialogManager = function(){
15100     var list = {};
15101     var accessList = [];
15102     var front = null;
15103
15104     // private
15105     var sortDialogs = function(d1, d2){
15106         return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15107     };
15108
15109     // private
15110     var orderDialogs = function(){
15111         accessList.sort(sortDialogs);
15112         var seed = Roo.DialogManager.zseed;
15113         for(var i = 0, len = accessList.length; i < len; i++){
15114             var dlg = accessList[i];
15115             if(dlg){
15116                 dlg.setZIndex(seed + (i*10));
15117             }
15118         }
15119     };
15120
15121     return {
15122         /**
15123          * The starting z-index for BasicDialogs (defaults to 9000)
15124          * @type Number The z-index value
15125          */
15126         zseed : 9000,
15127
15128         // private
15129         register : function(dlg){
15130             list[dlg.id] = dlg;
15131             accessList.push(dlg);
15132         },
15133
15134         // private
15135         unregister : function(dlg){
15136             delete list[dlg.id];
15137             var i=0;
15138             var len=0;
15139             if(!accessList.indexOf){
15140                 for(  i = 0, len = accessList.length; i < len; i++){
15141                     if(accessList[i] == dlg){
15142                         accessList.splice(i, 1);
15143                         return;
15144                     }
15145                 }
15146             }else{
15147                  i = accessList.indexOf(dlg);
15148                 if(i != -1){
15149                     accessList.splice(i, 1);
15150                 }
15151             }
15152         },
15153
15154         /**
15155          * Gets a registered dialog by id
15156          * @param {String/Object} id The id of the dialog or a dialog
15157          * @return {Roo.BasicDialog} this
15158          */
15159         get : function(id){
15160             return typeof id == "object" ? id : list[id];
15161         },
15162
15163         /**
15164          * Brings the specified dialog to the front
15165          * @param {String/Object} dlg The id of the dialog or a dialog
15166          * @return {Roo.BasicDialog} this
15167          */
15168         bringToFront : function(dlg){
15169             dlg = this.get(dlg);
15170             if(dlg != front){
15171                 front = dlg;
15172                 dlg._lastAccess = new Date().getTime();
15173                 orderDialogs();
15174             }
15175             return dlg;
15176         },
15177
15178         /**
15179          * Sends the specified dialog to the back
15180          * @param {String/Object} dlg The id of the dialog or a dialog
15181          * @return {Roo.BasicDialog} this
15182          */
15183         sendToBack : function(dlg){
15184             dlg = this.get(dlg);
15185             dlg._lastAccess = -(new Date().getTime());
15186             orderDialogs();
15187             return dlg;
15188         },
15189
15190         /**
15191          * Hides all dialogs
15192          */
15193         hideAll : function(){
15194             for(var id in list){
15195                 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15196                     list[id].hide();
15197                 }
15198             }
15199         }
15200     };
15201 }();
15202
15203 /**
15204  * @class Roo.LayoutDialog
15205  * @extends Roo.BasicDialog
15206  * Dialog which provides adjustments for working with a layout in a Dialog.
15207  * Add your necessary layout config options to the dialog's config.<br>
15208  * Example usage (including a nested layout):
15209  * <pre><code>
15210 if(!dialog){
15211     dialog = new Roo.LayoutDialog("download-dlg", {
15212         modal: true,
15213         width:600,
15214         height:450,
15215         shadow:true,
15216         minWidth:500,
15217         minHeight:350,
15218         autoTabs:true,
15219         proxyDrag:true,
15220         // layout config merges with the dialog config
15221         center:{
15222             tabPosition: "top",
15223             alwaysShowTabs: true
15224         }
15225     });
15226     dialog.addKeyListener(27, dialog.hide, dialog);
15227     dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15228     dialog.addButton("Build It!", this.getDownload, this);
15229
15230     // we can even add nested layouts
15231     var innerLayout = new Roo.BorderLayout("dl-inner", {
15232         east: {
15233             initialSize: 200,
15234             autoScroll:true,
15235             split:true
15236         },
15237         center: {
15238             autoScroll:true
15239         }
15240     });
15241     innerLayout.beginUpdate();
15242     innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15243     innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15244     innerLayout.endUpdate(true);
15245
15246     var layout = dialog.getLayout();
15247     layout.beginUpdate();
15248     layout.add("center", new Roo.ContentPanel("standard-panel",
15249                         {title: "Download the Source", fitToFrame:true}));
15250     layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15251                {title: "Build your own roo.js"}));
15252     layout.getRegion("center").showPanel(sp);
15253     layout.endUpdate();
15254 }
15255 </code></pre>
15256     * @constructor
15257     * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15258     * @param {Object} config configuration options
15259   */
15260 Roo.LayoutDialog = function(el, cfg){
15261     
15262     var config=  cfg;
15263     if (typeof(cfg) == 'undefined') {
15264         config = Roo.apply({}, el);
15265         // not sure why we use documentElement here.. - it should always be body.
15266         // IE7 borks horribly if we use documentElement.
15267         el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15268         //config.autoCreate = true;
15269     }
15270     
15271     
15272     config.autoTabs = false;
15273     Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15274     this.body.setStyle({overflow:"hidden", position:"relative"});
15275     this.layout = new Roo.BorderLayout(this.body.dom, config);
15276     this.layout.monitorWindowResize = false;
15277     this.el.addClass("x-dlg-auto-layout");
15278     // fix case when center region overwrites center function
15279     this.center = Roo.BasicDialog.prototype.center;
15280     this.on("show", this.layout.layout, this.layout, true);
15281     if (config.items) {
15282         var xitems = config.items;
15283         delete config.items;
15284         Roo.each(xitems, this.addxtype, this);
15285     }
15286     
15287     
15288 };
15289 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15290     /**
15291      * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15292      * @deprecated
15293      */
15294     endUpdate : function(){
15295         this.layout.endUpdate();
15296     },
15297
15298     /**
15299      * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15300      *  @deprecated
15301      */
15302     beginUpdate : function(){
15303         this.layout.beginUpdate();
15304     },
15305
15306     /**
15307      * Get the BorderLayout for this dialog
15308      * @return {Roo.BorderLayout}
15309      */
15310     getLayout : function(){
15311         return this.layout;
15312     },
15313
15314     showEl : function(){
15315         Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15316         if(Roo.isIE7){
15317             this.layout.layout();
15318         }
15319     },
15320
15321     // private
15322     // Use the syncHeightBeforeShow config option to control this automatically
15323     syncBodyHeight : function(){
15324         Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15325         if(this.layout){this.layout.layout();}
15326     },
15327     
15328       /**
15329      * Add an xtype element (actually adds to the layout.)
15330      * @return {Object} xdata xtype object data.
15331      */
15332     
15333     addxtype : function(c) {
15334         return this.layout.addxtype(c);
15335     }
15336 });/*
15337  * Based on:
15338  * Ext JS Library 1.1.1
15339  * Copyright(c) 2006-2007, Ext JS, LLC.
15340  *
15341  * Originally Released Under LGPL - original licence link has changed is not relivant.
15342  *
15343  * Fork - LGPL
15344  * <script type="text/javascript">
15345  */
15346  
15347 /**
15348  * @class Roo.MessageBox
15349  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
15350  * Example usage:
15351  *<pre><code>
15352 // Basic alert:
15353 Roo.Msg.alert('Status', 'Changes saved successfully.');
15354
15355 // Prompt for user data:
15356 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15357     if (btn == 'ok'){
15358         // process text value...
15359     }
15360 });
15361
15362 // Show a dialog using config options:
15363 Roo.Msg.show({
15364    title:'Save Changes?',
15365    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15366    buttons: Roo.Msg.YESNOCANCEL,
15367    fn: processResult,
15368    animEl: 'elId'
15369 });
15370 </code></pre>
15371  * @singleton
15372  */
15373 Roo.MessageBox = function(){
15374     var dlg, opt, mask, waitTimer;
15375     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15376     var buttons, activeTextEl, bwidth;
15377
15378     // private
15379     var handleButton = function(button){
15380         dlg.hide();
15381         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15382     };
15383
15384     // private
15385     var handleHide = function(){
15386         if(opt && opt.cls){
15387             dlg.el.removeClass(opt.cls);
15388         }
15389         if(waitTimer){
15390             Roo.TaskMgr.stop(waitTimer);
15391             waitTimer = null;
15392         }
15393     };
15394
15395     // private
15396     var updateButtons = function(b){
15397         var width = 0;
15398         if(!b){
15399             buttons["ok"].hide();
15400             buttons["cancel"].hide();
15401             buttons["yes"].hide();
15402             buttons["no"].hide();
15403             dlg.footer.dom.style.display = 'none';
15404             return width;
15405         }
15406         dlg.footer.dom.style.display = '';
15407         for(var k in buttons){
15408             if(typeof buttons[k] != "function"){
15409                 if(b[k]){
15410                     buttons[k].show();
15411                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15412                     width += buttons[k].el.getWidth()+15;
15413                 }else{
15414                     buttons[k].hide();
15415                 }
15416             }
15417         }
15418         return width;
15419     };
15420
15421     // private
15422     var handleEsc = function(d, k, e){
15423         if(opt && opt.closable !== false){
15424             dlg.hide();
15425         }
15426         if(e){
15427             e.stopEvent();
15428         }
15429     };
15430
15431     return {
15432         /**
15433          * Returns a reference to the underlying {@link Roo.BasicDialog} element
15434          * @return {Roo.BasicDialog} The BasicDialog element
15435          */
15436         getDialog : function(){
15437            if(!dlg){
15438                 dlg = new Roo.BasicDialog("x-msg-box", {
15439                     autoCreate : true,
15440                     shadow: true,
15441                     draggable: true,
15442                     resizable:false,
15443                     constraintoviewport:false,
15444                     fixedcenter:true,
15445                     collapsible : false,
15446                     shim:true,
15447                     modal: true,
15448                     width:400, height:100,
15449                     buttonAlign:"center",
15450                     closeClick : function(){
15451                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15452                             handleButton("no");
15453                         }else{
15454                             handleButton("cancel");
15455                         }
15456                     }
15457                 });
15458                 dlg.on("hide", handleHide);
15459                 mask = dlg.mask;
15460                 dlg.addKeyListener(27, handleEsc);
15461                 buttons = {};
15462                 var bt = this.buttonText;
15463                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15464                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15465                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15466                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15467                 bodyEl = dlg.body.createChild({
15468
15469                     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>'
15470                 });
15471                 msgEl = bodyEl.dom.firstChild;
15472                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15473                 textboxEl.enableDisplayMode();
15474                 textboxEl.addKeyListener([10,13], function(){
15475                     if(dlg.isVisible() && opt && opt.buttons){
15476                         if(opt.buttons.ok){
15477                             handleButton("ok");
15478                         }else if(opt.buttons.yes){
15479                             handleButton("yes");
15480                         }
15481                     }
15482                 });
15483                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15484                 textareaEl.enableDisplayMode();
15485                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15486                 progressEl.enableDisplayMode();
15487                 var pf = progressEl.dom.firstChild;
15488                 if (pf) {
15489                     pp = Roo.get(pf.firstChild);
15490                     pp.setHeight(pf.offsetHeight);
15491                 }
15492                 
15493             }
15494             return dlg;
15495         },
15496
15497         /**
15498          * Updates the message box body text
15499          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15500          * the XHTML-compliant non-breaking space character '&amp;#160;')
15501          * @return {Roo.MessageBox} This message box
15502          */
15503         updateText : function(text){
15504             if(!dlg.isVisible() && !opt.width){
15505                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15506             }
15507             msgEl.innerHTML = text || '&#160;';
15508             var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth), 
15509                         Math.max(opt.minWidth || this.minWidth, bwidth));
15510             if(opt.prompt){
15511                 activeTextEl.setWidth(w);
15512             }
15513             if(dlg.isVisible()){
15514                 dlg.fixedcenter = false;
15515             }
15516             dlg.setContentSize(w, bodyEl.getHeight());
15517             if(dlg.isVisible()){
15518                 dlg.fixedcenter = true;
15519             }
15520             return this;
15521         },
15522
15523         /**
15524          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
15525          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15526          * @param {Number} value Any number between 0 and 1 (e.g., .5)
15527          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15528          * @return {Roo.MessageBox} This message box
15529          */
15530         updateProgress : function(value, text){
15531             if(text){
15532                 this.updateText(text);
15533             }
15534             if (pp) { // weird bug on my firefox - for some reason this is not defined
15535                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15536             }
15537             return this;
15538         },        
15539
15540         /**
15541          * Returns true if the message box is currently displayed
15542          * @return {Boolean} True if the message box is visible, else false
15543          */
15544         isVisible : function(){
15545             return dlg && dlg.isVisible();  
15546         },
15547
15548         /**
15549          * Hides the message box if it is displayed
15550          */
15551         hide : function(){
15552             if(this.isVisible()){
15553                 dlg.hide();
15554             }  
15555         },
15556
15557         /**
15558          * Displays a new message box, or reinitializes an existing message box, based on the config options
15559          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15560          * The following config object properties are supported:
15561          * <pre>
15562 Property    Type             Description
15563 ----------  ---------------  ------------------------------------------------------------------------------------
15564 animEl            String/Element   An id or Element from which the message box should animate as it opens and
15565                                    closes (defaults to undefined)
15566 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15567                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
15568 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
15569                                    progress and wait dialogs will ignore this property and always hide the
15570                                    close button as they can only be closed programmatically.
15571 cls               String           A custom CSS class to apply to the message box element
15572 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
15573                                    displayed (defaults to 75)
15574 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
15575                                    function will be btn (the name of the button that was clicked, if applicable,
15576                                    e.g. "ok"), and text (the value of the active text field, if applicable).
15577                                    Progress and wait dialogs will ignore this option since they do not respond to
15578                                    user actions and can only be closed programmatically, so any required function
15579                                    should be called by the same code after it closes the dialog.
15580 icon              String           A CSS class that provides a background image to be used as an icon for
15581                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15582 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
15583 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
15584 modal             Boolean          False to allow user interaction with the page while the message box is
15585                                    displayed (defaults to true)
15586 msg               String           A string that will replace the existing message box body text (defaults
15587                                    to the XHTML-compliant non-breaking space character '&#160;')
15588 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
15589 progress          Boolean          True to display a progress bar (defaults to false)
15590 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
15591 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
15592 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
15593 title             String           The title text
15594 value             String           The string value to set into the active textbox element if displayed
15595 wait              Boolean          True to display a progress bar (defaults to false)
15596 width             Number           The width of the dialog in pixels
15597 </pre>
15598          *
15599          * Example usage:
15600          * <pre><code>
15601 Roo.Msg.show({
15602    title: 'Address',
15603    msg: 'Please enter your address:',
15604    width: 300,
15605    buttons: Roo.MessageBox.OKCANCEL,
15606    multiline: true,
15607    fn: saveAddress,
15608    animEl: 'addAddressBtn'
15609 });
15610 </code></pre>
15611          * @param {Object} config Configuration options
15612          * @return {Roo.MessageBox} This message box
15613          */
15614         show : function(options){
15615             if(this.isVisible()){
15616                 this.hide();
15617             }
15618             var d = this.getDialog();
15619             opt = options;
15620             d.setTitle(opt.title || "&#160;");
15621             d.close.setDisplayed(opt.closable !== false);
15622             activeTextEl = textboxEl;
15623             opt.prompt = opt.prompt || (opt.multiline ? true : false);
15624             if(opt.prompt){
15625                 if(opt.multiline){
15626                     textboxEl.hide();
15627                     textareaEl.show();
15628                     textareaEl.setHeight(typeof opt.multiline == "number" ?
15629                         opt.multiline : this.defaultTextHeight);
15630                     activeTextEl = textareaEl;
15631                 }else{
15632                     textboxEl.show();
15633                     textareaEl.hide();
15634                 }
15635             }else{
15636                 textboxEl.hide();
15637                 textareaEl.hide();
15638             }
15639             progressEl.setDisplayed(opt.progress === true);
15640             this.updateProgress(0);
15641             activeTextEl.dom.value = opt.value || "";
15642             if(opt.prompt){
15643                 dlg.setDefaultButton(activeTextEl);
15644             }else{
15645                 var bs = opt.buttons;
15646                 var db = null;
15647                 if(bs && bs.ok){
15648                     db = buttons["ok"];
15649                 }else if(bs && bs.yes){
15650                     db = buttons["yes"];
15651                 }
15652                 dlg.setDefaultButton(db);
15653             }
15654             bwidth = updateButtons(opt.buttons);
15655             this.updateText(opt.msg);
15656             if(opt.cls){
15657                 d.el.addClass(opt.cls);
15658             }
15659             d.proxyDrag = opt.proxyDrag === true;
15660             d.modal = opt.modal !== false;
15661             d.mask = opt.modal !== false ? mask : false;
15662             if(!d.isVisible()){
15663                 // force it to the end of the z-index stack so it gets a cursor in FF
15664                 document.body.appendChild(dlg.el.dom);
15665                 d.animateTarget = null;
15666                 d.show(options.animEl);
15667             }
15668             return this;
15669         },
15670
15671         /**
15672          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
15673          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15674          * and closing the message box when the process is complete.
15675          * @param {String} title The title bar text
15676          * @param {String} msg The message box body text
15677          * @return {Roo.MessageBox} This message box
15678          */
15679         progress : function(title, msg){
15680             this.show({
15681                 title : title,
15682                 msg : msg,
15683                 buttons: false,
15684                 progress:true,
15685                 closable:false,
15686                 minWidth: this.minProgressWidth,
15687                 modal : true
15688             });
15689             return this;
15690         },
15691
15692         /**
15693          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15694          * If a callback function is passed it will be called after the user clicks the button, and the
15695          * id of the button that was clicked will be passed as the only parameter to the callback
15696          * (could also be the top-right close button).
15697          * @param {String} title The title bar text
15698          * @param {String} msg The message box body text
15699          * @param {Function} fn (optional) The callback function invoked after the message box is closed
15700          * @param {Object} scope (optional) The scope of the callback function
15701          * @return {Roo.MessageBox} This message box
15702          */
15703         alert : function(title, msg, fn, scope){
15704             this.show({
15705                 title : title,
15706                 msg : msg,
15707                 buttons: this.OK,
15708                 fn: fn,
15709                 scope : scope,
15710                 modal : true
15711             });
15712             return this;
15713         },
15714
15715         /**
15716          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
15717          * interaction while waiting for a long-running process to complete that does not have defined intervals.
15718          * You are responsible for closing the message box when the process is complete.
15719          * @param {String} msg The message box body text
15720          * @param {String} title (optional) The title bar text
15721          * @return {Roo.MessageBox} This message box
15722          */
15723         wait : function(msg, title){
15724             this.show({
15725                 title : title,
15726                 msg : msg,
15727                 buttons: false,
15728                 closable:false,
15729                 progress:true,
15730                 modal:true,
15731                 width:300,
15732                 wait:true
15733             });
15734             waitTimer = Roo.TaskMgr.start({
15735                 run: function(i){
15736                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15737                 },
15738                 interval: 1000
15739             });
15740             return this;
15741         },
15742
15743         /**
15744          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15745          * If a callback function is passed it will be called after the user clicks either button, and the id of the
15746          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15747          * @param {String} title The title bar text
15748          * @param {String} msg The message box body text
15749          * @param {Function} fn (optional) The callback function invoked after the message box is closed
15750          * @param {Object} scope (optional) The scope of the callback function
15751          * @return {Roo.MessageBox} This message box
15752          */
15753         confirm : function(title, msg, fn, scope){
15754             this.show({
15755                 title : title,
15756                 msg : msg,
15757                 buttons: this.YESNO,
15758                 fn: fn,
15759                 scope : scope,
15760                 modal : true
15761             });
15762             return this;
15763         },
15764
15765         /**
15766          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15767          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
15768          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15769          * (could also be the top-right close button) and the text that was entered will be passed as the two
15770          * parameters to the callback.
15771          * @param {String} title The title bar text
15772          * @param {String} msg The message box body text
15773          * @param {Function} fn (optional) The callback function invoked after the message box is closed
15774          * @param {Object} scope (optional) The scope of the callback function
15775          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15776          * property, or the height in pixels to create the textbox (defaults to false / single-line)
15777          * @return {Roo.MessageBox} This message box
15778          */
15779         prompt : function(title, msg, fn, scope, multiline){
15780             this.show({
15781                 title : title,
15782                 msg : msg,
15783                 buttons: this.OKCANCEL,
15784                 fn: fn,
15785                 minWidth:250,
15786                 scope : scope,
15787                 prompt:true,
15788                 multiline: multiline,
15789                 modal : true
15790             });
15791             return this;
15792         },
15793
15794         /**
15795          * Button config that displays a single OK button
15796          * @type Object
15797          */
15798         OK : {ok:true},
15799         /**
15800          * Button config that displays Yes and No buttons
15801          * @type Object
15802          */
15803         YESNO : {yes:true, no:true},
15804         /**
15805          * Button config that displays OK and Cancel buttons
15806          * @type Object
15807          */
15808         OKCANCEL : {ok:true, cancel:true},
15809         /**
15810          * Button config that displays Yes, No and Cancel buttons
15811          * @type Object
15812          */
15813         YESNOCANCEL : {yes:true, no:true, cancel:true},
15814
15815         /**
15816          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15817          * @type Number
15818          */
15819         defaultTextHeight : 75,
15820         /**
15821          * The maximum width in pixels of the message box (defaults to 600)
15822          * @type Number
15823          */
15824         maxWidth : 600,
15825         /**
15826          * The minimum width in pixels of the message box (defaults to 100)
15827          * @type Number
15828          */
15829         minWidth : 100,
15830         /**
15831          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
15832          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15833          * @type Number
15834          */
15835         minProgressWidth : 250,
15836         /**
15837          * An object containing the default button text strings that can be overriden for localized language support.
15838          * Supported properties are: ok, cancel, yes and no.
15839          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15840          * @type Object
15841          */
15842         buttonText : {
15843             ok : "OK",
15844             cancel : "Cancel",
15845             yes : "Yes",
15846             no : "No"
15847         }
15848     };
15849 }();
15850
15851 /**
15852  * Shorthand for {@link Roo.MessageBox}
15853  */
15854 Roo.Msg = Roo.MessageBox;/*
15855  * Based on:
15856  * Ext JS Library 1.1.1
15857  * Copyright(c) 2006-2007, Ext JS, LLC.
15858  *
15859  * Originally Released Under LGPL - original licence link has changed is not relivant.
15860  *
15861  * Fork - LGPL
15862  * <script type="text/javascript">
15863  */
15864 /**
15865  * @class Roo.QuickTips
15866  * Provides attractive and customizable tooltips for any element.
15867  * @singleton
15868  */
15869 Roo.QuickTips = function(){
15870     var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15871     var ce, bd, xy, dd;
15872     var visible = false, disabled = true, inited = false;
15873     var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15874     
15875     var onOver = function(e){
15876         if(disabled){
15877             return;
15878         }
15879         var t = e.getTarget();
15880         if(!t || t.nodeType !== 1 || t == document || t == document.body){
15881             return;
15882         }
15883         if(ce && t == ce.el){
15884             clearTimeout(hideProc);
15885             return;
15886         }
15887         if(t && tagEls[t.id]){
15888             tagEls[t.id].el = t;
15889             showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15890             return;
15891         }
15892         var ttp, et = Roo.fly(t);
15893         var ns = cfg.namespace;
15894         if(tm.interceptTitles && t.title){
15895             ttp = t.title;
15896             t.qtip = ttp;
15897             t.removeAttribute("title");
15898             e.preventDefault();
15899         }else{
15900             ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15901         }
15902         if(ttp){
15903             showProc = show.defer(tm.showDelay, tm, [{
15904                 el: t, 
15905                 text: ttp, 
15906                 width: et.getAttributeNS(ns, cfg.width),
15907                 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15908                 title: et.getAttributeNS(ns, cfg.title),
15909                     cls: et.getAttributeNS(ns, cfg.cls)
15910             }]);
15911         }
15912     };
15913     
15914     var onOut = function(e){
15915         clearTimeout(showProc);
15916         var t = e.getTarget();
15917         if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15918             hideProc = setTimeout(hide, tm.hideDelay);
15919         }
15920     };
15921     
15922     var onMove = function(e){
15923         if(disabled){
15924             return;
15925         }
15926         xy = e.getXY();
15927         xy[1] += 18;
15928         if(tm.trackMouse && ce){
15929             el.setXY(xy);
15930         }
15931     };
15932     
15933     var onDown = function(e){
15934         clearTimeout(showProc);
15935         clearTimeout(hideProc);
15936         if(!e.within(el)){
15937             if(tm.hideOnClick){
15938                 hide();
15939                 tm.disable();
15940                 tm.enable.defer(100, tm);
15941             }
15942         }
15943     };
15944     
15945     var getPad = function(){
15946         return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15947     };
15948
15949     var show = function(o){
15950         if(disabled){
15951             return;
15952         }
15953         clearTimeout(dismissProc);
15954         ce = o;
15955         if(removeCls){ // in case manually hidden
15956             el.removeClass(removeCls);
15957             removeCls = null;
15958         }
15959         if(ce.cls){
15960             el.addClass(ce.cls);
15961             removeCls = ce.cls;
15962         }
15963         if(ce.title){
15964             tipTitle.update(ce.title);
15965             tipTitle.show();
15966         }else{
15967             tipTitle.update('');
15968             tipTitle.hide();
15969         }
15970         el.dom.style.width  = tm.maxWidth+'px';
15971         //tipBody.dom.style.width = '';
15972         tipBodyText.update(o.text);
15973         var p = getPad(), w = ce.width;
15974         if(!w){
15975             var td = tipBodyText.dom;
15976             var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15977             if(aw > tm.maxWidth){
15978                 w = tm.maxWidth;
15979             }else if(aw < tm.minWidth){
15980                 w = tm.minWidth;
15981             }else{
15982                 w = aw;
15983             }
15984         }
15985         //tipBody.setWidth(w);
15986         el.setWidth(parseInt(w, 10) + p);
15987         if(ce.autoHide === false){
15988             close.setDisplayed(true);
15989             if(dd){
15990                 dd.unlock();
15991             }
15992         }else{
15993             close.setDisplayed(false);
15994             if(dd){
15995                 dd.lock();
15996             }
15997         }
15998         if(xy){
15999             el.avoidY = xy[1]-18;
16000             el.setXY(xy);
16001         }
16002         if(tm.animate){
16003             el.setOpacity(.1);
16004             el.setStyle("visibility", "visible");
16005             el.fadeIn({callback: afterShow});
16006         }else{
16007             afterShow();
16008         }
16009     };
16010     
16011     var afterShow = function(){
16012         if(ce){
16013             el.show();
16014             esc.enable();
16015             if(tm.autoDismiss && ce.autoHide !== false){
16016                 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16017             }
16018         }
16019     };
16020     
16021     var hide = function(noanim){
16022         clearTimeout(dismissProc);
16023         clearTimeout(hideProc);
16024         ce = null;
16025         if(el.isVisible()){
16026             esc.disable();
16027             if(noanim !== true && tm.animate){
16028                 el.fadeOut({callback: afterHide});
16029             }else{
16030                 afterHide();
16031             } 
16032         }
16033     };
16034     
16035     var afterHide = function(){
16036         el.hide();
16037         if(removeCls){
16038             el.removeClass(removeCls);
16039             removeCls = null;
16040         }
16041     };
16042     
16043     return {
16044         /**
16045         * @cfg {Number} minWidth
16046         * The minimum width of the quick tip (defaults to 40)
16047         */
16048        minWidth : 40,
16049         /**
16050         * @cfg {Number} maxWidth
16051         * The maximum width of the quick tip (defaults to 300)
16052         */
16053        maxWidth : 300,
16054         /**
16055         * @cfg {Boolean} interceptTitles
16056         * True to automatically use the element's DOM title value if available (defaults to false)
16057         */
16058        interceptTitles : false,
16059         /**
16060         * @cfg {Boolean} trackMouse
16061         * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16062         */
16063        trackMouse : false,
16064         /**
16065         * @cfg {Boolean} hideOnClick
16066         * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16067         */
16068        hideOnClick : true,
16069         /**
16070         * @cfg {Number} showDelay
16071         * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16072         */
16073        showDelay : 500,
16074         /**
16075         * @cfg {Number} hideDelay
16076         * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16077         */
16078        hideDelay : 200,
16079         /**
16080         * @cfg {Boolean} autoHide
16081         * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16082         * Used in conjunction with hideDelay.
16083         */
16084        autoHide : true,
16085         /**
16086         * @cfg {Boolean}
16087         * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16088         * (defaults to true).  Used in conjunction with autoDismissDelay.
16089         */
16090        autoDismiss : true,
16091         /**
16092         * @cfg {Number}
16093         * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16094         */
16095        autoDismissDelay : 5000,
16096        /**
16097         * @cfg {Boolean} animate
16098         * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16099         */
16100        animate : false,
16101
16102        /**
16103         * @cfg {String} title
16104         * Title text to display (defaults to '').  This can be any valid HTML markup.
16105         */
16106         title: '',
16107        /**
16108         * @cfg {String} text
16109         * Body text to display (defaults to '').  This can be any valid HTML markup.
16110         */
16111         text : '',
16112        /**
16113         * @cfg {String} cls
16114         * A CSS class to apply to the base quick tip element (defaults to '').
16115         */
16116         cls : '',
16117        /**
16118         * @cfg {Number} width
16119         * Width in pixels of the quick tip (defaults to auto).  Width will be ignored if it exceeds the bounds of
16120         * minWidth or maxWidth.
16121         */
16122         width : null,
16123
16124     /**
16125      * Initialize and enable QuickTips for first use.  This should be called once before the first attempt to access
16126      * or display QuickTips in a page.
16127      */
16128        init : function(){
16129           tm = Roo.QuickTips;
16130           cfg = tm.tagConfig;
16131           if(!inited){
16132               if(!Roo.isReady){ // allow calling of init() before onReady
16133                   Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16134                   return;
16135               }
16136               el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16137               el.fxDefaults = {stopFx: true};
16138               // maximum custom styling
16139               //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>');
16140               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>');              
16141               tipTitle = el.child('h3');
16142               tipTitle.enableDisplayMode("block");
16143               tipBody = el.child('div.x-tip-bd');
16144               tipBodyText = el.child('div.x-tip-bd-inner');
16145               //bdLeft = el.child('div.x-tip-bd-left');
16146               //bdRight = el.child('div.x-tip-bd-right');
16147               close = el.child('div.x-tip-close');
16148               close.enableDisplayMode("block");
16149               close.on("click", hide);
16150               var d = Roo.get(document);
16151               d.on("mousedown", onDown);
16152               d.on("mouseover", onOver);
16153               d.on("mouseout", onOut);
16154               d.on("mousemove", onMove);
16155               esc = d.addKeyListener(27, hide);
16156               esc.disable();
16157               if(Roo.dd.DD){
16158                   dd = el.initDD("default", null, {
16159                       onDrag : function(){
16160                           el.sync();  
16161                       }
16162                   });
16163                   dd.setHandleElId(tipTitle.id);
16164                   dd.lock();
16165               }
16166               inited = true;
16167           }
16168           this.enable(); 
16169        },
16170
16171     /**
16172      * Configures a new quick tip instance and assigns it to a target element.  The following config options
16173      * are supported:
16174      * <pre>
16175 Property    Type                   Description
16176 ----------  ---------------------  ------------------------------------------------------------------------
16177 target      Element/String/Array   An Element, id or array of ids that this quick tip should be tied to
16178      * </ul>
16179      * @param {Object} config The config object
16180      */
16181        register : function(config){
16182            var cs = config instanceof Array ? config : arguments;
16183            for(var i = 0, len = cs.length; i < len; i++) {
16184                var c = cs[i];
16185                var target = c.target;
16186                if(target){
16187                    if(target instanceof Array){
16188                        for(var j = 0, jlen = target.length; j < jlen; j++){
16189                            tagEls[target[j]] = c;
16190                        }
16191                    }else{
16192                        tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16193                    }
16194                }
16195            }
16196        },
16197
16198     /**
16199      * Removes this quick tip from its element and destroys it.
16200      * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16201      */
16202        unregister : function(el){
16203            delete tagEls[Roo.id(el)];
16204        },
16205
16206     /**
16207      * Enable this quick tip.
16208      */
16209        enable : function(){
16210            if(inited && disabled){
16211                locks.pop();
16212                if(locks.length < 1){
16213                    disabled = false;
16214                }
16215            }
16216        },
16217
16218     /**
16219      * Disable this quick tip.
16220      */
16221        disable : function(){
16222           disabled = true;
16223           clearTimeout(showProc);
16224           clearTimeout(hideProc);
16225           clearTimeout(dismissProc);
16226           if(ce){
16227               hide(true);
16228           }
16229           locks.push(1);
16230        },
16231
16232     /**
16233      * Returns true if the quick tip is enabled, else false.
16234      */
16235        isEnabled : function(){
16236             return !disabled;
16237        },
16238
16239         // private
16240        tagConfig : {
16241            namespace : "ext",
16242            attribute : "qtip",
16243            width : "width",
16244            target : "target",
16245            title : "qtitle",
16246            hide : "hide",
16247            cls : "qclass"
16248        }
16249    };
16250 }();
16251
16252 // backwards compat
16253 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16254  * Based on:
16255  * Ext JS Library 1.1.1
16256  * Copyright(c) 2006-2007, Ext JS, LLC.
16257  *
16258  * Originally Released Under LGPL - original licence link has changed is not relivant.
16259  *
16260  * Fork - LGPL
16261  * <script type="text/javascript">
16262  */
16263  
16264
16265 /**
16266  * @class Roo.tree.TreePanel
16267  * @extends Roo.data.Tree
16268
16269  * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16270  * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16271  * @cfg {Boolean} enableDD true to enable drag and drop
16272  * @cfg {Boolean} enableDrag true to enable just drag
16273  * @cfg {Boolean} enableDrop true to enable just drop
16274  * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16275  * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16276  * @cfg {String} ddGroup The DD group this TreePanel belongs to
16277  * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16278  * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16279  * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16280  * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16281  * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16282  * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16283  * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16284  * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16285  * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16286  * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16287  * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16288  * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16289  * 
16290  * @constructor
16291  * @param {String/HTMLElement/Element} el The container element
16292  * @param {Object} config
16293  */
16294 Roo.tree.TreePanel = function(el, config){
16295     var root = false;
16296     var loader = false;
16297     if (config.root) {
16298         root = config.root;
16299         delete config.root;
16300     }
16301     if (config.loader) {
16302         loader = config.loader;
16303         delete config.loader;
16304     }
16305     
16306     Roo.apply(this, config);
16307     Roo.tree.TreePanel.superclass.constructor.call(this);
16308     this.el = Roo.get(el);
16309     this.el.addClass('x-tree');
16310     //console.log(root);
16311     if (root) {
16312         this.setRootNode( Roo.factory(root, Roo.tree));
16313     }
16314     if (loader) {
16315         this.loader = Roo.factory(loader, Roo.tree);
16316     }
16317    /**
16318     * Read-only. The id of the container element becomes this TreePanel's id.
16319     */
16320    this.id = this.el.id;
16321    this.addEvents({
16322         /**
16323         * @event beforeload
16324         * Fires before a node is loaded, return false to cancel
16325         * @param {Node} node The node being loaded
16326         */
16327         "beforeload" : true,
16328         /**
16329         * @event load
16330         * Fires when a node is loaded
16331         * @param {Node} node The node that was loaded
16332         */
16333         "load" : true,
16334         /**
16335         * @event textchange
16336         * Fires when the text for a node is changed
16337         * @param {Node} node The node
16338         * @param {String} text The new text
16339         * @param {String} oldText The old text
16340         */
16341         "textchange" : true,
16342         /**
16343         * @event beforeexpand
16344         * Fires before a node is expanded, return false to cancel.
16345         * @param {Node} node The node
16346         * @param {Boolean} deep
16347         * @param {Boolean} anim
16348         */
16349         "beforeexpand" : true,
16350         /**
16351         * @event beforecollapse
16352         * Fires before a node is collapsed, return false to cancel.
16353         * @param {Node} node The node
16354         * @param {Boolean} deep
16355         * @param {Boolean} anim
16356         */
16357         "beforecollapse" : true,
16358         /**
16359         * @event expand
16360         * Fires when a node is expanded
16361         * @param {Node} node The node
16362         */
16363         "expand" : true,
16364         /**
16365         * @event disabledchange
16366         * Fires when the disabled status of a node changes
16367         * @param {Node} node The node
16368         * @param {Boolean} disabled
16369         */
16370         "disabledchange" : true,
16371         /**
16372         * @event collapse
16373         * Fires when a node is collapsed
16374         * @param {Node} node The node
16375         */
16376         "collapse" : true,
16377         /**
16378         * @event beforeclick
16379         * Fires before click processing on a node. Return false to cancel the default action.
16380         * @param {Node} node The node
16381         * @param {Roo.EventObject} e The event object
16382         */
16383         "beforeclick":true,
16384         /**
16385         * @event checkchange
16386         * Fires when a node with a checkbox's checked property changes
16387         * @param {Node} this This node
16388         * @param {Boolean} checked
16389         */
16390         "checkchange":true,
16391         /**
16392         * @event click
16393         * Fires when a node is clicked
16394         * @param {Node} node The node
16395         * @param {Roo.EventObject} e The event object
16396         */
16397         "click":true,
16398         /**
16399         * @event dblclick
16400         * Fires when a node is double clicked
16401         * @param {Node} node The node
16402         * @param {Roo.EventObject} e The event object
16403         */
16404         "dblclick":true,
16405         /**
16406         * @event contextmenu
16407         * Fires when a node is right clicked
16408         * @param {Node} node The node
16409         * @param {Roo.EventObject} e The event object
16410         */
16411         "contextmenu":true,
16412         /**
16413         * @event beforechildrenrendered
16414         * Fires right before the child nodes for a node are rendered
16415         * @param {Node} node The node
16416         */
16417         "beforechildrenrendered":true,
16418        /**
16419              * @event startdrag
16420              * Fires when a node starts being dragged
16421              * @param {Roo.tree.TreePanel} this
16422              * @param {Roo.tree.TreeNode} node
16423              * @param {event} e The raw browser event
16424              */ 
16425             "startdrag" : true,
16426             /**
16427              * @event enddrag
16428              * Fires when a drag operation is complete
16429              * @param {Roo.tree.TreePanel} this
16430              * @param {Roo.tree.TreeNode} node
16431              * @param {event} e The raw browser event
16432              */
16433             "enddrag" : true,
16434             /**
16435              * @event dragdrop
16436              * Fires when a dragged node is dropped on a valid DD target
16437              * @param {Roo.tree.TreePanel} this
16438              * @param {Roo.tree.TreeNode} node
16439              * @param {DD} dd The dd it was dropped on
16440              * @param {event} e The raw browser event
16441              */
16442             "dragdrop" : true,
16443             /**
16444              * @event beforenodedrop
16445              * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16446              * passed to handlers has the following properties:<br />
16447              * <ul style="padding:5px;padding-left:16px;">
16448              * <li>tree - The TreePanel</li>
16449              * <li>target - The node being targeted for the drop</li>
16450              * <li>data - The drag data from the drag source</li>
16451              * <li>point - The point of the drop - append, above or below</li>
16452              * <li>source - The drag source</li>
16453              * <li>rawEvent - Raw mouse event</li>
16454              * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16455              * to be inserted by setting them on this object.</li>
16456              * <li>cancel - Set this to true to cancel the drop.</li>
16457              * </ul>
16458              * @param {Object} dropEvent
16459              */
16460             "beforenodedrop" : true,
16461             /**
16462              * @event nodedrop
16463              * Fires after a DD object is dropped on a node in this tree. The dropEvent
16464              * passed to handlers has the following properties:<br />
16465              * <ul style="padding:5px;padding-left:16px;">
16466              * <li>tree - The TreePanel</li>
16467              * <li>target - The node being targeted for the drop</li>
16468              * <li>data - The drag data from the drag source</li>
16469              * <li>point - The point of the drop - append, above or below</li>
16470              * <li>source - The drag source</li>
16471              * <li>rawEvent - Raw mouse event</li>
16472              * <li>dropNode - Dropped node(s).</li>
16473              * </ul>
16474              * @param {Object} dropEvent
16475              */
16476             "nodedrop" : true,
16477              /**
16478              * @event nodedragover
16479              * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16480              * passed to handlers has the following properties:<br />
16481              * <ul style="padding:5px;padding-left:16px;">
16482              * <li>tree - The TreePanel</li>
16483              * <li>target - The node being targeted for the drop</li>
16484              * <li>data - The drag data from the drag source</li>
16485              * <li>point - The point of the drop - append, above or below</li>
16486              * <li>source - The drag source</li>
16487              * <li>rawEvent - Raw mouse event</li>
16488              * <li>dropNode - Drop node(s) provided by the source.</li>
16489              * <li>cancel - Set this to true to signal drop not allowed.</li>
16490              * </ul>
16491              * @param {Object} dragOverEvent
16492              */
16493             "nodedragover" : true
16494         
16495    });
16496    if(this.singleExpand){
16497        this.on("beforeexpand", this.restrictExpand, this);
16498    }
16499 };
16500 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16501     rootVisible : true,
16502     animate: Roo.enableFx,
16503     lines : true,
16504     enableDD : false,
16505     hlDrop : Roo.enableFx,
16506   
16507     renderer: false,
16508     
16509     rendererTip: false,
16510     // private
16511     restrictExpand : function(node){
16512         var p = node.parentNode;
16513         if(p){
16514             if(p.expandedChild && p.expandedChild.parentNode == p){
16515                 p.expandedChild.collapse();
16516             }
16517             p.expandedChild = node;
16518         }
16519     },
16520
16521     // private override
16522     setRootNode : function(node){
16523         Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16524         if(!this.rootVisible){
16525             node.ui = new Roo.tree.RootTreeNodeUI(node);
16526         }
16527         return node;
16528     },
16529
16530     /**
16531      * Returns the container element for this TreePanel
16532      */
16533     getEl : function(){
16534         return this.el;
16535     },
16536
16537     /**
16538      * Returns the default TreeLoader for this TreePanel
16539      */
16540     getLoader : function(){
16541         return this.loader;
16542     },
16543
16544     /**
16545      * Expand all nodes
16546      */
16547     expandAll : function(){
16548         this.root.expand(true);
16549     },
16550
16551     /**
16552      * Collapse all nodes
16553      */
16554     collapseAll : function(){
16555         this.root.collapse(true);
16556     },
16557
16558     /**
16559      * Returns the selection model used by this TreePanel
16560      */
16561     getSelectionModel : function(){
16562         if(!this.selModel){
16563             this.selModel = new Roo.tree.DefaultSelectionModel();
16564         }
16565         return this.selModel;
16566     },
16567
16568     /**
16569      * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16570      * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16571      * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16572      * @return {Array}
16573      */
16574     getChecked : function(a, startNode){
16575         startNode = startNode || this.root;
16576         var r = [];
16577         var f = function(){
16578             if(this.attributes.checked){
16579                 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16580             }
16581         }
16582         startNode.cascade(f);
16583         return r;
16584     },
16585
16586     /**
16587      * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16588      * @param {String} path
16589      * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16590      * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16591      * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16592      */
16593     expandPath : function(path, attr, callback){
16594         attr = attr || "id";
16595         var keys = path.split(this.pathSeparator);
16596         var curNode = this.root;
16597         if(curNode.attributes[attr] != keys[1]){ // invalid root
16598             if(callback){
16599                 callback(false, null);
16600             }
16601             return;
16602         }
16603         var index = 1;
16604         var f = function(){
16605             if(++index == keys.length){
16606                 if(callback){
16607                     callback(true, curNode);
16608                 }
16609                 return;
16610             }
16611             var c = curNode.findChild(attr, keys[index]);
16612             if(!c){
16613                 if(callback){
16614                     callback(false, curNode);
16615                 }
16616                 return;
16617             }
16618             curNode = c;
16619             c.expand(false, false, f);
16620         };
16621         curNode.expand(false, false, f);
16622     },
16623
16624     /**
16625      * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16626      * @param {String} path
16627      * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16628      * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16629      * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16630      */
16631     selectPath : function(path, attr, callback){
16632         attr = attr || "id";
16633         var keys = path.split(this.pathSeparator);
16634         var v = keys.pop();
16635         if(keys.length > 0){
16636             var f = function(success, node){
16637                 if(success && node){
16638                     var n = node.findChild(attr, v);
16639                     if(n){
16640                         n.select();
16641                         if(callback){
16642                             callback(true, n);
16643                         }
16644                     }else if(callback){
16645                         callback(false, n);
16646                     }
16647                 }else{
16648                     if(callback){
16649                         callback(false, n);
16650                     }
16651                 }
16652             };
16653             this.expandPath(keys.join(this.pathSeparator), attr, f);
16654         }else{
16655             this.root.select();
16656             if(callback){
16657                 callback(true, this.root);
16658             }
16659         }
16660     },
16661
16662     getTreeEl : function(){
16663         return this.el;
16664     },
16665
16666     /**
16667      * Trigger rendering of this TreePanel
16668      */
16669     render : function(){
16670         if (this.innerCt) {
16671             return this; // stop it rendering more than once!!
16672         }
16673         
16674         this.innerCt = this.el.createChild({tag:"ul",
16675                cls:"x-tree-root-ct " +
16676                (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16677
16678         if(this.containerScroll){
16679             Roo.dd.ScrollManager.register(this.el);
16680         }
16681         if((this.enableDD || this.enableDrop) && !this.dropZone){
16682            /**
16683             * The dropZone used by this tree if drop is enabled
16684             * @type Roo.tree.TreeDropZone
16685             */
16686              this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16687                ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16688            });
16689         }
16690         if((this.enableDD || this.enableDrag) && !this.dragZone){
16691            /**
16692             * The dragZone used by this tree if drag is enabled
16693             * @type Roo.tree.TreeDragZone
16694             */
16695             this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16696                ddGroup: this.ddGroup || "TreeDD",
16697                scroll: this.ddScroll
16698            });
16699         }
16700         this.getSelectionModel().init(this);
16701         if (!this.root) {
16702             console.log("ROOT not set in tree");
16703             return;
16704         }
16705         this.root.render();
16706         if(!this.rootVisible){
16707             this.root.renderChildren();
16708         }
16709         return this;
16710     }
16711 });/*
16712  * Based on:
16713  * Ext JS Library 1.1.1
16714  * Copyright(c) 2006-2007, Ext JS, LLC.
16715  *
16716  * Originally Released Under LGPL - original licence link has changed is not relivant.
16717  *
16718  * Fork - LGPL
16719  * <script type="text/javascript">
16720  */
16721  
16722
16723 /**
16724  * @class Roo.tree.DefaultSelectionModel
16725  * @extends Roo.util.Observable
16726  * The default single selection for a TreePanel.
16727  */
16728 Roo.tree.DefaultSelectionModel = function(){
16729    this.selNode = null;
16730    
16731    this.addEvents({
16732        /**
16733         * @event selectionchange
16734         * Fires when the selected node changes
16735         * @param {DefaultSelectionModel} this
16736         * @param {TreeNode} node the new selection
16737         */
16738        "selectionchange" : true,
16739
16740        /**
16741         * @event beforeselect
16742         * Fires before the selected node changes, return false to cancel the change
16743         * @param {DefaultSelectionModel} this
16744         * @param {TreeNode} node the new selection
16745         * @param {TreeNode} node the old selection
16746         */
16747        "beforeselect" : true
16748    });
16749 };
16750
16751 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16752     init : function(tree){
16753         this.tree = tree;
16754         tree.getTreeEl().on("keydown", this.onKeyDown, this);
16755         tree.on("click", this.onNodeClick, this);
16756     },
16757     
16758     onNodeClick : function(node, e){
16759         if (e.ctrlKey && this.selNode == node)  {
16760             this.unselect(node);
16761             return;
16762         }
16763         this.select(node);
16764     },
16765     
16766     /**
16767      * Select a node.
16768      * @param {TreeNode} node The node to select
16769      * @return {TreeNode} The selected node
16770      */
16771     select : function(node){
16772         var last = this.selNode;
16773         if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16774             if(last){
16775                 last.ui.onSelectedChange(false);
16776             }
16777             this.selNode = node;
16778             node.ui.onSelectedChange(true);
16779             this.fireEvent("selectionchange", this, node, last);
16780         }
16781         return node;
16782     },
16783     
16784     /**
16785      * Deselect a node.
16786      * @param {TreeNode} node The node to unselect
16787      */
16788     unselect : function(node){
16789         if(this.selNode == node){
16790             this.clearSelections();
16791         }    
16792     },
16793     
16794     /**
16795      * Clear all selections
16796      */
16797     clearSelections : function(){
16798         var n = this.selNode;
16799         if(n){
16800             n.ui.onSelectedChange(false);
16801             this.selNode = null;
16802             this.fireEvent("selectionchange", this, null);
16803         }
16804         return n;
16805     },
16806     
16807     /**
16808      * Get the selected node
16809      * @return {TreeNode} The selected node
16810      */
16811     getSelectedNode : function(){
16812         return this.selNode;    
16813     },
16814     
16815     /**
16816      * Returns true if the node is selected
16817      * @param {TreeNode} node The node to check
16818      * @return {Boolean}
16819      */
16820     isSelected : function(node){
16821         return this.selNode == node;  
16822     },
16823
16824     /**
16825      * Selects the node above the selected node in the tree, intelligently walking the nodes
16826      * @return TreeNode The new selection
16827      */
16828     selectPrevious : function(){
16829         var s = this.selNode || this.lastSelNode;
16830         if(!s){
16831             return null;
16832         }
16833         var ps = s.previousSibling;
16834         if(ps){
16835             if(!ps.isExpanded() || ps.childNodes.length < 1){
16836                 return this.select(ps);
16837             } else{
16838                 var lc = ps.lastChild;
16839                 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16840                     lc = lc.lastChild;
16841                 }
16842                 return this.select(lc);
16843             }
16844         } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16845             return this.select(s.parentNode);
16846         }
16847         return null;
16848     },
16849
16850     /**
16851      * Selects the node above the selected node in the tree, intelligently walking the nodes
16852      * @return TreeNode The new selection
16853      */
16854     selectNext : function(){
16855         var s = this.selNode || this.lastSelNode;
16856         if(!s){
16857             return null;
16858         }
16859         if(s.firstChild && s.isExpanded()){
16860              return this.select(s.firstChild);
16861          }else if(s.nextSibling){
16862              return this.select(s.nextSibling);
16863          }else if(s.parentNode){
16864             var newS = null;
16865             s.parentNode.bubble(function(){
16866                 if(this.nextSibling){
16867                     newS = this.getOwnerTree().selModel.select(this.nextSibling);
16868                     return false;
16869                 }
16870             });
16871             return newS;
16872          }
16873         return null;
16874     },
16875
16876     onKeyDown : function(e){
16877         var s = this.selNode || this.lastSelNode;
16878         // undesirable, but required
16879         var sm = this;
16880         if(!s){
16881             return;
16882         }
16883         var k = e.getKey();
16884         switch(k){
16885              case e.DOWN:
16886                  e.stopEvent();
16887                  this.selectNext();
16888              break;
16889              case e.UP:
16890                  e.stopEvent();
16891                  this.selectPrevious();
16892              break;
16893              case e.RIGHT:
16894                  e.preventDefault();
16895                  if(s.hasChildNodes()){
16896                      if(!s.isExpanded()){
16897                          s.expand();
16898                      }else if(s.firstChild){
16899                          this.select(s.firstChild, e);
16900                      }
16901                  }
16902              break;
16903              case e.LEFT:
16904                  e.preventDefault();
16905                  if(s.hasChildNodes() && s.isExpanded()){
16906                      s.collapse();
16907                  }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16908                      this.select(s.parentNode, e);
16909                  }
16910              break;
16911         };
16912     }
16913 });
16914
16915 /**
16916  * @class Roo.tree.MultiSelectionModel
16917  * @extends Roo.util.Observable
16918  * Multi selection for a TreePanel.
16919  */
16920 Roo.tree.MultiSelectionModel = function(){
16921    this.selNodes = [];
16922    this.selMap = {};
16923    this.addEvents({
16924        /**
16925         * @event selectionchange
16926         * Fires when the selected nodes change
16927         * @param {MultiSelectionModel} this
16928         * @param {Array} nodes Array of the selected nodes
16929         */
16930        "selectionchange" : true
16931    });
16932 };
16933
16934 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16935     init : function(tree){
16936         this.tree = tree;
16937         tree.getTreeEl().on("keydown", this.onKeyDown, this);
16938         tree.on("click", this.onNodeClick, this);
16939     },
16940     
16941     onNodeClick : function(node, e){
16942         this.select(node, e, e.ctrlKey);
16943     },
16944     
16945     /**
16946      * Select a node.
16947      * @param {TreeNode} node The node to select
16948      * @param {EventObject} e (optional) An event associated with the selection
16949      * @param {Boolean} keepExisting True to retain existing selections
16950      * @return {TreeNode} The selected node
16951      */
16952     select : function(node, e, keepExisting){
16953         if(keepExisting !== true){
16954             this.clearSelections(true);
16955         }
16956         if(this.isSelected(node)){
16957             this.lastSelNode = node;
16958             return node;
16959         }
16960         this.selNodes.push(node);
16961         this.selMap[node.id] = node;
16962         this.lastSelNode = node;
16963         node.ui.onSelectedChange(true);
16964         this.fireEvent("selectionchange", this, this.selNodes);
16965         return node;
16966     },
16967     
16968     /**
16969      * Deselect a node.
16970      * @param {TreeNode} node The node to unselect
16971      */
16972     unselect : function(node){
16973         if(this.selMap[node.id]){
16974             node.ui.onSelectedChange(false);
16975             var sn = this.selNodes;
16976             var index = -1;
16977             if(sn.indexOf){
16978                 index = sn.indexOf(node);
16979             }else{
16980                 for(var i = 0, len = sn.length; i < len; i++){
16981                     if(sn[i] == node){
16982                         index = i;
16983                         break;
16984                     }
16985                 }
16986             }
16987             if(index != -1){
16988                 this.selNodes.splice(index, 1);
16989             }
16990             delete this.selMap[node.id];
16991             this.fireEvent("selectionchange", this, this.selNodes);
16992         }
16993     },
16994     
16995     /**
16996      * Clear all selections
16997      */
16998     clearSelections : function(suppressEvent){
16999         var sn = this.selNodes;
17000         if(sn.length > 0){
17001             for(var i = 0, len = sn.length; i < len; i++){
17002                 sn[i].ui.onSelectedChange(false);
17003             }
17004             this.selNodes = [];
17005             this.selMap = {};
17006             if(suppressEvent !== true){
17007                 this.fireEvent("selectionchange", this, this.selNodes);
17008             }
17009         }
17010     },
17011     
17012     /**
17013      * Returns true if the node is selected
17014      * @param {TreeNode} node The node to check
17015      * @return {Boolean}
17016      */
17017     isSelected : function(node){
17018         return this.selMap[node.id] ? true : false;  
17019     },
17020     
17021     /**
17022      * Returns an array of the selected nodes
17023      * @return {Array}
17024      */
17025     getSelectedNodes : function(){
17026         return this.selNodes;    
17027     },
17028
17029     onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17030
17031     selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17032
17033     selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17034 });/*
17035  * Based on:
17036  * Ext JS Library 1.1.1
17037  * Copyright(c) 2006-2007, Ext JS, LLC.
17038  *
17039  * Originally Released Under LGPL - original licence link has changed is not relivant.
17040  *
17041  * Fork - LGPL
17042  * <script type="text/javascript">
17043  */
17044  
17045 /**
17046  * @class Roo.tree.TreeNode
17047  * @extends Roo.data.Node
17048  * @cfg {String} text The text for this node
17049  * @cfg {Boolean} expanded true to start the node expanded
17050  * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17051  * @cfg {Boolean} allowDrop false if this node cannot be drop on
17052  * @cfg {Boolean} disabled true to start the node disabled
17053  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17054  * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17055  * @cfg {String} cls A css class to be added to the node
17056  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17057  * @cfg {String} href URL of the link used for the node (defaults to #)
17058  * @cfg {String} hrefTarget target frame for the link
17059  * @cfg {String} qtip An Ext QuickTip for the node
17060  * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17061  * @cfg {Boolean} singleClickExpand True for single click expand on this node
17062  * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17063  * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17064  * (defaults to undefined with no checkbox rendered)
17065  * @constructor
17066  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17067  */
17068 Roo.tree.TreeNode = function(attributes){
17069     attributes = attributes || {};
17070     if(typeof attributes == "string"){
17071         attributes = {text: attributes};
17072     }
17073     this.childrenRendered = false;
17074     this.rendered = false;
17075     Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17076     this.expanded = attributes.expanded === true;
17077     this.isTarget = attributes.isTarget !== false;
17078     this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17079     this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17080
17081     /**
17082      * Read-only. The text for this node. To change it use setText().
17083      * @type String
17084      */
17085     this.text = attributes.text;
17086     /**
17087      * True if this node is disabled.
17088      * @type Boolean
17089      */
17090     this.disabled = attributes.disabled === true;
17091
17092     this.addEvents({
17093         /**
17094         * @event textchange
17095         * Fires when the text for this node is changed
17096         * @param {Node} this This node
17097         * @param {String} text The new text
17098         * @param {String} oldText The old text
17099         */
17100         "textchange" : true,
17101         /**
17102         * @event beforeexpand
17103         * Fires before this node is expanded, return false to cancel.
17104         * @param {Node} this This node
17105         * @param {Boolean} deep
17106         * @param {Boolean} anim
17107         */
17108         "beforeexpand" : true,
17109         /**
17110         * @event beforecollapse
17111         * Fires before this node is collapsed, return false to cancel.
17112         * @param {Node} this This node
17113         * @param {Boolean} deep
17114         * @param {Boolean} anim
17115         */
17116         "beforecollapse" : true,
17117         /**
17118         * @event expand
17119         * Fires when this node is expanded
17120         * @param {Node} this This node
17121         */
17122         "expand" : true,
17123         /**
17124         * @event disabledchange
17125         * Fires when the disabled status of this node changes
17126         * @param {Node} this This node
17127         * @param {Boolean} disabled
17128         */
17129         "disabledchange" : true,
17130         /**
17131         * @event collapse
17132         * Fires when this node is collapsed
17133         * @param {Node} this This node
17134         */
17135         "collapse" : true,
17136         /**
17137         * @event beforeclick
17138         * Fires before click processing. Return false to cancel the default action.
17139         * @param {Node} this This node
17140         * @param {Roo.EventObject} e The event object
17141         */
17142         "beforeclick":true,
17143         /**
17144         * @event checkchange
17145         * Fires when a node with a checkbox's checked property changes
17146         * @param {Node} this This node
17147         * @param {Boolean} checked
17148         */
17149         "checkchange":true,
17150         /**
17151         * @event click
17152         * Fires when this node is clicked
17153         * @param {Node} this This node
17154         * @param {Roo.EventObject} e The event object
17155         */
17156         "click":true,
17157         /**
17158         * @event dblclick
17159         * Fires when this node is double clicked
17160         * @param {Node} this This node
17161         * @param {Roo.EventObject} e The event object
17162         */
17163         "dblclick":true,
17164         /**
17165         * @event contextmenu
17166         * Fires when this node is right clicked
17167         * @param {Node} this This node
17168         * @param {Roo.EventObject} e The event object
17169         */
17170         "contextmenu":true,
17171         /**
17172         * @event beforechildrenrendered
17173         * Fires right before the child nodes for this node are rendered
17174         * @param {Node} this This node
17175         */
17176         "beforechildrenrendered":true
17177     });
17178
17179     var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17180
17181     /**
17182      * Read-only. The UI for this node
17183      * @type TreeNodeUI
17184      */
17185     this.ui = new uiClass(this);
17186 };
17187 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17188     preventHScroll: true,
17189     /**
17190      * Returns true if this node is expanded
17191      * @return {Boolean}
17192      */
17193     isExpanded : function(){
17194         return this.expanded;
17195     },
17196
17197     /**
17198      * Returns the UI object for this node
17199      * @return {TreeNodeUI}
17200      */
17201     getUI : function(){
17202         return this.ui;
17203     },
17204
17205     // private override
17206     setFirstChild : function(node){
17207         var of = this.firstChild;
17208         Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17209         if(this.childrenRendered && of && node != of){
17210             of.renderIndent(true, true);
17211         }
17212         if(this.rendered){
17213             this.renderIndent(true, true);
17214         }
17215     },
17216
17217     // private override
17218     setLastChild : function(node){
17219         var ol = this.lastChild;
17220         Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17221         if(this.childrenRendered && ol && node != ol){
17222             ol.renderIndent(true, true);
17223         }
17224         if(this.rendered){
17225             this.renderIndent(true, true);
17226         }
17227     },
17228
17229     // these methods are overridden to provide lazy rendering support
17230     // private override
17231     appendChild : function(){
17232         var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17233         if(node && this.childrenRendered){
17234             node.render();
17235         }
17236         this.ui.updateExpandIcon();
17237         return node;
17238     },
17239
17240     // private override
17241     removeChild : function(node){
17242         this.ownerTree.getSelectionModel().unselect(node);
17243         Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17244         // if it's been rendered remove dom node
17245         if(this.childrenRendered){
17246             node.ui.remove();
17247         }
17248         if(this.childNodes.length < 1){
17249             this.collapse(false, false);
17250         }else{
17251             this.ui.updateExpandIcon();
17252         }
17253         if(!this.firstChild) {
17254             this.childrenRendered = false;
17255         }
17256         return node;
17257     },
17258
17259     // private override
17260     insertBefore : function(node, refNode){
17261         var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17262         if(newNode && refNode && this.childrenRendered){
17263             node.render();
17264         }
17265         this.ui.updateExpandIcon();
17266         return newNode;
17267     },
17268
17269     /**
17270      * Sets the text for this node
17271      * @param {String} text
17272      */
17273     setText : function(text){
17274         var oldText = this.text;
17275         this.text = text;
17276         this.attributes.text = text;
17277         if(this.rendered){ // event without subscribing
17278             this.ui.onTextChange(this, text, oldText);
17279         }
17280         this.fireEvent("textchange", this, text, oldText);
17281     },
17282
17283     /**
17284      * Triggers selection of this node
17285      */
17286     select : function(){
17287         this.getOwnerTree().getSelectionModel().select(this);
17288     },
17289
17290     /**
17291      * Triggers deselection of this node
17292      */
17293     unselect : function(){
17294         this.getOwnerTree().getSelectionModel().unselect(this);
17295     },
17296
17297     /**
17298      * Returns true if this node is selected
17299      * @return {Boolean}
17300      */
17301     isSelected : function(){
17302         return this.getOwnerTree().getSelectionModel().isSelected(this);
17303     },
17304
17305     /**
17306      * Expand this node.
17307      * @param {Boolean} deep (optional) True to expand all children as well
17308      * @param {Boolean} anim (optional) false to cancel the default animation
17309      * @param {Function} callback (optional) A callback to be called when
17310      * expanding this node completes (does not wait for deep expand to complete).
17311      * Called with 1 parameter, this node.
17312      */
17313     expand : function(deep, anim, callback){
17314         if(!this.expanded){
17315             if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17316                 return;
17317             }
17318             if(!this.childrenRendered){
17319                 this.renderChildren();
17320             }
17321             this.expanded = true;
17322             if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17323                 this.ui.animExpand(function(){
17324                     this.fireEvent("expand", this);
17325                     if(typeof callback == "function"){
17326                         callback(this);
17327                     }
17328                     if(deep === true){
17329                         this.expandChildNodes(true);
17330                     }
17331                 }.createDelegate(this));
17332                 return;
17333             }else{
17334                 this.ui.expand();
17335                 this.fireEvent("expand", this);
17336                 if(typeof callback == "function"){
17337                     callback(this);
17338                 }
17339             }
17340         }else{
17341            if(typeof callback == "function"){
17342                callback(this);
17343            }
17344         }
17345         if(deep === true){
17346             this.expandChildNodes(true);
17347         }
17348     },
17349
17350     isHiddenRoot : function(){
17351         return this.isRoot && !this.getOwnerTree().rootVisible;
17352     },
17353
17354     /**
17355      * Collapse this node.
17356      * @param {Boolean} deep (optional) True to collapse all children as well
17357      * @param {Boolean} anim (optional) false to cancel the default animation
17358      */
17359     collapse : function(deep, anim){
17360         if(this.expanded && !this.isHiddenRoot()){
17361             if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17362                 return;
17363             }
17364             this.expanded = false;
17365             if((this.getOwnerTree().animate && anim !== false) || anim){
17366                 this.ui.animCollapse(function(){
17367                     this.fireEvent("collapse", this);
17368                     if(deep === true){
17369                         this.collapseChildNodes(true);
17370                     }
17371                 }.createDelegate(this));
17372                 return;
17373             }else{
17374                 this.ui.collapse();
17375                 this.fireEvent("collapse", this);
17376             }
17377         }
17378         if(deep === true){
17379             var cs = this.childNodes;
17380             for(var i = 0, len = cs.length; i < len; i++) {
17381                 cs[i].collapse(true, false);
17382             }
17383         }
17384     },
17385
17386     // private
17387     delayedExpand : function(delay){
17388         if(!this.expandProcId){
17389             this.expandProcId = this.expand.defer(delay, this);
17390         }
17391     },
17392
17393     // private
17394     cancelExpand : function(){
17395         if(this.expandProcId){
17396             clearTimeout(this.expandProcId);
17397         }
17398         this.expandProcId = false;
17399     },
17400
17401     /**
17402      * Toggles expanded/collapsed state of the node
17403      */
17404     toggle : function(){
17405         if(this.expanded){
17406             this.collapse();
17407         }else{
17408             this.expand();
17409         }
17410     },
17411
17412     /**
17413      * Ensures all parent nodes are expanded
17414      */
17415     ensureVisible : function(callback){
17416         var tree = this.getOwnerTree();
17417         tree.expandPath(this.parentNode.getPath(), false, function(){
17418             tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17419             Roo.callback(callback);
17420         }.createDelegate(this));
17421     },
17422
17423     /**
17424      * Expand all child nodes
17425      * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17426      */
17427     expandChildNodes : function(deep){
17428         var cs = this.childNodes;
17429         for(var i = 0, len = cs.length; i < len; i++) {
17430                 cs[i].expand(deep);
17431         }
17432     },
17433
17434     /**
17435      * Collapse all child nodes
17436      * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17437      */
17438     collapseChildNodes : function(deep){
17439         var cs = this.childNodes;
17440         for(var i = 0, len = cs.length; i < len; i++) {
17441                 cs[i].collapse(deep);
17442         }
17443     },
17444
17445     /**
17446      * Disables this node
17447      */
17448     disable : function(){
17449         this.disabled = true;
17450         this.unselect();
17451         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17452             this.ui.onDisableChange(this, true);
17453         }
17454         this.fireEvent("disabledchange", this, true);
17455     },
17456
17457     /**
17458      * Enables this node
17459      */
17460     enable : function(){
17461         this.disabled = false;
17462         if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17463             this.ui.onDisableChange(this, false);
17464         }
17465         this.fireEvent("disabledchange", this, false);
17466     },
17467
17468     // private
17469     renderChildren : function(suppressEvent){
17470         if(suppressEvent !== false){
17471             this.fireEvent("beforechildrenrendered", this);
17472         }
17473         var cs = this.childNodes;
17474         for(var i = 0, len = cs.length; i < len; i++){
17475             cs[i].render(true);
17476         }
17477         this.childrenRendered = true;
17478     },
17479
17480     // private
17481     sort : function(fn, scope){
17482         Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17483         if(this.childrenRendered){
17484             var cs = this.childNodes;
17485             for(var i = 0, len = cs.length; i < len; i++){
17486                 cs[i].render(true);
17487             }
17488         }
17489     },
17490
17491     // private
17492     render : function(bulkRender){
17493         this.ui.render(bulkRender);
17494         if(!this.rendered){
17495             this.rendered = true;
17496             if(this.expanded){
17497                 this.expanded = false;
17498                 this.expand(false, false);
17499             }
17500         }
17501     },
17502
17503     // private
17504     renderIndent : function(deep, refresh){
17505         if(refresh){
17506             this.ui.childIndent = null;
17507         }
17508         this.ui.renderIndent();
17509         if(deep === true && this.childrenRendered){
17510             var cs = this.childNodes;
17511             for(var i = 0, len = cs.length; i < len; i++){
17512                 cs[i].renderIndent(true, refresh);
17513             }
17514         }
17515     }
17516 });/*
17517  * Based on:
17518  * Ext JS Library 1.1.1
17519  * Copyright(c) 2006-2007, Ext JS, LLC.
17520  *
17521  * Originally Released Under LGPL - original licence link has changed is not relivant.
17522  *
17523  * Fork - LGPL
17524  * <script type="text/javascript">
17525  */
17526  
17527 /**
17528  * @class Roo.tree.AsyncTreeNode
17529  * @extends Roo.tree.TreeNode
17530  * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17531  * @constructor
17532  * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node 
17533  */
17534  Roo.tree.AsyncTreeNode = function(config){
17535     this.loaded = false;
17536     this.loading = false;
17537     Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17538     /**
17539     * @event beforeload
17540     * Fires before this node is loaded, return false to cancel
17541     * @param {Node} this This node
17542     */
17543     this.addEvents({'beforeload':true, 'load': true});
17544     /**
17545     * @event load
17546     * Fires when this node is loaded
17547     * @param {Node} this This node
17548     */
17549     /**
17550      * The loader used by this node (defaults to using the tree's defined loader)
17551      * @type TreeLoader
17552      * @property loader
17553      */
17554 };
17555 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17556     expand : function(deep, anim, callback){
17557         if(this.loading){ // if an async load is already running, waiting til it's done
17558             var timer;
17559             var f = function(){
17560                 if(!this.loading){ // done loading
17561                     clearInterval(timer);
17562                     this.expand(deep, anim, callback);
17563                 }
17564             }.createDelegate(this);
17565             timer = setInterval(f, 200);
17566             return;
17567         }
17568         if(!this.loaded){
17569             if(this.fireEvent("beforeload", this) === false){
17570                 return;
17571             }
17572             this.loading = true;
17573             this.ui.beforeLoad(this);
17574             var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17575             if(loader){
17576                 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17577                 return;
17578             }
17579         }
17580         Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17581     },
17582     
17583     /**
17584      * Returns true if this node is currently loading
17585      * @return {Boolean}
17586      */
17587     isLoading : function(){
17588         return this.loading;  
17589     },
17590     
17591     loadComplete : function(deep, anim, callback){
17592         this.loading = false;
17593         this.loaded = true;
17594         this.ui.afterLoad(this);
17595         this.fireEvent("load", this);
17596         this.expand(deep, anim, callback);
17597     },
17598     
17599     /**
17600      * Returns true if this node has been loaded
17601      * @return {Boolean}
17602      */
17603     isLoaded : function(){
17604         return this.loaded;
17605     },
17606     
17607     hasChildNodes : function(){
17608         if(!this.isLeaf() && !this.loaded){
17609             return true;
17610         }else{
17611             return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17612         }
17613     },
17614
17615     /**
17616      * Trigger a reload for this node
17617      * @param {Function} callback
17618      */
17619     reload : function(callback){
17620         this.collapse(false, false);
17621         while(this.firstChild){
17622             this.removeChild(this.firstChild);
17623         }
17624         this.childrenRendered = false;
17625         this.loaded = false;
17626         if(this.isHiddenRoot()){
17627             this.expanded = false;
17628         }
17629         this.expand(false, false, callback);
17630     }
17631 });/*
17632  * Based on:
17633  * Ext JS Library 1.1.1
17634  * Copyright(c) 2006-2007, Ext JS, LLC.
17635  *
17636  * Originally Released Under LGPL - original licence link has changed is not relivant.
17637  *
17638  * Fork - LGPL
17639  * <script type="text/javascript">
17640  */
17641  
17642 /**
17643  * @class Roo.tree.TreeNodeUI
17644  * @constructor
17645  * @param {Object} node The node to render
17646  * The TreeNode UI implementation is separate from the
17647  * tree implementation. Unless you are customizing the tree UI,
17648  * you should never have to use this directly.
17649  */
17650 Roo.tree.TreeNodeUI = function(node){
17651     this.node = node;
17652     this.rendered = false;
17653     this.animating = false;
17654     this.emptyIcon = Roo.BLANK_IMAGE_URL;
17655 };
17656
17657 Roo.tree.TreeNodeUI.prototype = {
17658     removeChild : function(node){
17659         if(this.rendered){
17660             this.ctNode.removeChild(node.ui.getEl());
17661         }
17662     },
17663
17664     beforeLoad : function(){
17665          this.addClass("x-tree-node-loading");
17666     },
17667
17668     afterLoad : function(){
17669          this.removeClass("x-tree-node-loading");
17670     },
17671
17672     onTextChange : function(node, text, oldText){
17673         if(this.rendered){
17674             this.textNode.innerHTML = text;
17675         }
17676     },
17677
17678     onDisableChange : function(node, state){
17679         this.disabled = state;
17680         if(state){
17681             this.addClass("x-tree-node-disabled");
17682         }else{
17683             this.removeClass("x-tree-node-disabled");
17684         }
17685     },
17686
17687     onSelectedChange : function(state){
17688         if(state){
17689             this.focus();
17690             this.addClass("x-tree-selected");
17691         }else{
17692             //this.blur();
17693             this.removeClass("x-tree-selected");
17694         }
17695     },
17696
17697     onMove : function(tree, node, oldParent, newParent, index, refNode){
17698         this.childIndent = null;
17699         if(this.rendered){
17700             var targetNode = newParent.ui.getContainer();
17701             if(!targetNode){//target not rendered
17702                 this.holder = document.createElement("div");
17703                 this.holder.appendChild(this.wrap);
17704                 return;
17705             }
17706             var insertBefore = refNode ? refNode.ui.getEl() : null;
17707             if(insertBefore){
17708                 targetNode.insertBefore(this.wrap, insertBefore);
17709             }else{
17710                 targetNode.appendChild(this.wrap);
17711             }
17712             this.node.renderIndent(true);
17713         }
17714     },
17715
17716     addClass : function(cls){
17717         if(this.elNode){
17718             Roo.fly(this.elNode).addClass(cls);
17719         }
17720     },
17721
17722     removeClass : function(cls){
17723         if(this.elNode){
17724             Roo.fly(this.elNode).removeClass(cls);
17725         }
17726     },
17727
17728     remove : function(){
17729         if(this.rendered){
17730             this.holder = document.createElement("div");
17731             this.holder.appendChild(this.wrap);
17732         }
17733     },
17734
17735     fireEvent : function(){
17736         return this.node.fireEvent.apply(this.node, arguments);
17737     },
17738
17739     initEvents : function(){
17740         this.node.on("move", this.onMove, this);
17741         var E = Roo.EventManager;
17742         var a = this.anchor;
17743
17744         var el = Roo.fly(a, '_treeui');
17745
17746         if(Roo.isOpera){ // opera render bug ignores the CSS
17747             el.setStyle("text-decoration", "none");
17748         }
17749
17750         el.on("click", this.onClick, this);
17751         el.on("dblclick", this.onDblClick, this);
17752
17753         if(this.checkbox){
17754             Roo.EventManager.on(this.checkbox,
17755                     Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17756         }
17757
17758         el.on("contextmenu", this.onContextMenu, this);
17759
17760         var icon = Roo.fly(this.iconNode);
17761         icon.on("click", this.onClick, this);
17762         icon.on("dblclick", this.onDblClick, this);
17763         icon.on("contextmenu", this.onContextMenu, this);
17764         E.on(this.ecNode, "click", this.ecClick, this, true);
17765
17766         if(this.node.disabled){
17767             this.addClass("x-tree-node-disabled");
17768         }
17769         if(this.node.hidden){
17770             this.addClass("x-tree-node-disabled");
17771         }
17772         var ot = this.node.getOwnerTree();
17773         var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17774         if(dd && (!this.node.isRoot || ot.rootVisible)){
17775             Roo.dd.Registry.register(this.elNode, {
17776                 node: this.node,
17777                 handles: this.getDDHandles(),
17778                 isHandle: false
17779             });
17780         }
17781     },
17782
17783     getDDHandles : function(){
17784         return [this.iconNode, this.textNode];
17785     },
17786
17787     hide : function(){
17788         if(this.rendered){
17789             this.wrap.style.display = "none";
17790         }
17791     },
17792
17793     show : function(){
17794         if(this.rendered){
17795             this.wrap.style.display = "";
17796         }
17797     },
17798
17799     onContextMenu : function(e){
17800         if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17801             e.preventDefault();
17802             this.focus();
17803             this.fireEvent("contextmenu", this.node, e);
17804         }
17805     },
17806
17807     onClick : function(e){
17808         if(this.dropping){
17809             e.stopEvent();
17810             return;
17811         }
17812         if(this.fireEvent("beforeclick", this.node, e) !== false){
17813             if(!this.disabled && this.node.attributes.href){
17814                 this.fireEvent("click", this.node, e);
17815                 return;
17816             }
17817             e.preventDefault();
17818             if(this.disabled){
17819                 return;
17820             }
17821
17822             if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17823                 this.node.toggle();
17824             }
17825
17826             this.fireEvent("click", this.node, e);
17827         }else{
17828             e.stopEvent();
17829         }
17830     },
17831
17832     onDblClick : function(e){
17833         e.preventDefault();
17834         if(this.disabled){
17835             return;
17836         }
17837         if(this.checkbox){
17838             this.toggleCheck();
17839         }
17840         if(!this.animating && this.node.hasChildNodes()){
17841             this.node.toggle();
17842         }
17843         this.fireEvent("dblclick", this.node, e);
17844     },
17845
17846     onCheckChange : function(){
17847         var checked = this.checkbox.checked;
17848         this.node.attributes.checked = checked;
17849         this.fireEvent('checkchange', this.node, checked);
17850     },
17851
17852     ecClick : function(e){
17853         if(!this.animating && this.node.hasChildNodes()){
17854             this.node.toggle();
17855         }
17856     },
17857
17858     startDrop : function(){
17859         this.dropping = true;
17860     },
17861
17862     // delayed drop so the click event doesn't get fired on a drop
17863     endDrop : function(){
17864        setTimeout(function(){
17865            this.dropping = false;
17866        }.createDelegate(this), 50);
17867     },
17868
17869     expand : function(){
17870         this.updateExpandIcon();
17871         this.ctNode.style.display = "";
17872     },
17873
17874     focus : function(){
17875         if(!this.node.preventHScroll){
17876             try{this.anchor.focus();
17877             }catch(e){}
17878         }else if(!Roo.isIE){
17879             try{
17880                 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17881                 var l = noscroll.scrollLeft;
17882                 this.anchor.focus();
17883                 noscroll.scrollLeft = l;
17884             }catch(e){}
17885         }
17886     },
17887
17888     toggleCheck : function(value){
17889         var cb = this.checkbox;
17890         if(cb){
17891             cb.checked = (value === undefined ? !cb.checked : value);
17892         }
17893     },
17894
17895     blur : function(){
17896         try{
17897             this.anchor.blur();
17898         }catch(e){}
17899     },
17900
17901     animExpand : function(callback){
17902         var ct = Roo.get(this.ctNode);
17903         ct.stopFx();
17904         if(!this.node.hasChildNodes()){
17905             this.updateExpandIcon();
17906             this.ctNode.style.display = "";
17907             Roo.callback(callback);
17908             return;
17909         }
17910         this.animating = true;
17911         this.updateExpandIcon();
17912
17913         ct.slideIn('t', {
17914            callback : function(){
17915                this.animating = false;
17916                Roo.callback(callback);
17917             },
17918             scope: this,
17919             duration: this.node.ownerTree.duration || .25
17920         });
17921     },
17922
17923     highlight : function(){
17924         var tree = this.node.getOwnerTree();
17925         Roo.fly(this.wrap).highlight(
17926             tree.hlColor || "C3DAF9",
17927             {endColor: tree.hlBaseColor}
17928         );
17929     },
17930
17931     collapse : function(){
17932         this.updateExpandIcon();
17933         this.ctNode.style.display = "none";
17934     },
17935
17936     animCollapse : function(callback){
17937         var ct = Roo.get(this.ctNode);
17938         ct.enableDisplayMode('block');
17939         ct.stopFx();
17940
17941         this.animating = true;
17942         this.updateExpandIcon();
17943
17944         ct.slideOut('t', {
17945             callback : function(){
17946                this.animating = false;
17947                Roo.callback(callback);
17948             },
17949             scope: this,
17950             duration: this.node.ownerTree.duration || .25
17951         });
17952     },
17953
17954     getContainer : function(){
17955         return this.ctNode;
17956     },
17957
17958     getEl : function(){
17959         return this.wrap;
17960     },
17961
17962     appendDDGhost : function(ghostNode){
17963         ghostNode.appendChild(this.elNode.cloneNode(true));
17964     },
17965
17966     getDDRepairXY : function(){
17967         return Roo.lib.Dom.getXY(this.iconNode);
17968     },
17969
17970     onRender : function(){
17971         this.render();
17972     },
17973
17974     render : function(bulkRender){
17975         var n = this.node, a = n.attributes;
17976         var targetNode = n.parentNode ?
17977               n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17978
17979         if(!this.rendered){
17980             this.rendered = true;
17981
17982             this.renderElements(n, a, targetNode, bulkRender);
17983
17984             if(a.qtip){
17985                if(this.textNode.setAttributeNS){
17986                    this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17987                    if(a.qtipTitle){
17988                        this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17989                    }
17990                }else{
17991                    this.textNode.setAttribute("ext:qtip", a.qtip);
17992                    if(a.qtipTitle){
17993                        this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
17994                    }
17995                }
17996             }else if(a.qtipCfg){
17997                 a.qtipCfg.target = Roo.id(this.textNode);
17998                 Roo.QuickTips.register(a.qtipCfg);
17999             }
18000             this.initEvents();
18001             if(!this.node.expanded){
18002                 this.updateExpandIcon();
18003             }
18004         }else{
18005             if(bulkRender === true) {
18006                 targetNode.appendChild(this.wrap);
18007             }
18008         }
18009     },
18010
18011     renderElements : function(n, a, targetNode, bulkRender){
18012         // add some indent caching, this helps performance when rendering a large tree
18013         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18014         var t = n.getOwnerTree();
18015         var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18016         var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18017         var cb = typeof a.checked == 'boolean';
18018         var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18019         var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18020             '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18021             '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18022             '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18023             cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18024             '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18025              a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", 
18026                 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18027             '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18028             "</li>"];
18029
18030         if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18031             this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18032                                 n.nextSibling.ui.getEl(), buf.join(""));
18033         }else{
18034             this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18035         }
18036
18037         this.elNode = this.wrap.childNodes[0];
18038         this.ctNode = this.wrap.childNodes[1];
18039         var cs = this.elNode.childNodes;
18040         this.indentNode = cs[0];
18041         this.ecNode = cs[1];
18042         this.iconNode = cs[2];
18043         var index = 3;
18044         if(cb){
18045             this.checkbox = cs[3];
18046             index++;
18047         }
18048         this.anchor = cs[index];
18049         this.textNode = cs[index].firstChild;
18050     },
18051
18052     getAnchor : function(){
18053         return this.anchor;
18054     },
18055
18056     getTextEl : function(){
18057         return this.textNode;
18058     },
18059
18060     getIconEl : function(){
18061         return this.iconNode;
18062     },
18063
18064     isChecked : function(){
18065         return this.checkbox ? this.checkbox.checked : false;
18066     },
18067
18068     updateExpandIcon : function(){
18069         if(this.rendered){
18070             var n = this.node, c1, c2;
18071             var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18072             var hasChild = n.hasChildNodes();
18073             if(hasChild){
18074                 if(n.expanded){
18075                     cls += "-minus";
18076                     c1 = "x-tree-node-collapsed";
18077                     c2 = "x-tree-node-expanded";
18078                 }else{
18079                     cls += "-plus";
18080                     c1 = "x-tree-node-expanded";
18081                     c2 = "x-tree-node-collapsed";
18082                 }
18083                 if(this.wasLeaf){
18084                     this.removeClass("x-tree-node-leaf");
18085                     this.wasLeaf = false;
18086                 }
18087                 if(this.c1 != c1 || this.c2 != c2){
18088                     Roo.fly(this.elNode).replaceClass(c1, c2);
18089                     this.c1 = c1; this.c2 = c2;
18090                 }
18091             }else{
18092                 if(!this.wasLeaf){
18093                     Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18094                     delete this.c1;
18095                     delete this.c2;
18096                     this.wasLeaf = true;
18097                 }
18098             }
18099             var ecc = "x-tree-ec-icon "+cls;
18100             if(this.ecc != ecc){
18101                 this.ecNode.className = ecc;
18102                 this.ecc = ecc;
18103             }
18104         }
18105     },
18106
18107     getChildIndent : function(){
18108         if(!this.childIndent){
18109             var buf = [];
18110             var p = this.node;
18111             while(p){
18112                 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18113                     if(!p.isLast()) {
18114                         buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18115                     } else {
18116                         buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18117                     }
18118                 }
18119                 p = p.parentNode;
18120             }
18121             this.childIndent = buf.join("");
18122         }
18123         return this.childIndent;
18124     },
18125
18126     renderIndent : function(){
18127         if(this.rendered){
18128             var indent = "";
18129             var p = this.node.parentNode;
18130             if(p){
18131                 indent = p.ui.getChildIndent();
18132             }
18133             if(this.indentMarkup != indent){ // don't rerender if not required
18134                 this.indentNode.innerHTML = indent;
18135                 this.indentMarkup = indent;
18136             }
18137             this.updateExpandIcon();
18138         }
18139     }
18140 };
18141
18142 Roo.tree.RootTreeNodeUI = function(){
18143     Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18144 };
18145 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18146     render : function(){
18147         if(!this.rendered){
18148             var targetNode = this.node.ownerTree.innerCt.dom;
18149             this.node.expanded = true;
18150             targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18151             this.wrap = this.ctNode = targetNode.firstChild;
18152         }
18153     },
18154     collapse : function(){
18155     },
18156     expand : function(){
18157     }
18158 });