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     
76 };
77
78 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
79
80     /**
81      * The id of the element associated with this object.  This is what we
82      * refer to as the "linked element" because the size and position of
83      * this element is used to determine when the drag and drop objects have
84      * interacted.
85      * @property id
86      * @type String
87      */
88     id: null,
89
90     /**
91      * Configuration attributes passed into the constructor
92      * @property config
93      * @type object
94      */
95     config: null,
96
97     /**
98      * The id of the element that will be dragged.  By default this is same
99      * as the linked element , but could be changed to another element. Ex:
100      * Roo.dd.DDProxy
101      * @property dragElId
102      * @type String
103      * @private
104      */
105     dragElId: null,
106
107     /**
108      * the id of the element that initiates the drag operation.  By default
109      * this is the linked element, but could be changed to be a child of this
110      * element.  This lets us do things like only starting the drag when the
111      * header element within the linked html element is clicked.
112      * @property handleElId
113      * @type String
114      * @private
115      */
116     handleElId: null,
117
118     /**
119      * An associative array of HTML tags that will be ignored if clicked.
120      * @property invalidHandleTypes
121      * @type {string: string}
122      */
123     invalidHandleTypes: null,
124
125     /**
126      * An associative array of ids for elements that will be ignored if clicked
127      * @property invalidHandleIds
128      * @type {string: string}
129      */
130     invalidHandleIds: null,
131
132     /**
133      * An indexted array of css class names for elements that will be ignored
134      * if clicked.
135      * @property invalidHandleClasses
136      * @type string[]
137      */
138     invalidHandleClasses: null,
139
140     /**
141      * The linked element's absolute X position at the time the drag was
142      * started
143      * @property startPageX
144      * @type int
145      * @private
146      */
147     startPageX: 0,
148
149     /**
150      * The linked element's absolute X position at the time the drag was
151      * started
152      * @property startPageY
153      * @type int
154      * @private
155      */
156     startPageY: 0,
157
158     /**
159      * The group defines a logical collection of DragDrop objects that are
160      * related.  Instances only get events when interacting with other
161      * DragDrop object in the same group.  This lets us define multiple
162      * groups using a single DragDrop subclass if we want.
163      * @property groups
164      * @type {string: string}
165      */
166     groups: null,
167
168     /**
169      * Individual drag/drop instances can be locked.  This will prevent
170      * onmousedown start drag.
171      * @property locked
172      * @type boolean
173      * @private
174      */
175     locked: false,
176
177     /**
178      * Lock this instance
179      * @method lock
180      */
181     lock: function() { this.locked = true; },
182
183     /**
184      * Unlock this instace
185      * @method unlock
186      */
187     unlock: function() { this.locked = false; },
188
189     /**
190      * By default, all insances can be a drop target.  This can be disabled by
191      * setting isTarget to false.
192      * @method isTarget
193      * @type boolean
194      */
195     isTarget: true,
196
197     /**
198      * The padding configured for this drag and drop object for calculating
199      * the drop zone intersection with this object.
200      * @method padding
201      * @type int[]
202      */
203     padding: null,
204
205     /**
206      * Cached reference to the linked element
207      * @property _domRef
208      * @private
209      */
210     _domRef: null,
211
212     /**
213      * Internal typeof flag
214      * @property __ygDragDrop
215      * @private
216      */
217     __ygDragDrop: true,
218
219     /**
220      * Set to true when horizontal contraints are applied
221      * @property constrainX
222      * @type boolean
223      * @private
224      */
225     constrainX: false,
226
227     /**
228      * Set to true when vertical contraints are applied
229      * @property constrainY
230      * @type boolean
231      * @private
232      */
233     constrainY: false,
234
235     /**
236      * The left constraint
237      * @property minX
238      * @type int
239      * @private
240      */
241     minX: 0,
242
243     /**
244      * The right constraint
245      * @property maxX
246      * @type int
247      * @private
248      */
249     maxX: 0,
250
251     /**
252      * The up constraint
253      * @property minY
254      * @type int
255      * @type int
256      * @private
257      */
258     minY: 0,
259
260     /**
261      * The down constraint
262      * @property maxY
263      * @type int
264      * @private
265      */
266     maxY: 0,
267
268     /**
269      * Maintain offsets when we resetconstraints.  Set to true when you want
270      * the position of the element relative to its parent to stay the same
271      * when the page changes
272      *
273      * @property maintainOffset
274      * @type boolean
275      */
276     maintainOffset: false,
277
278     /**
279      * Array of pixel locations the element will snap to if we specified a
280      * horizontal graduation/interval.  This array is generated automatically
281      * when you define a tick interval.
282      * @property xTicks
283      * @type int[]
284      */
285     xTicks: null,
286
287     /**
288      * Array of pixel locations the element will snap to if we specified a
289      * vertical graduation/interval.  This array is generated automatically
290      * when you define a tick interval.
291      * @property yTicks
292      * @type int[]
293      */
294     yTicks: null,
295
296     /**
297      * By default the drag and drop instance will only respond to the primary
298      * button click (left button for a right-handed mouse).  Set to true to
299      * allow drag and drop to start with any mouse click that is propogated
300      * by the browser
301      * @property primaryButtonOnly
302      * @type boolean
303      */
304     primaryButtonOnly: true,
305
306     /**
307      * The availabe property is false until the linked dom element is accessible.
308      * @property available
309      * @type boolean
310      */
311     available: false,
312
313     /**
314      * By default, drags can only be initiated if the mousedown occurs in the
315      * region the linked element is.  This is done in part to work around a
316      * bug in some browsers that mis-report the mousedown if the previous
317      * mouseup happened outside of the window.  This property is set to true
318      * if outer handles are defined.
319      *
320      * @property hasOuterHandles
321      * @type boolean
322      * @default false
323      */
324     hasOuterHandles: false,
325
326     /**
327      * Code that executes immediately before the startDrag event
328      * @method b4StartDrag
329      * @private
330      */
331     b4StartDrag: function(x, y) { },
332
333     /**
334      * Abstract method called after a drag/drop object is clicked
335      * and the drag or mousedown time thresholds have beeen met.
336      * @method startDrag
337      * @param {int} X click location
338      * @param {int} Y click location
339      */
340     startDrag: function(x, y) { /* override this */ },
341
342     /**
343      * Code that executes immediately before the onDrag event
344      * @method b4Drag
345      * @private
346      */
347     b4Drag: function(e) { },
348
349     /**
350      * Abstract method called during the onMouseMove event while dragging an
351      * object.
352      * @method onDrag
353      * @param {Event} e the mousemove event
354      */
355     onDrag: function(e) { /* override this */ },
356
357     /**
358      * Abstract method called when this element fist begins hovering over
359      * another DragDrop obj
360      * @method onDragEnter
361      * @param {Event} e the mousemove event
362      * @param {String|DragDrop[]} id In POINT mode, the element
363      * id this is hovering over.  In INTERSECT mode, an array of one or more
364      * dragdrop items being hovered over.
365      */
366     onDragEnter: function(e, id) { /* override this */ },
367
368     /**
369      * Code that executes immediately before the onDragOver event
370      * @method b4DragOver
371      * @private
372      */
373     b4DragOver: function(e) { },
374
375     /**
376      * Abstract method called when this element is hovering over another
377      * DragDrop obj
378      * @method onDragOver
379      * @param {Event} e the mousemove event
380      * @param {String|DragDrop[]} id In POINT mode, the element
381      * id this is hovering over.  In INTERSECT mode, an array of dd items
382      * being hovered over.
383      */
384     onDragOver: function(e, id) { /* override this */ },
385
386     /**
387      * Code that executes immediately before the onDragOut event
388      * @method b4DragOut
389      * @private
390      */
391     b4DragOut: function(e) { },
392
393     /**
394      * Abstract method called when we are no longer hovering over an element
395      * @method onDragOut
396      * @param {Event} e the mousemove event
397      * @param {String|DragDrop[]} id In POINT mode, the element
398      * id this was hovering over.  In INTERSECT mode, an array of dd items
399      * that the mouse is no longer over.
400      */
401     onDragOut: function(e, id) { /* override this */ },
402
403     /**
404      * Code that executes immediately before the onDragDrop event
405      * @method b4DragDrop
406      * @private
407      */
408     b4DragDrop: function(e) { },
409
410     /**
411      * Abstract method called when this item is dropped on another DragDrop
412      * obj
413      * @method onDragDrop
414      * @param {Event} e the mouseup event
415      * @param {String|DragDrop[]} id In POINT mode, the element
416      * id this was dropped on.  In INTERSECT mode, an array of dd items this
417      * was dropped on.
418      */
419     onDragDrop: function(e, id) { /* override this */ },
420
421     /**
422      * Abstract method called when this item is dropped on an area with no
423      * drop target
424      * @method onInvalidDrop
425      * @param {Event} e the mouseup event
426      */
427     onInvalidDrop: function(e) { /* override this */ },
428
429     /**
430      * Code that executes immediately before the endDrag event
431      * @method b4EndDrag
432      * @private
433      */
434     b4EndDrag: function(e) { },
435
436     /**
437      * Fired when we are done dragging the object
438      * @method endDrag
439      * @param {Event} e the mouseup event
440      */
441     endDrag: function(e) { /* override this */ },
442
443     /**
444      * Code executed immediately before the onMouseDown event
445      * @method b4MouseDown
446      * @param {Event} e the mousedown event
447      * @private
448      */
449     b4MouseDown: function(e) {  },
450
451     /**
452      * Event handler that fires when a drag/drop obj gets a mousedown
453      * @method onMouseDown
454      * @param {Event} e the mousedown event
455      */
456     onMouseDown: function(e) { /* override this */ },
457
458     /**
459      * Event handler that fires when a drag/drop obj gets a mouseup
460      * @method onMouseUp
461      * @param {Event} e the mouseup event
462      */
463     onMouseUp: function(e) { /* override this */ },
464
465     /**
466      * Override the onAvailable method to do what is needed after the initial
467      * position was determined.
468      * @method onAvailable
469      */
470     onAvailable: function () {
471     },
472
473     /*
474      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
475      * @type Object
476      */
477     defaultPadding : {left:0, right:0, top:0, bottom:0},
478
479     /*
480      * Initializes the drag drop object's constraints to restrict movement to a certain element.
481  *
482  * Usage:
483  <pre><code>
484  var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
485                 { dragElId: "existingProxyDiv" });
486  dd.startDrag = function(){
487      this.constrainTo("parent-id");
488  };
489  </code></pre>
490  * Or you can initalize it using the {@link Roo.Element} object:
491  <pre><code>
492  Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
493      startDrag : function(){
494          this.constrainTo("parent-id");
495      }
496  });
497  </code></pre>
498      * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
499      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
500      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
501      * an object containing the sides to pad. For example: {right:10, bottom:10}
502      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
503      */
504     constrainTo : function(constrainTo, pad, inContent){
505         if(typeof pad == "number"){
506             pad = {left: pad, right:pad, top:pad, bottom:pad};
507         }
508         pad = pad || this.defaultPadding;
509         var b = Roo.get(this.getEl()).getBox();
510         var ce = Roo.get(constrainTo);
511         var s = ce.getScroll();
512         var c, cd = ce.dom;
513         if(cd == document.body){
514             c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
515         }else{
516             xy = ce.getXY();
517             c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
518         }
519
520
521         var topSpace = b.y - c.y;
522         var leftSpace = b.x - c.x;
523
524         this.resetConstraints();
525         this.setXConstraint(leftSpace - (pad.left||0), // left
526                 c.width - leftSpace - b.width - (pad.right||0) //right
527         );
528         this.setYConstraint(topSpace - (pad.top||0), //top
529                 c.height - topSpace - b.height - (pad.bottom||0) //bottom
530         );
531     },
532
533     /**
534      * Returns a reference to the linked element
535      * @method getEl
536      * @return {HTMLElement} the html element
537      */
538     getEl: function() {
539         if (!this._domRef) {
540             this._domRef = Roo.getDom(this.id);
541         }
542
543         return this._domRef;
544     },
545
546     /**
547      * Returns a reference to the actual element to drag.  By default this is
548      * the same as the html element, but it can be assigned to another
549      * element. An example of this can be found in Roo.dd.DDProxy
550      * @method getDragEl
551      * @return {HTMLElement} the html element
552      */
553     getDragEl: function() {
554         return Roo.getDom(this.dragElId);
555     },
556
557     /**
558      * Sets up the DragDrop object.  Must be called in the constructor of any
559      * Roo.dd.DragDrop subclass
560      * @method init
561      * @param id the id of the linked element
562      * @param {String} sGroup the group of related items
563      * @param {object} config configuration attributes
564      */
565     init: function(id, sGroup, config) {
566         this.initTarget(id, sGroup, config);
567         Event.on(this.id, "mousedown", this.handleMouseDown, this);
568         // Event.on(this.id, "selectstart", Event.preventDefault);
569     },
570
571     /**
572      * Initializes Targeting functionality only... the object does not
573      * get a mousedown handler.
574      * @method initTarget
575      * @param id the id of the linked element
576      * @param {String} sGroup the group of related items
577      * @param {object} config configuration attributes
578      */
579     initTarget: function(id, sGroup, config) {
580
581         // configuration attributes
582         this.config = config || {};
583
584         // create a local reference to the drag and drop manager
585         this.DDM = Roo.dd.DDM;
586         // initialize the groups array
587         this.groups = {};
588
589         // assume that we have an element reference instead of an id if the
590         // parameter is not a string
591         if (typeof id !== "string") {
592             id = Roo.id(id);
593         }
594
595         // set the id
596         this.id = id;
597
598         // add to an interaction group
599         this.addToGroup((sGroup) ? sGroup : "default");
600
601         // We don't want to register this as the handle with the manager
602         // so we just set the id rather than calling the setter.
603         this.handleElId = id;
604
605         // the linked element is the element that gets dragged by default
606         this.setDragElId(id);
607
608         // by default, clicked anchors will not start drag operations.
609         this.invalidHandleTypes = { A: "A" };
610         this.invalidHandleIds = {};
611         this.invalidHandleClasses = [];
612
613         this.applyConfig();
614
615         this.handleOnAvailable();
616     },
617
618     /**
619      * Applies the configuration parameters that were passed into the constructor.
620      * This is supposed to happen at each level through the inheritance chain.  So
621      * a DDProxy implentation will execute apply config on DDProxy, DD, and
622      * DragDrop in order to get all of the parameters that are available in
623      * each object.
624      * @method applyConfig
625      */
626     applyConfig: function() {
627
628         // configurable properties:
629         //    padding, isTarget, maintainOffset, primaryButtonOnly
630         this.padding           = this.config.padding || [0, 0, 0, 0];
631         this.isTarget          = (this.config.isTarget !== false);
632         this.maintainOffset    = (this.config.maintainOffset);
633         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
634
635     },
636
637     /**
638      * Executed when the linked element is available
639      * @method handleOnAvailable
640      * @private
641      */
642     handleOnAvailable: function() {
643         this.available = true;
644         this.resetConstraints();
645         this.onAvailable();
646     },
647
648      /**
649      * Configures the padding for the target zone in px.  Effectively expands
650      * (or reduces) the virtual object size for targeting calculations.
651      * Supports css-style shorthand; if only one parameter is passed, all sides
652      * will have that padding, and if only two are passed, the top and bottom
653      * will have the first param, the left and right the second.
654      * @method setPadding
655      * @param {int} iTop    Top pad
656      * @param {int} iRight  Right pad
657      * @param {int} iBot    Bot pad
658      * @param {int} iLeft   Left pad
659      */
660     setPadding: function(iTop, iRight, iBot, iLeft) {
661         // this.padding = [iLeft, iRight, iTop, iBot];
662         if (!iRight && 0 !== iRight) {
663             this.padding = [iTop, iTop, iTop, iTop];
664         } else if (!iBot && 0 !== iBot) {
665             this.padding = [iTop, iRight, iTop, iRight];
666         } else {
667             this.padding = [iTop, iRight, iBot, iLeft];
668         }
669     },
670
671     /**
672      * Stores the initial placement of the linked element.
673      * @method setInitialPosition
674      * @param {int} diffX   the X offset, default 0
675      * @param {int} diffY   the Y offset, default 0
676      */
677     setInitPosition: function(diffX, diffY) {
678         var el = this.getEl();
679
680         if (!this.DDM.verifyEl(el)) {
681             return;
682         }
683
684         var dx = diffX || 0;
685         var dy = diffY || 0;
686
687         var p = Dom.getXY( el );
688
689         this.initPageX = p[0] - dx;
690         this.initPageY = p[1] - dy;
691
692         this.lastPageX = p[0];
693         this.lastPageY = p[1];
694
695
696         this.setStartPosition(p);
697     },
698
699     /**
700      * Sets the start position of the element.  This is set when the obj
701      * is initialized, the reset when a drag is started.
702      * @method setStartPosition
703      * @param pos current position (from previous lookup)
704      * @private
705      */
706     setStartPosition: function(pos) {
707         var p = pos || Dom.getXY( this.getEl() );
708         this.deltaSetXY = null;
709
710         this.startPageX = p[0];
711         this.startPageY = p[1];
712     },
713
714     /**
715      * Add this instance to a group of related drag/drop objects.  All
716      * instances belong to at least one group, and can belong to as many
717      * groups as needed.
718      * @method addToGroup
719      * @param sGroup {string} the name of the group
720      */
721     addToGroup: function(sGroup) {
722         this.groups[sGroup] = true;
723         this.DDM.regDragDrop(this, sGroup);
724     },
725
726     /**
727      * Remove's this instance from the supplied interaction group
728      * @method removeFromGroup
729      * @param {string}  sGroup  The group to drop
730      */
731     removeFromGroup: function(sGroup) {
732         if (this.groups[sGroup]) {
733             delete this.groups[sGroup];
734         }
735
736         this.DDM.removeDDFromGroup(this, sGroup);
737     },
738
739     /**
740      * Allows you to specify that an element other than the linked element
741      * will be moved with the cursor during a drag
742      * @method setDragElId
743      * @param id {string} the id of the element that will be used to initiate the drag
744      */
745     setDragElId: function(id) {
746         this.dragElId = id;
747     },
748
749     /**
750      * Allows you to specify a child of the linked element that should be
751      * used to initiate the drag operation.  An example of this would be if
752      * you have a content div with text and links.  Clicking anywhere in the
753      * content area would normally start the drag operation.  Use this method
754      * to specify that an element inside of the content div is the element
755      * that starts the drag operation.
756      * @method setHandleElId
757      * @param id {string} the id of the element that will be used to
758      * initiate the drag.
759      */
760     setHandleElId: function(id) {
761         if (typeof id !== "string") {
762             id = Roo.id(id);
763         }
764         this.handleElId = id;
765         this.DDM.regHandle(this.id, id);
766     },
767
768     /**
769      * Allows you to set an element outside of the linked element as a drag
770      * handle
771      * @method setOuterHandleElId
772      * @param id the id of the element that will be used to initiate the drag
773      */
774     setOuterHandleElId: function(id) {
775         if (typeof id !== "string") {
776             id = Roo.id(id);
777         }
778         Event.on(id, "mousedown",
779                 this.handleMouseDown, this);
780         this.setHandleElId(id);
781
782         this.hasOuterHandles = true;
783     },
784
785     /**
786      * Remove all drag and drop hooks for this element
787      * @method unreg
788      */
789     unreg: function() {
790         Event.un(this.id, "mousedown",
791                 this.handleMouseDown);
792         this._domRef = null;
793         this.DDM._remove(this);
794     },
795
796     destroy : function(){
797         this.unreg();
798     },
799
800     /**
801      * Returns true if this instance is locked, or the drag drop mgr is locked
802      * (meaning that all drag/drop is disabled on the page.)
803      * @method isLocked
804      * @return {boolean} true if this obj or all drag/drop is locked, else
805      * false
806      */
807     isLocked: function() {
808         return (this.DDM.isLocked() || this.locked);
809     },
810
811     /**
812      * Fired when this object is clicked
813      * @method handleMouseDown
814      * @param {Event} e
815      * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
816      * @private
817      */
818     handleMouseDown: function(e, oDD){
819         if (this.primaryButtonOnly && e.button != 0) {
820             return;
821         }
822
823         if (this.isLocked()) {
824             return;
825         }
826
827         this.DDM.refreshCache(this.groups);
828
829         var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
830         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
831         } else {
832             if (this.clickValidator(e)) {
833
834                 // set the initial element position
835                 this.setStartPosition();
836
837
838                 this.b4MouseDown(e);
839                 this.onMouseDown(e);
840
841                 this.DDM.handleMouseDown(e, this);
842
843                 this.DDM.stopEvent(e);
844             } else {
845
846
847             }
848         }
849     },
850
851     clickValidator: function(e) {
852         var target = e.getTarget();
853         return ( this.isValidHandleChild(target) &&
854                     (this.id == this.handleElId ||
855                         this.DDM.handleWasClicked(target, this.id)) );
856     },
857
858     /**
859      * Allows you to specify a tag name that should not start a drag operation
860      * when clicked.  This is designed to facilitate embedding links within a
861      * drag handle that do something other than start the drag.
862      * @method addInvalidHandleType
863      * @param {string} tagName the type of element to exclude
864      */
865     addInvalidHandleType: function(tagName) {
866         var type = tagName.toUpperCase();
867         this.invalidHandleTypes[type] = type;
868     },
869
870     /**
871      * Lets you to specify an element id for a child of a drag handle
872      * that should not initiate a drag
873      * @method addInvalidHandleId
874      * @param {string} id the element id of the element you wish to ignore
875      */
876     addInvalidHandleId: function(id) {
877         if (typeof id !== "string") {
878             id = Roo.id(id);
879         }
880         this.invalidHandleIds[id] = id;
881     },
882
883     /**
884      * Lets you specify a css class of elements that will not initiate a drag
885      * @method addInvalidHandleClass
886      * @param {string} cssClass the class of the elements you wish to ignore
887      */
888     addInvalidHandleClass: function(cssClass) {
889         this.invalidHandleClasses.push(cssClass);
890     },
891
892     /**
893      * Unsets an excluded tag name set by addInvalidHandleType
894      * @method removeInvalidHandleType
895      * @param {string} tagName the type of element to unexclude
896      */
897     removeInvalidHandleType: function(tagName) {
898         var type = tagName.toUpperCase();
899         // this.invalidHandleTypes[type] = null;
900         delete this.invalidHandleTypes[type];
901     },
902
903     /**
904      * Unsets an invalid handle id
905      * @method removeInvalidHandleId
906      * @param {string} id the id of the element to re-enable
907      */
908     removeInvalidHandleId: function(id) {
909         if (typeof id !== "string") {
910             id = Roo.id(id);
911         }
912         delete this.invalidHandleIds[id];
913     },
914
915     /**
916      * Unsets an invalid css class
917      * @method removeInvalidHandleClass
918      * @param {string} cssClass the class of the element(s) you wish to
919      * re-enable
920      */
921     removeInvalidHandleClass: function(cssClass) {
922         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
923             if (this.invalidHandleClasses[i] == cssClass) {
924                 delete this.invalidHandleClasses[i];
925             }
926         }
927     },
928
929     /**
930      * Checks the tag exclusion list to see if this click should be ignored
931      * @method isValidHandleChild
932      * @param {HTMLElement} node the HTMLElement to evaluate
933      * @return {boolean} true if this is a valid tag type, false if not
934      */
935     isValidHandleChild: function(node) {
936
937         var valid = true;
938         // var n = (node.nodeName == "#text") ? node.parentNode : node;
939         var nodeName;
940         try {
941             nodeName = node.nodeName.toUpperCase();
942         } catch(e) {
943             nodeName = node.nodeName;
944         }
945         valid = valid && !this.invalidHandleTypes[nodeName];
946         valid = valid && !this.invalidHandleIds[node.id];
947
948         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
949             valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
950         }
951
952
953         return valid;
954
955     },
956
957     /**
958      * Create the array of horizontal tick marks if an interval was specified
959      * in setXConstraint().
960      * @method setXTicks
961      * @private
962      */
963     setXTicks: function(iStartX, iTickSize) {
964         this.xTicks = [];
965         this.xTickSize = iTickSize;
966
967         var tickMap = {};
968
969         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
970             if (!tickMap[i]) {
971                 this.xTicks[this.xTicks.length] = i;
972                 tickMap[i] = true;
973             }
974         }
975
976         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
977             if (!tickMap[i]) {
978                 this.xTicks[this.xTicks.length] = i;
979                 tickMap[i] = true;
980             }
981         }
982
983         this.xTicks.sort(this.DDM.numericSort) ;
984     },
985
986     /**
987      * Create the array of vertical tick marks if an interval was specified in
988      * setYConstraint().
989      * @method setYTicks
990      * @private
991      */
992     setYTicks: function(iStartY, iTickSize) {
993         this.yTicks = [];
994         this.yTickSize = iTickSize;
995
996         var tickMap = {};
997
998         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
999             if (!tickMap[i]) {
1000                 this.yTicks[this.yTicks.length] = i;
1001                 tickMap[i] = true;
1002             }
1003         }
1004
1005         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1006             if (!tickMap[i]) {
1007                 this.yTicks[this.yTicks.length] = i;
1008                 tickMap[i] = true;
1009             }
1010         }
1011
1012         this.yTicks.sort(this.DDM.numericSort) ;
1013     },
1014
1015     /**
1016      * By default, the element can be dragged any place on the screen.  Use
1017      * this method to limit the horizontal travel of the element.  Pass in
1018      * 0,0 for the parameters if you want to lock the drag to the y axis.
1019      * @method setXConstraint
1020      * @param {int} iLeft the number of pixels the element can move to the left
1021      * @param {int} iRight the number of pixels the element can move to the
1022      * right
1023      * @param {int} iTickSize optional parameter for specifying that the
1024      * element
1025      * should move iTickSize pixels at a time.
1026      */
1027     setXConstraint: function(iLeft, iRight, iTickSize) {
1028         this.leftConstraint = iLeft;
1029         this.rightConstraint = iRight;
1030
1031         this.minX = this.initPageX - iLeft;
1032         this.maxX = this.initPageX + iRight;
1033         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1034
1035         this.constrainX = true;
1036     },
1037
1038     /**
1039      * Clears any constraints applied to this instance.  Also clears ticks
1040      * since they can't exist independent of a constraint at this time.
1041      * @method clearConstraints
1042      */
1043     clearConstraints: function() {
1044         this.constrainX = false;
1045         this.constrainY = false;
1046         this.clearTicks();
1047     },
1048
1049     /**
1050      * Clears any tick interval defined for this instance
1051      * @method clearTicks
1052      */
1053     clearTicks: function() {
1054         this.xTicks = null;
1055         this.yTicks = null;
1056         this.xTickSize = 0;
1057         this.yTickSize = 0;
1058     },
1059
1060     /**
1061      * By default, the element can be dragged any place on the screen.  Set
1062      * this to limit the vertical travel of the element.  Pass in 0,0 for the
1063      * parameters if you want to lock the drag to the x axis.
1064      * @method setYConstraint
1065      * @param {int} iUp the number of pixels the element can move up
1066      * @param {int} iDown the number of pixels the element can move down
1067      * @param {int} iTickSize optional parameter for specifying that the
1068      * element should move iTickSize pixels at a time.
1069      */
1070     setYConstraint: function(iUp, iDown, iTickSize) {
1071         this.topConstraint = iUp;
1072         this.bottomConstraint = iDown;
1073
1074         this.minY = this.initPageY - iUp;
1075         this.maxY = this.initPageY + iDown;
1076         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1077
1078         this.constrainY = true;
1079
1080     },
1081
1082     /**
1083      * resetConstraints must be called if you manually reposition a dd element.
1084      * @method resetConstraints
1085      * @param {boolean} maintainOffset
1086      */
1087     resetConstraints: function() {
1088
1089
1090         // Maintain offsets if necessary
1091         if (this.initPageX || this.initPageX === 0) {
1092             // figure out how much this thing has moved
1093             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1094             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1095
1096             this.setInitPosition(dx, dy);
1097
1098         // This is the first time we have detected the element's position
1099         } else {
1100             this.setInitPosition();
1101         }
1102
1103         if (this.constrainX) {
1104             this.setXConstraint( this.leftConstraint,
1105                                  this.rightConstraint,
1106                                  this.xTickSize        );
1107         }
1108
1109         if (this.constrainY) {
1110             this.setYConstraint( this.topConstraint,
1111                                  this.bottomConstraint,
1112                                  this.yTickSize         );
1113         }
1114     },
1115
1116     /**
1117      * Normally the drag element is moved pixel by pixel, but we can specify
1118      * that it move a number of pixels at a time.  This method resolves the
1119      * location when we have it set up like this.
1120      * @method getTick
1121      * @param {int} val where we want to place the object
1122      * @param {int[]} tickArray sorted array of valid points
1123      * @return {int} the closest tick
1124      * @private
1125      */
1126     getTick: function(val, tickArray) {
1127
1128         if (!tickArray) {
1129             // If tick interval is not defined, it is effectively 1 pixel,
1130             // so we return the value passed to us.
1131             return val;
1132         } else if (tickArray[0] >= val) {
1133             // The value is lower than the first tick, so we return the first
1134             // tick.
1135             return tickArray[0];
1136         } else {
1137             for (var i=0, len=tickArray.length; i<len; ++i) {
1138                 var next = i + 1;
1139                 if (tickArray[next] && tickArray[next] >= val) {
1140                     var diff1 = val - tickArray[i];
1141                     var diff2 = tickArray[next] - val;
1142                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1143                 }
1144             }
1145
1146             // The value is larger than the last tick, so we return the last
1147             // tick.
1148             return tickArray[tickArray.length - 1];
1149         }
1150     },
1151
1152     /**
1153      * toString method
1154      * @method toString
1155      * @return {string} string representation of the dd obj
1156      */
1157     toString: function() {
1158         return ("DragDrop " + this.id);
1159     }
1160
1161 });
1162
1163 })();
1164 /*
1165  * Based on:
1166  * Ext JS Library 1.1.1
1167  * Copyright(c) 2006-2007, Ext JS, LLC.
1168  *
1169  * Originally Released Under LGPL - original licence link has changed is not relivant.
1170  *
1171  * Fork - LGPL
1172  * <script type="text/javascript">
1173  */
1174
1175
1176 /**
1177  * The drag and drop utility provides a framework for building drag and drop
1178  * applications.  In addition to enabling drag and drop for specific elements,
1179  * the drag and drop elements are tracked by the manager class, and the
1180  * interactions between the various elements are tracked during the drag and
1181  * the implementing code is notified about these important moments.
1182  */
1183
1184 // Only load the library once.  Rewriting the manager class would orphan
1185 // existing drag and drop instances.
1186 if (!Roo.dd.DragDropMgr) {
1187
1188 /**
1189  * @class Roo.dd.DragDropMgr
1190  * DragDropMgr is a singleton that tracks the element interaction for
1191  * all DragDrop items in the window.  Generally, you will not call
1192  * this class directly, but it does have helper methods that could
1193  * be useful in your DragDrop implementations.
1194  * @singleton
1195  */
1196 Roo.dd.DragDropMgr = function() {
1197
1198     var Event = Roo.EventManager;
1199
1200     return {
1201
1202         /**
1203          * Two dimensional Array of registered DragDrop objects.  The first
1204          * dimension is the DragDrop item group, the second the DragDrop
1205          * object.
1206          * @property ids
1207          * @type {string: string}
1208          * @private
1209          * @static
1210          */
1211         ids: {},
1212
1213         /**
1214          * Array of element ids defined as drag handles.  Used to determine
1215          * if the element that generated the mousedown event is actually the
1216          * handle and not the html element itself.
1217          * @property handleIds
1218          * @type {string: string}
1219          * @private
1220          * @static
1221          */
1222         handleIds: {},
1223
1224         /**
1225          * the DragDrop object that is currently being dragged
1226          * @property dragCurrent
1227          * @type DragDrop
1228          * @private
1229          * @static
1230          **/
1231         dragCurrent: null,
1232
1233         /**
1234          * the DragDrop object(s) that are being hovered over
1235          * @property dragOvers
1236          * @type Array
1237          * @private
1238          * @static
1239          */
1240         dragOvers: {},
1241
1242         /**
1243          * the X distance between the cursor and the object being dragged
1244          * @property deltaX
1245          * @type int
1246          * @private
1247          * @static
1248          */
1249         deltaX: 0,
1250
1251         /**
1252          * the Y distance between the cursor and the object being dragged
1253          * @property deltaY
1254          * @type int
1255          * @private
1256          * @static
1257          */
1258         deltaY: 0,
1259
1260         /**
1261          * Flag to determine if we should prevent the default behavior of the
1262          * events we define. By default this is true, but this can be set to
1263          * false if you need the default behavior (not recommended)
1264          * @property preventDefault
1265          * @type boolean
1266          * @static
1267          */
1268         preventDefault: true,
1269
1270         /**
1271          * Flag to determine if we should stop the propagation of the events
1272          * we generate. This is true by default but you may want to set it to
1273          * false if the html element contains other features that require the
1274          * mouse click.
1275          * @property stopPropagation
1276          * @type boolean
1277          * @static
1278          */
1279         stopPropagation: true,
1280
1281         /**
1282          * Internal flag that is set to true when drag and drop has been
1283          * intialized
1284          * @property initialized
1285          * @private
1286          * @static
1287          */
1288         initalized: false,
1289
1290         /**
1291          * All drag and drop can be disabled.
1292          * @property locked
1293          * @private
1294          * @static
1295          */
1296         locked: false,
1297
1298         /**
1299          * Called the first time an element is registered.
1300          * @method init
1301          * @private
1302          * @static
1303          */
1304         init: function() {
1305             this.initialized = true;
1306         },
1307
1308         /**
1309          * In point mode, drag and drop interaction is defined by the
1310          * location of the cursor during the drag/drop
1311          * @property POINT
1312          * @type int
1313          * @static
1314          */
1315         POINT: 0,
1316
1317         /**
1318          * In intersect mode, drag and drop interactio nis defined by the
1319          * overlap of two or more drag and drop objects.
1320          * @property INTERSECT
1321          * @type int
1322          * @static
1323          */
1324         INTERSECT: 1,
1325
1326         /**
1327          * The current drag and drop mode.  Default: POINT
1328          * @property mode
1329          * @type int
1330          * @static
1331          */
1332         mode: 0,
1333
1334         /**
1335          * Runs method on all drag and drop objects
1336          * @method _execOnAll
1337          * @private
1338          * @static
1339          */
1340         _execOnAll: function(sMethod, args) {
1341             for (var i in this.ids) {
1342                 for (var j in this.ids[i]) {
1343                     var oDD = this.ids[i][j];
1344                     if (! this.isTypeOfDD(oDD)) {
1345                         continue;
1346                     }
1347                     oDD[sMethod].apply(oDD, args);
1348                 }
1349             }
1350         },
1351
1352         /**
1353          * Drag and drop initialization.  Sets up the global event handlers
1354          * @method _onLoad
1355          * @private
1356          * @static
1357          */
1358         _onLoad: function() {
1359
1360             this.init();
1361
1362
1363             Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1364             Event.on(document, "mousemove", this.handleMouseMove, this, true);
1365             Event.on(window,   "unload",    this._onUnload, this, true);
1366             Event.on(window,   "resize",    this._onResize, this, true);
1367             // Event.on(window,   "mouseout",    this._test);
1368
1369         },
1370
1371         /**
1372          * Reset constraints on all drag and drop objs
1373          * @method _onResize
1374          * @private
1375          * @static
1376          */
1377         _onResize: function(e) {
1378             this._execOnAll("resetConstraints", []);
1379         },
1380
1381         /**
1382          * Lock all drag and drop functionality
1383          * @method lock
1384          * @static
1385          */
1386         lock: function() { this.locked = true; },
1387
1388         /**
1389          * Unlock all drag and drop functionality
1390          * @method unlock
1391          * @static
1392          */
1393         unlock: function() { this.locked = false; },
1394
1395         /**
1396          * Is drag and drop locked?
1397          * @method isLocked
1398          * @return {boolean} True if drag and drop is locked, false otherwise.
1399          * @static
1400          */
1401         isLocked: function() { return this.locked; },
1402
1403         /**
1404          * Location cache that is set for all drag drop objects when a drag is
1405          * initiated, cleared when the drag is finished.
1406          * @property locationCache
1407          * @private
1408          * @static
1409          */
1410         locationCache: {},
1411
1412         /**
1413          * Set useCache to false if you want to force object the lookup of each
1414          * drag and drop linked element constantly during a drag.
1415          * @property useCache
1416          * @type boolean
1417          * @static
1418          */
1419         useCache: true,
1420
1421         /**
1422          * The number of pixels that the mouse needs to move after the
1423          * mousedown before the drag is initiated.  Default=3;
1424          * @property clickPixelThresh
1425          * @type int
1426          * @static
1427          */
1428         clickPixelThresh: 3,
1429
1430         /**
1431          * The number of milliseconds after the mousedown event to initiate the
1432          * drag if we don't get a mouseup event. Default=1000
1433          * @property clickTimeThresh
1434          * @type int
1435          * @static
1436          */
1437         clickTimeThresh: 350,
1438
1439         /**
1440          * Flag that indicates that either the drag pixel threshold or the
1441          * mousdown time threshold has been met
1442          * @property dragThreshMet
1443          * @type boolean
1444          * @private
1445          * @static
1446          */
1447         dragThreshMet: false,
1448
1449         /**
1450          * Timeout used for the click time threshold
1451          * @property clickTimeout
1452          * @type Object
1453          * @private
1454          * @static
1455          */
1456         clickTimeout: null,
1457
1458         /**
1459          * The X position of the mousedown event stored for later use when a
1460          * drag threshold is met.
1461          * @property startX
1462          * @type int
1463          * @private
1464          * @static
1465          */
1466         startX: 0,
1467
1468         /**
1469          * The Y position of the mousedown event stored for later use when a
1470          * drag threshold is met.
1471          * @property startY
1472          * @type int
1473          * @private
1474          * @static
1475          */
1476         startY: 0,
1477
1478         /**
1479          * Each DragDrop instance must be registered with the DragDropMgr.
1480          * This is executed in DragDrop.init()
1481          * @method regDragDrop
1482          * @param {DragDrop} oDD the DragDrop object to register
1483          * @param {String} sGroup the name of the group this element belongs to
1484          * @static
1485          */
1486         regDragDrop: function(oDD, sGroup) {
1487             if (!this.initialized) { this.init(); }
1488
1489             if (!this.ids[sGroup]) {
1490                 this.ids[sGroup] = {};
1491             }
1492             this.ids[sGroup][oDD.id] = oDD;
1493         },
1494
1495         /**
1496          * Removes the supplied dd instance from the supplied group. Executed
1497          * by DragDrop.removeFromGroup, so don't call this function directly.
1498          * @method removeDDFromGroup
1499          * @private
1500          * @static
1501          */
1502         removeDDFromGroup: function(oDD, sGroup) {
1503             if (!this.ids[sGroup]) {
1504                 this.ids[sGroup] = {};
1505             }
1506
1507             var obj = this.ids[sGroup];
1508             if (obj && obj[oDD.id]) {
1509                 delete obj[oDD.id];
1510             }
1511         },
1512
1513         /**
1514          * Unregisters a drag and drop item.  This is executed in
1515          * DragDrop.unreg, use that method instead of calling this directly.
1516          * @method _remove
1517          * @private
1518          * @static
1519          */
1520         _remove: function(oDD) {
1521             for (var g in oDD.groups) {
1522                 if (g && this.ids[g][oDD.id]) {
1523                     delete this.ids[g][oDD.id];
1524                 }
1525             }
1526             delete this.handleIds[oDD.id];
1527         },
1528
1529         /**
1530          * Each DragDrop handle element must be registered.  This is done
1531          * automatically when executing DragDrop.setHandleElId()
1532          * @method regHandle
1533          * @param {String} sDDId the DragDrop id this element is a handle for
1534          * @param {String} sHandleId the id of the element that is the drag
1535          * handle
1536          * @static
1537          */
1538         regHandle: function(sDDId, sHandleId) {
1539             if (!this.handleIds[sDDId]) {
1540                 this.handleIds[sDDId] = {};
1541             }
1542             this.handleIds[sDDId][sHandleId] = sHandleId;
1543         },
1544
1545         /**
1546          * Utility function to determine if a given element has been
1547          * registered as a drag drop item.
1548          * @method isDragDrop
1549          * @param {String} id the element id to check
1550          * @return {boolean} true if this element is a DragDrop item,
1551          * false otherwise
1552          * @static
1553          */
1554         isDragDrop: function(id) {
1555             return ( this.getDDById(id) ) ? true : false;
1556         },
1557
1558         /**
1559          * Returns the drag and drop instances that are in all groups the
1560          * passed in instance belongs to.
1561          * @method getRelated
1562          * @param {DragDrop} p_oDD the obj to get related data for
1563          * @param {boolean} bTargetsOnly if true, only return targetable objs
1564          * @return {DragDrop[]} the related instances
1565          * @static
1566          */
1567         getRelated: function(p_oDD, bTargetsOnly) {
1568             var oDDs = [];
1569             for (var i in p_oDD.groups) {
1570                 for (j in this.ids[i]) {
1571                     var dd = this.ids[i][j];
1572                     if (! this.isTypeOfDD(dd)) {
1573                         continue;
1574                     }
1575                     if (!bTargetsOnly || dd.isTarget) {
1576                         oDDs[oDDs.length] = dd;
1577                     }
1578                 }
1579             }
1580
1581             return oDDs;
1582         },
1583
1584         /**
1585          * Returns true if the specified dd target is a legal target for
1586          * the specifice drag obj
1587          * @method isLegalTarget
1588          * @param {DragDrop} the drag obj
1589          * @param {DragDrop} the target
1590          * @return {boolean} true if the target is a legal target for the
1591          * dd obj
1592          * @static
1593          */
1594         isLegalTarget: function (oDD, oTargetDD) {
1595             var targets = this.getRelated(oDD, true);
1596             for (var i=0, len=targets.length;i<len;++i) {
1597                 if (targets[i].id == oTargetDD.id) {
1598                     return true;
1599                 }
1600             }
1601
1602             return false;
1603         },
1604
1605         /**
1606          * My goal is to be able to transparently determine if an object is
1607          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1608          * returns "object", oDD.constructor.toString() always returns
1609          * "DragDrop" and not the name of the subclass.  So for now it just
1610          * evaluates a well-known variable in DragDrop.
1611          * @method isTypeOfDD
1612          * @param {Object} the object to evaluate
1613          * @return {boolean} true if typeof oDD = DragDrop
1614          * @static
1615          */
1616         isTypeOfDD: function (oDD) {
1617             return (oDD && oDD.__ygDragDrop);
1618         },
1619
1620         /**
1621          * Utility function to determine if a given element has been
1622          * registered as a drag drop handle for the given Drag Drop object.
1623          * @method isHandle
1624          * @param {String} id the element id to check
1625          * @return {boolean} true if this element is a DragDrop handle, false
1626          * otherwise
1627          * @static
1628          */
1629         isHandle: function(sDDId, sHandleId) {
1630             return ( this.handleIds[sDDId] &&
1631                             this.handleIds[sDDId][sHandleId] );
1632         },
1633
1634         /**
1635          * Returns the DragDrop instance for a given id
1636          * @method getDDById
1637          * @param {String} id the id of the DragDrop object
1638          * @return {DragDrop} the drag drop object, null if it is not found
1639          * @static
1640          */
1641         getDDById: function(id) {
1642             for (var i in this.ids) {
1643                 if (this.ids[i][id]) {
1644                     return this.ids[i][id];
1645                 }
1646             }
1647             return null;
1648         },
1649
1650         /**
1651          * Fired after a registered DragDrop object gets the mousedown event.
1652          * Sets up the events required to track the object being dragged
1653          * @method handleMouseDown
1654          * @param {Event} e the event
1655          * @param oDD the DragDrop object being dragged
1656          * @private
1657          * @static
1658          */
1659         handleMouseDown: function(e, oDD) {
1660             if(Roo.QuickTips){
1661                 Roo.QuickTips.disable();
1662             }
1663             this.currentTarget = e.getTarget();
1664
1665             this.dragCurrent = oDD;
1666
1667             var el = oDD.getEl();
1668
1669             // track start position
1670             this.startX = e.getPageX();
1671             this.startY = e.getPageY();
1672
1673             this.deltaX = this.startX - el.offsetLeft;
1674             this.deltaY = this.startY - el.offsetTop;
1675
1676             this.dragThreshMet = false;
1677
1678             this.clickTimeout = setTimeout(
1679                     function() {
1680                         var DDM = Roo.dd.DDM;
1681                         DDM.startDrag(DDM.startX, DDM.startY);
1682                     },
1683                     this.clickTimeThresh );
1684         },
1685
1686         /**
1687          * Fired when either the drag pixel threshol or the mousedown hold
1688          * time threshold has been met.
1689          * @method startDrag
1690          * @param x {int} the X position of the original mousedown
1691          * @param y {int} the Y position of the original mousedown
1692          * @static
1693          */
1694         startDrag: function(x, y) {
1695             clearTimeout(this.clickTimeout);
1696             if (this.dragCurrent) {
1697                 this.dragCurrent.b4StartDrag(x, y);
1698                 this.dragCurrent.startDrag(x, y);
1699             }
1700             this.dragThreshMet = true;
1701         },
1702
1703         /**
1704          * Internal function to handle the mouseup event.  Will be invoked
1705          * from the context of the document.
1706          * @method handleMouseUp
1707          * @param {Event} e the event
1708          * @private
1709          * @static
1710          */
1711         handleMouseUp: function(e) {
1712
1713             if(Roo.QuickTips){
1714                 Roo.QuickTips.enable();
1715             }
1716             if (! this.dragCurrent) {
1717                 return;
1718             }
1719
1720             clearTimeout(this.clickTimeout);
1721
1722             if (this.dragThreshMet) {
1723                 this.fireEvents(e, true);
1724             } else {
1725             }
1726
1727             this.stopDrag(e);
1728
1729             this.stopEvent(e);
1730         },
1731
1732         /**
1733          * Utility to stop event propagation and event default, if these
1734          * features are turned on.
1735          * @method stopEvent
1736          * @param {Event} e the event as returned by this.getEvent()
1737          * @static
1738          */
1739         stopEvent: function(e){
1740             if(this.stopPropagation) {
1741                 e.stopPropagation();
1742             }
1743
1744             if (this.preventDefault) {
1745                 e.preventDefault();
1746             }
1747         },
1748
1749         /**
1750          * Internal function to clean up event handlers after the drag
1751          * operation is complete
1752          * @method stopDrag
1753          * @param {Event} e the event
1754          * @private
1755          * @static
1756          */
1757         stopDrag: function(e) {
1758             // Fire the drag end event for the item that was dragged
1759             if (this.dragCurrent) {
1760                 if (this.dragThreshMet) {
1761                     this.dragCurrent.b4EndDrag(e);
1762                     this.dragCurrent.endDrag(e);
1763                 }
1764
1765                 this.dragCurrent.onMouseUp(e);
1766             }
1767
1768             this.dragCurrent = null;
1769             this.dragOvers = {};
1770         },
1771
1772         /**
1773          * Internal function to handle the mousemove event.  Will be invoked
1774          * from the context of the html element.
1775          *
1776          * @TODO figure out what we can do about mouse events lost when the
1777          * user drags objects beyond the window boundary.  Currently we can
1778          * detect this in internet explorer by verifying that the mouse is
1779          * down during the mousemove event.  Firefox doesn't give us the
1780          * button state on the mousemove event.
1781          * @method handleMouseMove
1782          * @param {Event} e the event
1783          * @private
1784          * @static
1785          */
1786         handleMouseMove: function(e) {
1787             if (! this.dragCurrent) {
1788                 return true;
1789             }
1790
1791             // var button = e.which || e.button;
1792
1793             // check for IE mouseup outside of page boundary
1794             if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1795                 this.stopEvent(e);
1796                 return this.handleMouseUp(e);
1797             }
1798
1799             if (!this.dragThreshMet) {
1800                 var diffX = Math.abs(this.startX - e.getPageX());
1801                 var diffY = Math.abs(this.startY - e.getPageY());
1802                 if (diffX > this.clickPixelThresh ||
1803                             diffY > this.clickPixelThresh) {
1804                     this.startDrag(this.startX, this.startY);
1805                 }
1806             }
1807
1808             if (this.dragThreshMet) {
1809                 this.dragCurrent.b4Drag(e);
1810                 this.dragCurrent.onDrag(e);
1811                 if(!this.dragCurrent.moveOnly){
1812                     this.fireEvents(e, false);
1813                 }
1814             }
1815
1816             this.stopEvent(e);
1817
1818             return true;
1819         },
1820
1821         /**
1822          * Iterates over all of the DragDrop elements to find ones we are
1823          * hovering over or dropping on
1824          * @method fireEvents
1825          * @param {Event} e the event
1826          * @param {boolean} isDrop is this a drop op or a mouseover op?
1827          * @private
1828          * @static
1829          */
1830         fireEvents: function(e, isDrop) {
1831             var dc = this.dragCurrent;
1832
1833             // If the user did the mouse up outside of the window, we could
1834             // get here even though we have ended the drag.
1835             if (!dc || dc.isLocked()) {
1836                 return;
1837             }
1838
1839             var pt = e.getPoint();
1840
1841             // cache the previous dragOver array
1842             var oldOvers = [];
1843
1844             var outEvts   = [];
1845             var overEvts  = [];
1846             var dropEvts  = [];
1847             var enterEvts = [];
1848
1849             // Check to see if the object(s) we were hovering over is no longer
1850             // being hovered over so we can fire the onDragOut event
1851             for (var i in this.dragOvers) {
1852
1853                 var ddo = this.dragOvers[i];
1854
1855                 if (! this.isTypeOfDD(ddo)) {
1856                     continue;
1857                 }
1858
1859                 if (! this.isOverTarget(pt, ddo, this.mode)) {
1860                     outEvts.push( ddo );
1861                 }
1862
1863                 oldOvers[i] = true;
1864                 delete this.dragOvers[i];
1865             }
1866
1867             for (var sGroup in dc.groups) {
1868
1869                 if ("string" != typeof sGroup) {
1870                     continue;
1871                 }
1872
1873                 for (i in this.ids[sGroup]) {
1874                     var oDD = this.ids[sGroup][i];
1875                     if (! this.isTypeOfDD(oDD)) {
1876                         continue;
1877                     }
1878
1879                     if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1880                         if (this.isOverTarget(pt, oDD, this.mode)) {
1881                             // look for drop interactions
1882                             if (isDrop) {
1883                                 dropEvts.push( oDD );
1884                             // look for drag enter and drag over interactions
1885                             } else {
1886
1887                                 // initial drag over: dragEnter fires
1888                                 if (!oldOvers[oDD.id]) {
1889                                     enterEvts.push( oDD );
1890                                 // subsequent drag overs: dragOver fires
1891                                 } else {
1892                                     overEvts.push( oDD );
1893                                 }
1894
1895                                 this.dragOvers[oDD.id] = oDD;
1896                             }
1897                         }
1898                     }
1899                 }
1900             }
1901
1902             if (this.mode) {
1903                 if (outEvts.length) {
1904                     dc.b4DragOut(e, outEvts);
1905                     dc.onDragOut(e, outEvts);
1906                 }
1907
1908                 if (enterEvts.length) {
1909                     dc.onDragEnter(e, enterEvts);
1910                 }
1911
1912                 if (overEvts.length) {
1913                     dc.b4DragOver(e, overEvts);
1914                     dc.onDragOver(e, overEvts);
1915                 }
1916
1917                 if (dropEvts.length) {
1918                     dc.b4DragDrop(e, dropEvts);
1919                     dc.onDragDrop(e, dropEvts);
1920                 }
1921
1922             } else {
1923                 // fire dragout events
1924                 var len = 0;
1925                 for (i=0, len=outEvts.length; i<len; ++i) {
1926                     dc.b4DragOut(e, outEvts[i].id);
1927                     dc.onDragOut(e, outEvts[i].id);
1928                 }
1929
1930                 // fire enter events
1931                 for (i=0,len=enterEvts.length; i<len; ++i) {
1932                     // dc.b4DragEnter(e, oDD.id);
1933                     dc.onDragEnter(e, enterEvts[i].id);
1934                 }
1935
1936                 // fire over events
1937                 for (i=0,len=overEvts.length; i<len; ++i) {
1938                     dc.b4DragOver(e, overEvts[i].id);
1939                     dc.onDragOver(e, overEvts[i].id);
1940                 }
1941
1942                 // fire drop events
1943                 for (i=0, len=dropEvts.length; i<len; ++i) {
1944                     dc.b4DragDrop(e, dropEvts[i].id);
1945                     dc.onDragDrop(e, dropEvts[i].id);
1946                 }
1947
1948             }
1949
1950             // notify about a drop that did not find a target
1951             if (isDrop && !dropEvts.length) {
1952                 dc.onInvalidDrop(e);
1953             }
1954
1955         },
1956
1957         /**
1958          * Helper function for getting the best match from the list of drag
1959          * and drop objects returned by the drag and drop events when we are
1960          * in INTERSECT mode.  It returns either the first object that the
1961          * cursor is over, or the object that has the greatest overlap with
1962          * the dragged element.
1963          * @method getBestMatch
1964          * @param  {DragDrop[]} dds The array of drag and drop objects
1965          * targeted
1966          * @return {DragDrop}       The best single match
1967          * @static
1968          */
1969         getBestMatch: function(dds) {
1970             var winner = null;
1971             // Return null if the input is not what we expect
1972             //if (!dds || !dds.length || dds.length == 0) {
1973                // winner = null;
1974             // If there is only one item, it wins
1975             //} else if (dds.length == 1) {
1976
1977             var len = dds.length;
1978
1979             if (len == 1) {
1980                 winner = dds[0];
1981             } else {
1982                 // Loop through the targeted items
1983                 for (var i=0; i<len; ++i) {
1984                     var dd = dds[i];
1985                     // If the cursor is over the object, it wins.  If the
1986                     // cursor is over multiple matches, the first one we come
1987                     // to wins.
1988                     if (dd.cursorIsOver) {
1989                         winner = dd;
1990                         break;
1991                     // Otherwise the object with the most overlap wins
1992                     } else {
1993                         if (!winner ||
1994                             winner.overlap.getArea() < dd.overlap.getArea()) {
1995                             winner = dd;
1996                         }
1997                     }
1998                 }
1999             }
2000
2001             return winner;
2002         },
2003
2004         /**
2005          * Refreshes the cache of the top-left and bottom-right points of the
2006          * drag and drop objects in the specified group(s).  This is in the
2007          * format that is stored in the drag and drop instance, so typical
2008          * usage is:
2009          * <code>
2010          * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2011          * </code>
2012          * Alternatively:
2013          * <code>
2014          * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2015          * </code>
2016          * @TODO this really should be an indexed array.  Alternatively this
2017          * method could accept both.
2018          * @method refreshCache
2019          * @param {Object} groups an associative array of groups to refresh
2020          * @static
2021          */
2022         refreshCache: function(groups) {
2023             for (var sGroup in groups) {
2024                 if ("string" != typeof sGroup) {
2025                     continue;
2026                 }
2027                 for (var i in this.ids[sGroup]) {
2028                     var oDD = this.ids[sGroup][i];
2029
2030                     if (this.isTypeOfDD(oDD)) {
2031                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2032                         var loc = this.getLocation(oDD);
2033                         if (loc) {
2034                             this.locationCache[oDD.id] = loc;
2035                         } else {
2036                             delete this.locationCache[oDD.id];
2037                             // this will unregister the drag and drop object if
2038                             // the element is not in a usable state
2039                             // oDD.unreg();
2040                         }
2041                     }
2042                 }
2043             }
2044         },
2045
2046         /**
2047          * This checks to make sure an element exists and is in the DOM.  The
2048          * main purpose is to handle cases where innerHTML is used to remove
2049          * drag and drop objects from the DOM.  IE provides an 'unspecified
2050          * error' when trying to access the offsetParent of such an element
2051          * @method verifyEl
2052          * @param {HTMLElement} el the element to check
2053          * @return {boolean} true if the element looks usable
2054          * @static
2055          */
2056         verifyEl: function(el) {
2057             if (el) {
2058                 var parent;
2059                 if(Roo.isIE){
2060                     try{
2061                         parent = el.offsetParent;
2062                     }catch(e){}
2063                 }else{
2064                     parent = el.offsetParent;
2065                 }
2066                 if (parent) {
2067                     return true;
2068                 }
2069             }
2070
2071             return false;
2072         },
2073
2074         /**
2075          * Returns a Region object containing the drag and drop element's position
2076          * and size, including the padding configured for it
2077          * @method getLocation
2078          * @param {DragDrop} oDD the drag and drop object to get the
2079          *                       location for
2080          * @return {Roo.lib.Region} a Region object representing the total area
2081          *                             the element occupies, including any padding
2082          *                             the instance is configured for.
2083          * @static
2084          */
2085         getLocation: function(oDD) {
2086             if (! this.isTypeOfDD(oDD)) {
2087                 return null;
2088             }
2089
2090             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2091
2092             try {
2093                 pos= Roo.lib.Dom.getXY(el);
2094             } catch (e) { }
2095
2096             if (!pos) {
2097                 return null;
2098             }
2099
2100             x1 = pos[0];
2101             x2 = x1 + el.offsetWidth;
2102             y1 = pos[1];
2103             y2 = y1 + el.offsetHeight;
2104
2105             t = y1 - oDD.padding[0];
2106             r = x2 + oDD.padding[1];
2107             b = y2 + oDD.padding[2];
2108             l = x1 - oDD.padding[3];
2109
2110             return new Roo.lib.Region( t, r, b, l );
2111         },
2112
2113         /**
2114          * Checks the cursor location to see if it over the target
2115          * @method isOverTarget
2116          * @param {Roo.lib.Point} pt The point to evaluate
2117          * @param {DragDrop} oTarget the DragDrop object we are inspecting
2118          * @return {boolean} true if the mouse is over the target
2119          * @private
2120          * @static
2121          */
2122         isOverTarget: function(pt, oTarget, intersect) {
2123             // use cache if available
2124             var loc = this.locationCache[oTarget.id];
2125             if (!loc || !this.useCache) {
2126                 loc = this.getLocation(oTarget);
2127                 this.locationCache[oTarget.id] = loc;
2128
2129             }
2130
2131             if (!loc) {
2132                 return false;
2133             }
2134
2135             oTarget.cursorIsOver = loc.contains( pt );
2136
2137             // DragDrop is using this as a sanity check for the initial mousedown
2138             // in this case we are done.  In POINT mode, if the drag obj has no
2139             // contraints, we are also done. Otherwise we need to evaluate the
2140             // location of the target as related to the actual location of the
2141             // dragged element.
2142             var dc = this.dragCurrent;
2143             if (!dc || !dc.getTargetCoord ||
2144                     (!intersect && !dc.constrainX && !dc.constrainY)) {
2145                 return oTarget.cursorIsOver;
2146             }
2147
2148             oTarget.overlap = null;
2149
2150             // Get the current location of the drag element, this is the
2151             // location of the mouse event less the delta that represents
2152             // where the original mousedown happened on the element.  We
2153             // need to consider constraints and ticks as well.
2154             var pos = dc.getTargetCoord(pt.x, pt.y);
2155
2156             var el = dc.getDragEl();
2157             var curRegion = new Roo.lib.Region( pos.y,
2158                                                    pos.x + el.offsetWidth,
2159                                                    pos.y + el.offsetHeight,
2160                                                    pos.x );
2161
2162             var overlap = curRegion.intersect(loc);
2163
2164             if (overlap) {
2165                 oTarget.overlap = overlap;
2166                 return (intersect) ? true : oTarget.cursorIsOver;
2167             } else {
2168                 return false;
2169             }
2170         },
2171
2172         /**
2173          * unload event handler
2174          * @method _onUnload
2175          * @private
2176          * @static
2177          */
2178         _onUnload: function(e, me) {
2179             Roo.dd.DragDropMgr.unregAll();
2180         },
2181
2182         /**
2183          * Cleans up the drag and drop events and objects.
2184          * @method unregAll
2185          * @private
2186          * @static
2187          */
2188         unregAll: function() {
2189
2190             if (this.dragCurrent) {
2191                 this.stopDrag();
2192                 this.dragCurrent = null;
2193             }
2194
2195             this._execOnAll("unreg", []);
2196
2197             for (i in this.elementCache) {
2198                 delete this.elementCache[i];
2199             }
2200
2201             this.elementCache = {};
2202             this.ids = {};
2203         },
2204
2205         /**
2206          * A cache of DOM elements
2207          * @property elementCache
2208          * @private
2209          * @static
2210          */
2211         elementCache: {},
2212
2213         /**
2214          * Get the wrapper for the DOM element specified
2215          * @method getElWrapper
2216          * @param {String} id the id of the element to get
2217          * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2218          * @private
2219          * @deprecated This wrapper isn't that useful
2220          * @static
2221          */
2222         getElWrapper: function(id) {
2223             var oWrapper = this.elementCache[id];
2224             if (!oWrapper || !oWrapper.el) {
2225                 oWrapper = this.elementCache[id] =
2226                     new this.ElementWrapper(Roo.getDom(id));
2227             }
2228             return oWrapper;
2229         },
2230
2231         /**
2232          * Returns the actual DOM element
2233          * @method getElement
2234          * @param {String} id the id of the elment to get
2235          * @return {Object} The element
2236          * @deprecated use Roo.getDom instead
2237          * @static
2238          */
2239         getElement: function(id) {
2240             return Roo.getDom(id);
2241         },
2242
2243         /**
2244          * Returns the style property for the DOM element (i.e.,
2245          * document.getElById(id).style)
2246          * @method getCss
2247          * @param {String} id the id of the elment to get
2248          * @return {Object} The style property of the element
2249          * @deprecated use Roo.getDom instead
2250          * @static
2251          */
2252         getCss: function(id) {
2253             var el = Roo.getDom(id);
2254             return (el) ? el.style : null;
2255         },
2256
2257         /**
2258          * Inner class for cached elements
2259          * @class DragDropMgr.ElementWrapper
2260          * @for DragDropMgr
2261          * @private
2262          * @deprecated
2263          */
2264         ElementWrapper: function(el) {
2265                 /**
2266                  * The element
2267                  * @property el
2268                  */
2269                 this.el = el || null;
2270                 /**
2271                  * The element id
2272                  * @property id
2273                  */
2274                 this.id = this.el && el.id;
2275                 /**
2276                  * A reference to the style property
2277                  * @property css
2278                  */
2279                 this.css = this.el && el.style;
2280             },
2281
2282         /**
2283          * Returns the X position of an html element
2284          * @method getPosX
2285          * @param el the element for which to get the position
2286          * @return {int} the X coordinate
2287          * @for DragDropMgr
2288          * @deprecated use Roo.lib.Dom.getX instead
2289          * @static
2290          */
2291         getPosX: function(el) {
2292             return Roo.lib.Dom.getX(el);
2293         },
2294
2295         /**
2296          * Returns the Y position of an html element
2297          * @method getPosY
2298          * @param el the element for which to get the position
2299          * @return {int} the Y coordinate
2300          * @deprecated use Roo.lib.Dom.getY instead
2301          * @static
2302          */
2303         getPosY: function(el) {
2304             return Roo.lib.Dom.getY(el);
2305         },
2306
2307         /**
2308          * Swap two nodes.  In IE, we use the native method, for others we
2309          * emulate the IE behavior
2310          * @method swapNode
2311          * @param n1 the first node to swap
2312          * @param n2 the other node to swap
2313          * @static
2314          */
2315         swapNode: function(n1, n2) {
2316             if (n1.swapNode) {
2317                 n1.swapNode(n2);
2318             } else {
2319                 var p = n2.parentNode;
2320                 var s = n2.nextSibling;
2321
2322                 if (s == n1) {
2323                     p.insertBefore(n1, n2);
2324                 } else if (n2 == n1.nextSibling) {
2325                     p.insertBefore(n2, n1);
2326                 } else {
2327                     n1.parentNode.replaceChild(n2, n1);
2328                     p.insertBefore(n1, s);
2329                 }
2330             }
2331         },
2332
2333         /**
2334          * Returns the current scroll position
2335          * @method getScroll
2336          * @private
2337          * @static
2338          */
2339         getScroll: function () {
2340             var t, l, dde=document.documentElement, db=document.body;
2341             if (dde && (dde.scrollTop || dde.scrollLeft)) {
2342                 t = dde.scrollTop;
2343                 l = dde.scrollLeft;
2344             } else if (db) {
2345                 t = db.scrollTop;
2346                 l = db.scrollLeft;
2347             } else {
2348
2349             }
2350             return { top: t, left: l };
2351         },
2352
2353         /**
2354          * Returns the specified element style property
2355          * @method getStyle
2356          * @param {HTMLElement} el          the element
2357          * @param {string}      styleProp   the style property
2358          * @return {string} The value of the style property
2359          * @deprecated use Roo.lib.Dom.getStyle
2360          * @static
2361          */
2362         getStyle: function(el, styleProp) {
2363             return Roo.fly(el).getStyle(styleProp);
2364         },
2365
2366         /**
2367          * Gets the scrollTop
2368          * @method getScrollTop
2369          * @return {int} the document's scrollTop
2370          * @static
2371          */
2372         getScrollTop: function () { return this.getScroll().top; },
2373
2374         /**
2375          * Gets the scrollLeft
2376          * @method getScrollLeft
2377          * @return {int} the document's scrollTop
2378          * @static
2379          */
2380         getScrollLeft: function () { return this.getScroll().left; },
2381
2382         /**
2383          * Sets the x/y position of an element to the location of the
2384          * target element.
2385          * @method moveToEl
2386          * @param {HTMLElement} moveEl      The element to move
2387          * @param {HTMLElement} targetEl    The position reference element
2388          * @static
2389          */
2390         moveToEl: function (moveEl, targetEl) {
2391             var aCoord = Roo.lib.Dom.getXY(targetEl);
2392             Roo.lib.Dom.setXY(moveEl, aCoord);
2393         },
2394
2395         /**
2396          * Numeric array sort function
2397          * @method numericSort
2398          * @static
2399          */
2400         numericSort: function(a, b) { return (a - b); },
2401
2402         /**
2403          * Internal counter
2404          * @property _timeoutCount
2405          * @private
2406          * @static
2407          */
2408         _timeoutCount: 0,
2409
2410         /**
2411          * Trying to make the load order less important.  Without this we get
2412          * an error if this file is loaded before the Event Utility.
2413          * @method _addListeners
2414          * @private
2415          * @static
2416          */
2417         _addListeners: function() {
2418             var DDM = Roo.dd.DDM;
2419             if ( Roo.lib.Event && document ) {
2420                 DDM._onLoad();
2421             } else {
2422                 if (DDM._timeoutCount > 2000) {
2423                 } else {
2424                     setTimeout(DDM._addListeners, 10);
2425                     if (document && document.body) {
2426                         DDM._timeoutCount += 1;
2427                     }
2428                 }
2429             }
2430         },
2431
2432         /**
2433          * Recursively searches the immediate parent and all child nodes for
2434          * the handle element in order to determine wheter or not it was
2435          * clicked.
2436          * @method handleWasClicked
2437          * @param node the html element to inspect
2438          * @static
2439          */
2440         handleWasClicked: function(node, id) {
2441             if (this.isHandle(id, node.id)) {
2442                 return true;
2443             } else {
2444                 // check to see if this is a text node child of the one we want
2445                 var p = node.parentNode;
2446
2447                 while (p) {
2448                     if (this.isHandle(id, p.id)) {
2449                         return true;
2450                     } else {
2451                         p = p.parentNode;
2452                     }
2453                 }
2454             }
2455
2456             return false;
2457         }
2458
2459     };
2460
2461 }();
2462
2463 // shorter alias, save a few bytes
2464 Roo.dd.DDM = Roo.dd.DragDropMgr;
2465 Roo.dd.DDM._addListeners();
2466
2467 }/*
2468  * Based on:
2469  * Ext JS Library 1.1.1
2470  * Copyright(c) 2006-2007, Ext JS, LLC.
2471  *
2472  * Originally Released Under LGPL - original licence link has changed is not relivant.
2473  *
2474  * Fork - LGPL
2475  * <script type="text/javascript">
2476  */
2477
2478 /**
2479  * @class Roo.dd.DD
2480  * A DragDrop implementation where the linked element follows the
2481  * mouse cursor during a drag.
2482  * @extends Roo.dd.DragDrop
2483  * @constructor
2484  * @param {String} id the id of the linked element
2485  * @param {String} sGroup the group of related DragDrop items
2486  * @param {object} config an object containing configurable attributes
2487  *                Valid properties for DD:
2488  *                    scroll
2489  */
2490 Roo.dd.DD = function(id, sGroup, config) {
2491     if (id) {
2492         this.init(id, sGroup, config);
2493     }
2494 };
2495
2496 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2497
2498     /**
2499      * When set to true, the utility automatically tries to scroll the browser
2500      * window wehn a drag and drop element is dragged near the viewport boundary.
2501      * Defaults to true.
2502      * @property scroll
2503      * @type boolean
2504      */
2505     scroll: true,
2506
2507     /**
2508      * Sets the pointer offset to the distance between the linked element's top
2509      * left corner and the location the element was clicked
2510      * @method autoOffset
2511      * @param {int} iPageX the X coordinate of the click
2512      * @param {int} iPageY the Y coordinate of the click
2513      */
2514     autoOffset: function(iPageX, iPageY) {
2515         var x = iPageX - this.startPageX;
2516         var y = iPageY - this.startPageY;
2517         this.setDelta(x, y);
2518     },
2519
2520     /**
2521      * Sets the pointer offset.  You can call this directly to force the
2522      * offset to be in a particular location (e.g., pass in 0,0 to set it
2523      * to the center of the object)
2524      * @method setDelta
2525      * @param {int} iDeltaX the distance from the left
2526      * @param {int} iDeltaY the distance from the top
2527      */
2528     setDelta: function(iDeltaX, iDeltaY) {
2529         this.deltaX = iDeltaX;
2530         this.deltaY = iDeltaY;
2531     },
2532
2533     /**
2534      * Sets the drag element to the location of the mousedown or click event,
2535      * maintaining the cursor location relative to the location on the element
2536      * that was clicked.  Override this if you want to place the element in a
2537      * location other than where the cursor is.
2538      * @method setDragElPos
2539      * @param {int} iPageX the X coordinate of the mousedown or drag event
2540      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2541      */
2542     setDragElPos: function(iPageX, iPageY) {
2543         // the first time we do this, we are going to check to make sure
2544         // the element has css positioning
2545
2546         var el = this.getDragEl();
2547         this.alignElWithMouse(el, iPageX, iPageY);
2548     },
2549
2550     /**
2551      * Sets the element to the location of the mousedown or click event,
2552      * maintaining the cursor location relative to the location on the element
2553      * that was clicked.  Override this if you want to place the element in a
2554      * location other than where the cursor is.
2555      * @method alignElWithMouse
2556      * @param {HTMLElement} el the element to move
2557      * @param {int} iPageX the X coordinate of the mousedown or drag event
2558      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2559      */
2560     alignElWithMouse: function(el, iPageX, iPageY) {
2561         var oCoord = this.getTargetCoord(iPageX, iPageY);
2562         var fly = el.dom ? el : Roo.fly(el);
2563         if (!this.deltaSetXY) {
2564             var aCoord = [oCoord.x, oCoord.y];
2565             fly.setXY(aCoord);
2566             var newLeft = fly.getLeft(true);
2567             var newTop  = fly.getTop(true);
2568             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2569         } else {
2570             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2571         }
2572
2573         this.cachePosition(oCoord.x, oCoord.y);
2574         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2575         return oCoord;
2576     },
2577
2578     /**
2579      * Saves the most recent position so that we can reset the constraints and
2580      * tick marks on-demand.  We need to know this so that we can calculate the
2581      * number of pixels the element is offset from its original position.
2582      * @method cachePosition
2583      * @param iPageX the current x position (optional, this just makes it so we
2584      * don't have to look it up again)
2585      * @param iPageY the current y position (optional, this just makes it so we
2586      * don't have to look it up again)
2587      */
2588     cachePosition: function(iPageX, iPageY) {
2589         if (iPageX) {
2590             this.lastPageX = iPageX;
2591             this.lastPageY = iPageY;
2592         } else {
2593             var aCoord = Roo.lib.Dom.getXY(this.getEl());
2594             this.lastPageX = aCoord[0];
2595             this.lastPageY = aCoord[1];
2596         }
2597     },
2598
2599     /**
2600      * Auto-scroll the window if the dragged object has been moved beyond the
2601      * visible window boundary.
2602      * @method autoScroll
2603      * @param {int} x the drag element's x position
2604      * @param {int} y the drag element's y position
2605      * @param {int} h the height of the drag element
2606      * @param {int} w the width of the drag element
2607      * @private
2608      */
2609     autoScroll: function(x, y, h, w) {
2610
2611         if (this.scroll) {
2612             // The client height
2613             var clientH = Roo.lib.Dom.getViewWidth();
2614
2615             // The client width
2616             var clientW = Roo.lib.Dom.getViewHeight();
2617
2618             // The amt scrolled down
2619             var st = this.DDM.getScrollTop();
2620
2621             // The amt scrolled right
2622             var sl = this.DDM.getScrollLeft();
2623
2624             // Location of the bottom of the element
2625             var bot = h + y;
2626
2627             // Location of the right of the element
2628             var right = w + x;
2629
2630             // The distance from the cursor to the bottom of the visible area,
2631             // adjusted so that we don't scroll if the cursor is beyond the
2632             // element drag constraints
2633             var toBot = (clientH + st - y - this.deltaY);
2634
2635             // The distance from the cursor to the right of the visible area
2636             var toRight = (clientW + sl - x - this.deltaX);
2637
2638
2639             // How close to the edge the cursor must be before we scroll
2640             // var thresh = (document.all) ? 100 : 40;
2641             var thresh = 40;
2642
2643             // How many pixels to scroll per autoscroll op.  This helps to reduce
2644             // clunky scrolling. IE is more sensitive about this ... it needs this
2645             // value to be higher.
2646             var scrAmt = (document.all) ? 80 : 30;
2647
2648             // Scroll down if we are near the bottom of the visible page and the
2649             // obj extends below the crease
2650             if ( bot > clientH && toBot < thresh ) {
2651                 window.scrollTo(sl, st + scrAmt);
2652             }
2653
2654             // Scroll up if the window is scrolled down and the top of the object
2655             // goes above the top border
2656             if ( y < st && st > 0 && y - st < thresh ) {
2657                 window.scrollTo(sl, st - scrAmt);
2658             }
2659
2660             // Scroll right if the obj is beyond the right border and the cursor is
2661             // near the border.
2662             if ( right > clientW && toRight < thresh ) {
2663                 window.scrollTo(sl + scrAmt, st);
2664             }
2665
2666             // Scroll left if the window has been scrolled to the right and the obj
2667             // extends past the left border
2668             if ( x < sl && sl > 0 && x - sl < thresh ) {
2669                 window.scrollTo(sl - scrAmt, st);
2670             }
2671         }
2672     },
2673
2674     /**
2675      * Finds the location the element should be placed if we want to move
2676      * it to where the mouse location less the click offset would place us.
2677      * @method getTargetCoord
2678      * @param {int} iPageX the X coordinate of the click
2679      * @param {int} iPageY the Y coordinate of the click
2680      * @return an object that contains the coordinates (Object.x and Object.y)
2681      * @private
2682      */
2683     getTargetCoord: function(iPageX, iPageY) {
2684
2685
2686         var x = iPageX - this.deltaX;
2687         var y = iPageY - this.deltaY;
2688
2689         if (this.constrainX) {
2690             if (x < this.minX) { x = this.minX; }
2691             if (x > this.maxX) { x = this.maxX; }
2692         }
2693
2694         if (this.constrainY) {
2695             if (y < this.minY) { y = this.minY; }
2696             if (y > this.maxY) { y = this.maxY; }
2697         }
2698
2699         x = this.getTick(x, this.xTicks);
2700         y = this.getTick(y, this.yTicks);
2701
2702
2703         return {x:x, y:y};
2704     },
2705
2706     /*
2707      * Sets up config options specific to this class. Overrides
2708      * Roo.dd.DragDrop, but all versions of this method through the
2709      * inheritance chain are called
2710      */
2711     applyConfig: function() {
2712         Roo.dd.DD.superclass.applyConfig.call(this);
2713         this.scroll = (this.config.scroll !== false);
2714     },
2715
2716     /*
2717      * Event that fires prior to the onMouseDown event.  Overrides
2718      * Roo.dd.DragDrop.
2719      */
2720     b4MouseDown: function(e) {
2721         // this.resetConstraints();
2722         this.autoOffset(e.getPageX(),
2723                             e.getPageY());
2724     },
2725
2726     /*
2727      * Event that fires prior to the onDrag event.  Overrides
2728      * Roo.dd.DragDrop.
2729      */
2730     b4Drag: function(e) {
2731         this.setDragElPos(e.getPageX(),
2732                             e.getPageY());
2733     },
2734
2735     toString: function() {
2736         return ("DD " + this.id);
2737     }
2738
2739     //////////////////////////////////////////////////////////////////////////
2740     // Debugging ygDragDrop events that can be overridden
2741     //////////////////////////////////////////////////////////////////////////
2742     /*
2743     startDrag: function(x, y) {
2744     },
2745
2746     onDrag: function(e) {
2747     },
2748
2749     onDragEnter: function(e, id) {
2750     },
2751
2752     onDragOver: function(e, id) {
2753     },
2754
2755     onDragOut: function(e, id) {
2756     },
2757
2758     onDragDrop: function(e, id) {
2759     },
2760
2761     endDrag: function(e) {
2762     }
2763
2764     */
2765
2766 });/*
2767  * Based on:
2768  * Ext JS Library 1.1.1
2769  * Copyright(c) 2006-2007, Ext JS, LLC.
2770  *
2771  * Originally Released Under LGPL - original licence link has changed is not relivant.
2772  *
2773  * Fork - LGPL
2774  * <script type="text/javascript">
2775  */
2776
2777 /**
2778  * @class Roo.dd.DDProxy
2779  * A DragDrop implementation that inserts an empty, bordered div into
2780  * the document that follows the cursor during drag operations.  At the time of
2781  * the click, the frame div is resized to the dimensions of the linked html
2782  * element, and moved to the exact location of the linked element.
2783  *
2784  * References to the "frame" element refer to the single proxy element that
2785  * was created to be dragged in place of all DDProxy elements on the
2786  * page.
2787  *
2788  * @extends Roo.dd.DD
2789  * @constructor
2790  * @param {String} id the id of the linked html element
2791  * @param {String} sGroup the group of related DragDrop objects
2792  * @param {object} config an object containing configurable attributes
2793  *                Valid properties for DDProxy in addition to those in DragDrop:
2794  *                   resizeFrame, centerFrame, dragElId
2795  */
2796 Roo.dd.DDProxy = function(id, sGroup, config) {
2797     if (id) {
2798         this.init(id, sGroup, config);
2799         this.initFrame();
2800     }
2801 };
2802
2803 /**
2804  * The default drag frame div id
2805  * @property Roo.dd.DDProxy.dragElId
2806  * @type String
2807  * @static
2808  */
2809 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2810
2811 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2812
2813     /**
2814      * By default we resize the drag frame to be the same size as the element
2815      * we want to drag (this is to get the frame effect).  We can turn it off
2816      * if we want a different behavior.
2817      * @property resizeFrame
2818      * @type boolean
2819      */
2820     resizeFrame: true,
2821
2822     /**
2823      * By default the frame is positioned exactly where the drag element is, so
2824      * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
2825      * you do not have constraints on the obj is to have the drag frame centered
2826      * around the cursor.  Set centerFrame to true for this effect.
2827      * @property centerFrame
2828      * @type boolean
2829      */
2830     centerFrame: false,
2831
2832     /**
2833      * Creates the proxy element if it does not yet exist
2834      * @method createFrame
2835      */
2836     createFrame: function() {
2837         var self = this;
2838         var body = document.body;
2839
2840         if (!body || !body.firstChild) {
2841             setTimeout( function() { self.createFrame(); }, 50 );
2842             return;
2843         }
2844
2845         var div = this.getDragEl();
2846
2847         if (!div) {
2848             div    = document.createElement("div");
2849             div.id = this.dragElId;
2850             var s  = div.style;
2851
2852             s.position   = "absolute";
2853             s.visibility = "hidden";
2854             s.cursor     = "move";
2855             s.border     = "2px solid #aaa";
2856             s.zIndex     = 999;
2857
2858             // appendChild can blow up IE if invoked prior to the window load event
2859             // while rendering a table.  It is possible there are other scenarios
2860             // that would cause this to happen as well.
2861             body.insertBefore(div, body.firstChild);
2862         }
2863     },
2864
2865     /**
2866      * Initialization for the drag frame element.  Must be called in the
2867      * constructor of all subclasses
2868      * @method initFrame
2869      */
2870     initFrame: function() {
2871         this.createFrame();
2872     },
2873
2874     applyConfig: function() {
2875         Roo.dd.DDProxy.superclass.applyConfig.call(this);
2876
2877         this.resizeFrame = (this.config.resizeFrame !== false);
2878         this.centerFrame = (this.config.centerFrame);
2879         this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2880     },
2881
2882     /**
2883      * Resizes the drag frame to the dimensions of the clicked object, positions
2884      * it over the object, and finally displays it
2885      * @method showFrame
2886      * @param {int} iPageX X click position
2887      * @param {int} iPageY Y click position
2888      * @private
2889      */
2890     showFrame: function(iPageX, iPageY) {
2891         var el = this.getEl();
2892         var dragEl = this.getDragEl();
2893         var s = dragEl.style;
2894
2895         this._resizeProxy();
2896
2897         if (this.centerFrame) {
2898             this.setDelta( Math.round(parseInt(s.width,  10)/2),
2899                            Math.round(parseInt(s.height, 10)/2) );
2900         }
2901
2902         this.setDragElPos(iPageX, iPageY);
2903
2904         Roo.fly(dragEl).show();
2905     },
2906
2907     /**
2908      * The proxy is automatically resized to the dimensions of the linked
2909      * element when a drag is initiated, unless resizeFrame is set to false
2910      * @method _resizeProxy
2911      * @private
2912      */
2913     _resizeProxy: function() {
2914         if (this.resizeFrame) {
2915             var el = this.getEl();
2916             Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2917         }
2918     },
2919
2920     // overrides Roo.dd.DragDrop
2921     b4MouseDown: function(e) {
2922         var x = e.getPageX();
2923         var y = e.getPageY();
2924         this.autoOffset(x, y);
2925         this.setDragElPos(x, y);
2926     },
2927
2928     // overrides Roo.dd.DragDrop
2929     b4StartDrag: function(x, y) {
2930         // show the drag frame
2931         this.showFrame(x, y);
2932     },
2933
2934     // overrides Roo.dd.DragDrop
2935     b4EndDrag: function(e) {
2936         Roo.fly(this.getDragEl()).hide();
2937     },
2938
2939     // overrides Roo.dd.DragDrop
2940     // By default we try to move the element to the last location of the frame.
2941     // This is so that the default behavior mirrors that of Roo.dd.DD.
2942     endDrag: function(e) {
2943
2944         var lel = this.getEl();
2945         var del = this.getDragEl();
2946
2947         // Show the drag frame briefly so we can get its position
2948         del.style.visibility = "";
2949
2950         this.beforeMove();
2951         // Hide the linked element before the move to get around a Safari
2952         // rendering bug.
2953         lel.style.visibility = "hidden";
2954         Roo.dd.DDM.moveToEl(lel, del);
2955         del.style.visibility = "hidden";
2956         lel.style.visibility = "";
2957
2958         this.afterDrag();
2959     },
2960
2961     beforeMove : function(){
2962
2963     },
2964
2965     afterDrag : function(){
2966
2967     },
2968
2969     toString: function() {
2970         return ("DDProxy " + this.id);
2971     }
2972
2973 });
2974 /*
2975  * Based on:
2976  * Ext JS Library 1.1.1
2977  * Copyright(c) 2006-2007, Ext JS, LLC.
2978  *
2979  * Originally Released Under LGPL - original licence link has changed is not relivant.
2980  *
2981  * Fork - LGPL
2982  * <script type="text/javascript">
2983  */
2984
2985  /**
2986  * @class Roo.dd.DDTarget
2987  * A DragDrop implementation that does not move, but can be a drop
2988  * target.  You would get the same result by simply omitting implementation
2989  * for the event callbacks, but this way we reduce the processing cost of the
2990  * event listener and the callbacks.
2991  * @extends Roo.dd.DragDrop
2992  * @constructor
2993  * @param {String} id the id of the element that is a drop target
2994  * @param {String} sGroup the group of related DragDrop objects
2995  * @param {object} config an object containing configurable attributes
2996  *                 Valid properties for DDTarget in addition to those in
2997  *                 DragDrop:
2998  *                    none
2999  */
3000 Roo.dd.DDTarget = function(id, sGroup, config) {
3001     if (id) {
3002         this.initTarget(id, sGroup, config);
3003     }
3004     if (config.listeners || config.events) { 
3005        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
3006             listeners : config.listeners || {}, 
3007             events : config.events || {} 
3008         });    
3009     }
3010 };
3011
3012 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3013 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3014     toString: function() {
3015         return ("DDTarget " + this.id);
3016     }
3017 });
3018 /*
3019  * Based on:
3020  * Ext JS Library 1.1.1
3021  * Copyright(c) 2006-2007, Ext JS, LLC.
3022  *
3023  * Originally Released Under LGPL - original licence link has changed is not relivant.
3024  *
3025  * Fork - LGPL
3026  * <script type="text/javascript">
3027  */
3028  
3029
3030 /**
3031  * @class Roo.dd.ScrollManager
3032  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3033  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3034  * @singleton
3035  */
3036 Roo.dd.ScrollManager = function(){
3037     var ddm = Roo.dd.DragDropMgr;
3038     var els = {};
3039     var dragEl = null;
3040     var proc = {};
3041     
3042     var onStop = function(e){
3043         dragEl = null;
3044         clearProc();
3045     };
3046     
3047     var triggerRefresh = function(){
3048         if(ddm.dragCurrent){
3049              ddm.refreshCache(ddm.dragCurrent.groups);
3050         }
3051     };
3052     
3053     var doScroll = function(){
3054         if(ddm.dragCurrent){
3055             var dds = Roo.dd.ScrollManager;
3056             if(!dds.animate){
3057                 if(proc.el.scroll(proc.dir, dds.increment)){
3058                     triggerRefresh();
3059                 }
3060             }else{
3061                 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3062             }
3063         }
3064     };
3065     
3066     var clearProc = function(){
3067         if(proc.id){
3068             clearInterval(proc.id);
3069         }
3070         proc.id = 0;
3071         proc.el = null;
3072         proc.dir = "";
3073     };
3074     
3075     var startProc = function(el, dir){
3076         clearProc();
3077         proc.el = el;
3078         proc.dir = dir;
3079         proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3080     };
3081     
3082     var onFire = function(e, isDrop){
3083         if(isDrop || !ddm.dragCurrent){ return; }
3084         var dds = Roo.dd.ScrollManager;
3085         if(!dragEl || dragEl != ddm.dragCurrent){
3086             dragEl = ddm.dragCurrent;
3087             // refresh regions on drag start
3088             dds.refreshCache();
3089         }
3090         
3091         var xy = Roo.lib.Event.getXY(e);
3092         var pt = new Roo.lib.Point(xy[0], xy[1]);
3093         for(var id in els){
3094             var el = els[id], r = el._region;
3095             if(r && r.contains(pt) && el.isScrollable()){
3096                 if(r.bottom - pt.y <= dds.thresh){
3097                     if(proc.el != el){
3098                         startProc(el, "down");
3099                     }
3100                     return;
3101                 }else if(r.right - pt.x <= dds.thresh){
3102                     if(proc.el != el){
3103                         startProc(el, "left");
3104                     }
3105                     return;
3106                 }else if(pt.y - r.top <= dds.thresh){
3107                     if(proc.el != el){
3108                         startProc(el, "up");
3109                     }
3110                     return;
3111                 }else if(pt.x - r.left <= dds.thresh){
3112                     if(proc.el != el){
3113                         startProc(el, "right");
3114                     }
3115                     return;
3116                 }
3117             }
3118         }
3119         clearProc();
3120     };
3121     
3122     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3123     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3124     
3125     return {
3126         /**
3127          * Registers new overflow element(s) to auto scroll
3128          * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129          */
3130         register : function(el){
3131             if(el instanceof Array){
3132                 for(var i = 0, len = el.length; i < len; i++) {
3133                         this.register(el[i]);
3134                 }
3135             }else{
3136                 el = Roo.get(el);
3137                 els[el.id] = el;
3138             }
3139         },
3140         
3141         /**
3142          * Unregisters overflow element(s) so they are no longer scrolled
3143          * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144          */
3145         unregister : function(el){
3146             if(el instanceof Array){
3147                 for(var i = 0, len = el.length; i < len; i++) {
3148                         this.unregister(el[i]);
3149                 }
3150             }else{
3151                 el = Roo.get(el);
3152                 delete els[el.id];
3153             }
3154         },
3155         
3156         /**
3157          * The number of pixels from the edge of a container the pointer needs to be to 
3158          * trigger scrolling (defaults to 25)
3159          * @type Number
3160          */
3161         thresh : 25,
3162         
3163         /**
3164          * The number of pixels to scroll in each scroll increment (defaults to 50)
3165          * @type Number
3166          */
3167         increment : 100,
3168         
3169         /**
3170          * The frequency of scrolls in milliseconds (defaults to 500)
3171          * @type Number
3172          */
3173         frequency : 500,
3174         
3175         /**
3176          * True to animate the scroll (defaults to true)
3177          * @type Boolean
3178          */
3179         animate: true,
3180         
3181         /**
3182          * The animation duration in seconds - 
3183          * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3184          * @type Number
3185          */
3186         animDuration: .4,
3187         
3188         /**
3189          * Manually trigger a cache refresh.
3190          */
3191         refreshCache : function(){
3192             for(var id in els){
3193                 if(typeof els[id] == 'object'){ // for people extending the object prototype
3194                     els[id]._region = els[id].getRegion();
3195                 }
3196             }
3197         }
3198     };
3199 }();/*
3200  * Based on:
3201  * Ext JS Library 1.1.1
3202  * Copyright(c) 2006-2007, Ext JS, LLC.
3203  *
3204  * Originally Released Under LGPL - original licence link has changed is not relivant.
3205  *
3206  * Fork - LGPL
3207  * <script type="text/javascript">
3208  */
3209  
3210
3211 /**
3212  * @class Roo.dd.Registry
3213  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
3214  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3215  * @singleton
3216  */
3217 Roo.dd.Registry = function(){
3218     var elements = {}; 
3219     var handles = {}; 
3220     var autoIdSeed = 0;
3221
3222     var getId = function(el, autogen){
3223         if(typeof el == "string"){
3224             return el;
3225         }
3226         var id = el.id;
3227         if(!id && autogen !== false){
3228             id = "roodd-" + (++autoIdSeed);
3229             el.id = id;
3230         }
3231         return id;
3232     };
3233     
3234     return {
3235     /**
3236      * Register a drag drop element
3237      * @param {String|HTMLElement} element The id or DOM node to register
3238      * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3239      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
3240      * knows how to interpret, plus there are some specific properties known to the Registry that should be
3241      * populated in the data object (if applicable):
3242      * <pre>
3243 Value      Description<br />
3244 ---------  ------------------------------------------<br />
3245 handles    Array of DOM nodes that trigger dragging<br />
3246            for the element being registered<br />
3247 isHandle   True if the element passed in triggers<br />
3248            dragging itself, else false
3249 </pre>
3250      */
3251         register : function(el, data){
3252             data = data || {};
3253             if(typeof el == "string"){
3254                 el = document.getElementById(el);
3255             }
3256             data.ddel = el;
3257             elements[getId(el)] = data;
3258             if(data.isHandle !== false){
3259                 handles[data.ddel.id] = data;
3260             }
3261             if(data.handles){
3262                 var hs = data.handles;
3263                 for(var i = 0, len = hs.length; i < len; i++){
3264                         handles[getId(hs[i])] = data;
3265                 }
3266             }
3267         },
3268
3269     /**
3270      * Unregister a drag drop element
3271      * @param {String|HTMLElement}  element The id or DOM node to unregister
3272      */
3273         unregister : function(el){
3274             var id = getId(el, false);
3275             var data = elements[id];
3276             if(data){
3277                 delete elements[id];
3278                 if(data.handles){
3279                     var hs = data.handles;
3280                     for(var i = 0, len = hs.length; i < len; i++){
3281                         delete handles[getId(hs[i], false)];
3282                     }
3283                 }
3284             }
3285         },
3286
3287     /**
3288      * Returns the handle registered for a DOM Node by id
3289      * @param {String|HTMLElement} id The DOM node or id to look up
3290      * @return {Object} handle The custom handle data
3291      */
3292         getHandle : function(id){
3293             if(typeof id != "string"){ // must be element?
3294                 id = id.id;
3295             }
3296             return handles[id];
3297         },
3298
3299     /**
3300      * Returns the handle that is registered for the DOM node that is the target of the event
3301      * @param {Event} e The event
3302      * @return {Object} handle The custom handle data
3303      */
3304         getHandleFromEvent : function(e){
3305             var t = Roo.lib.Event.getTarget(e);
3306             return t ? handles[t.id] : null;
3307         },
3308
3309     /**
3310      * Returns a custom data object that is registered for a DOM node by id
3311      * @param {String|HTMLElement} id The DOM node or id to look up
3312      * @return {Object} data The custom data
3313      */
3314         getTarget : function(id){
3315             if(typeof id != "string"){ // must be element?
3316                 id = id.id;
3317             }
3318             return elements[id];
3319         },
3320
3321     /**
3322      * Returns a custom data object that is registered for the DOM node that is the target of the event
3323      * @param {Event} e The event
3324      * @return {Object} data The custom data
3325      */
3326         getTargetFromEvent : function(e){
3327             var t = Roo.lib.Event.getTarget(e);
3328             return t ? elements[t.id] || handles[t.id] : null;
3329         }
3330     };
3331 }();/*
3332  * Based on:
3333  * Ext JS Library 1.1.1
3334  * Copyright(c) 2006-2007, Ext JS, LLC.
3335  *
3336  * Originally Released Under LGPL - original licence link has changed is not relivant.
3337  *
3338  * Fork - LGPL
3339  * <script type="text/javascript">
3340  */
3341  
3342
3343 /**
3344  * @class Roo.dd.StatusProxy
3345  * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
3346  * default drag proxy used by all Roo.dd components.
3347  * @constructor
3348  * @param {Object} config
3349  */
3350 Roo.dd.StatusProxy = function(config){
3351     Roo.apply(this, config);
3352     this.id = this.id || Roo.id();
3353     this.el = new Roo.Layer({
3354         dh: {
3355             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3356                 {tag: "div", cls: "x-dd-drop-icon"},
3357                 {tag: "div", cls: "x-dd-drag-ghost"}
3358             ]
3359         }, 
3360         shadow: !config || config.shadow !== false
3361     });
3362     this.ghost = Roo.get(this.el.dom.childNodes[1]);
3363     this.dropStatus = this.dropNotAllowed;
3364 };
3365
3366 Roo.dd.StatusProxy.prototype = {
3367     /**
3368      * @cfg {String} dropAllowed
3369      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370      */
3371     dropAllowed : "x-dd-drop-ok",
3372     /**
3373      * @cfg {String} dropNotAllowed
3374      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375      */
3376     dropNotAllowed : "x-dd-drop-nodrop",
3377
3378     /**
3379      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3380      * over the current target element.
3381      * @param {String} cssClass The css class for the new drop status indicator image
3382      */
3383     setStatus : function(cssClass){
3384         cssClass = cssClass || this.dropNotAllowed;
3385         if(this.dropStatus != cssClass){
3386             this.el.replaceClass(this.dropStatus, cssClass);
3387             this.dropStatus = cssClass;
3388         }
3389     },
3390
3391     /**
3392      * Resets the status indicator to the default dropNotAllowed value
3393      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394      */
3395     reset : function(clearGhost){
3396         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3397         this.dropStatus = this.dropNotAllowed;
3398         if(clearGhost){
3399             this.ghost.update("");
3400         }
3401     },
3402
3403     /**
3404      * Updates the contents of the ghost element
3405      * @param {String} html The html that will replace the current innerHTML of the ghost element
3406      */
3407     update : function(html){
3408         if(typeof html == "string"){
3409             this.ghost.update(html);
3410         }else{
3411             this.ghost.update("");
3412             html.style.margin = "0";
3413             this.ghost.dom.appendChild(html);
3414         }
3415         // ensure float = none set?? cant remember why though.
3416         var el = this.ghost.dom.firstChild;
3417                 if(el){
3418                         Roo.fly(el).setStyle('float', 'none');
3419                 }
3420     },
3421     
3422     /**
3423      * Returns the underlying proxy {@link Roo.Layer}
3424      * @return {Roo.Layer} el
3425     */
3426     getEl : function(){
3427         return this.el;
3428     },
3429
3430     /**
3431      * Returns the ghost element
3432      * @return {Roo.Element} el
3433      */
3434     getGhost : function(){
3435         return this.ghost;
3436     },
3437
3438     /**
3439      * Hides the proxy
3440      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441      */
3442     hide : function(clear){
3443         this.el.hide();
3444         if(clear){
3445             this.reset(true);
3446         }
3447     },
3448
3449     /**
3450      * Stops the repair animation if it's currently running
3451      */
3452     stop : function(){
3453         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3454             this.anim.stop();
3455         }
3456     },
3457
3458     /**
3459      * Displays this proxy
3460      */
3461     show : function(){
3462         this.el.show();
3463     },
3464
3465     /**
3466      * Force the Layer to sync its shadow and shim positions to the element
3467      */
3468     sync : function(){
3469         this.el.sync();
3470     },
3471
3472     /**
3473      * Causes the proxy to return to its position of origin via an animation.  Should be called after an
3474      * invalid drop operation by the item being dragged.
3475      * @param {Array} xy The XY position of the element ([x, y])
3476      * @param {Function} callback The function to call after the repair is complete
3477      * @param {Object} scope The scope in which to execute the callback
3478      */
3479     repair : function(xy, callback, scope){
3480         this.callback = callback;
3481         this.scope = scope;
3482         if(xy && this.animRepair !== false){
3483             this.el.addClass("x-dd-drag-repair");
3484             this.el.hideUnders(true);
3485             this.anim = this.el.shift({
3486                 duration: this.repairDuration || .5,
3487                 easing: 'easeOut',
3488                 xy: xy,
3489                 stopFx: true,
3490                 callback: this.afterRepair,
3491                 scope: this
3492             });
3493         }else{
3494             this.afterRepair();
3495         }
3496     },
3497
3498     // private
3499     afterRepair : function(){
3500         this.hide(true);
3501         if(typeof this.callback == "function"){
3502             this.callback.call(this.scope || this);
3503         }
3504         this.callback = null;
3505         this.scope = null;
3506     }
3507 };/*
3508  * Based on:
3509  * Ext JS Library 1.1.1
3510  * Copyright(c) 2006-2007, Ext JS, LLC.
3511  *
3512  * Originally Released Under LGPL - original licence link has changed is not relivant.
3513  *
3514  * Fork - LGPL
3515  * <script type="text/javascript">
3516  */
3517
3518 /**
3519  * @class Roo.dd.DragSource
3520  * @extends Roo.dd.DDProxy
3521  * A simple class that provides the basic implementation needed to make any element draggable.
3522  * @constructor
3523  * @param {String/HTMLElement/Element} el The container element
3524  * @param {Object} config
3525  */
3526 Roo.dd.DragSource = function(el, config){
3527     this.el = Roo.get(el);
3528     this.dragData = {};
3529     
3530     Roo.apply(this, config);
3531     
3532     if(!this.proxy){
3533         this.proxy = new Roo.dd.StatusProxy();
3534     }
3535
3536     Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3537           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538     
3539     this.dragging = false;
3540 };
3541
3542 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543     /**
3544      * @cfg {String} dropAllowed
3545      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546      */
3547     dropAllowed : "x-dd-drop-ok",
3548     /**
3549      * @cfg {String} dropNotAllowed
3550      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551      */
3552     dropNotAllowed : "x-dd-drop-nodrop",
3553
3554     /**
3555      * Returns the data object associated with this drag source
3556      * @return {Object} data An object containing arbitrary data
3557      */
3558     getDragData : function(e){
3559         return this.dragData;
3560     },
3561
3562     // private
3563     onDragEnter : function(e, id){
3564         var target = Roo.dd.DragDropMgr.getDDById(id);
3565         this.cachedTarget = target;
3566         if(this.beforeDragEnter(target, e, id) !== false){
3567             if(target.isNotifyTarget){
3568                 var status = target.notifyEnter(this, e, this.dragData);
3569                 this.proxy.setStatus(status);
3570             }else{
3571                 this.proxy.setStatus(this.dropAllowed);
3572             }
3573             
3574             if(this.afterDragEnter){
3575                 /**
3576                  * An empty function by default, but provided so that you can perform a custom action
3577                  * when the dragged item enters the drop target by providing an implementation.
3578                  * @param {Roo.dd.DragDrop} target The drop target
3579                  * @param {Event} e The event object
3580                  * @param {String} id The id of the dragged element
3581                  * @method afterDragEnter
3582                  */
3583                 this.afterDragEnter(target, e, id);
3584             }
3585         }
3586     },
3587
3588     /**
3589      * An empty function by default, but provided so that you can perform a custom action
3590      * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3591      * @param {Roo.dd.DragDrop} target The drop target
3592      * @param {Event} e The event object
3593      * @param {String} id The id of the dragged element
3594      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595      */
3596     beforeDragEnter : function(target, e, id){
3597         return true;
3598     },
3599
3600     // private
3601     alignElWithMouse: function() {
3602         Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3603         this.proxy.sync();
3604     },
3605
3606     // private
3607     onDragOver : function(e, id){
3608         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3609         if(this.beforeDragOver(target, e, id) !== false){
3610             if(target.isNotifyTarget){
3611                 var status = target.notifyOver(this, e, this.dragData);
3612                 this.proxy.setStatus(status);
3613             }
3614
3615             if(this.afterDragOver){
3616                 /**
3617                  * An empty function by default, but provided so that you can perform a custom action
3618                  * while the dragged item is over the drop target by providing an implementation.
3619                  * @param {Roo.dd.DragDrop} target The drop target
3620                  * @param {Event} e The event object
3621                  * @param {String} id The id of the dragged element
3622                  * @method afterDragOver
3623                  */
3624                 this.afterDragOver(target, e, id);
3625             }
3626         }
3627     },
3628
3629     /**
3630      * An empty function by default, but provided so that you can perform a custom action
3631      * while the dragged item is over the drop target and optionally cancel the onDragOver.
3632      * @param {Roo.dd.DragDrop} target The drop target
3633      * @param {Event} e The event object
3634      * @param {String} id The id of the dragged element
3635      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636      */
3637     beforeDragOver : function(target, e, id){
3638         return true;
3639     },
3640
3641     // private
3642     onDragOut : function(e, id){
3643         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3644         if(this.beforeDragOut(target, e, id) !== false){
3645             if(target.isNotifyTarget){
3646                 target.notifyOut(this, e, this.dragData);
3647             }
3648             this.proxy.reset();
3649             if(this.afterDragOut){
3650                 /**
3651                  * An empty function by default, but provided so that you can perform a custom action
3652                  * after the dragged item is dragged out of the target without dropping.
3653                  * @param {Roo.dd.DragDrop} target The drop target
3654                  * @param {Event} e The event object
3655                  * @param {String} id The id of the dragged element
3656                  * @method afterDragOut
3657                  */
3658                 this.afterDragOut(target, e, id);
3659             }
3660         }
3661         this.cachedTarget = null;
3662     },
3663
3664     /**
3665      * An empty function by default, but provided so that you can perform a custom action before the dragged
3666      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3667      * @param {Roo.dd.DragDrop} target The drop target
3668      * @param {Event} e The event object
3669      * @param {String} id The id of the dragged element
3670      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671      */
3672     beforeDragOut : function(target, e, id){
3673         return true;
3674     },
3675     
3676     // private
3677     onDragDrop : function(e, id){
3678         var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3679         if(this.beforeDragDrop(target, e, id) !== false){
3680             if(target.isNotifyTarget){
3681                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3682                     this.onValidDrop(target, e, id);
3683                 }else{
3684                     this.onInvalidDrop(target, e, id);
3685                 }
3686             }else{
3687                 this.onValidDrop(target, e, id);
3688             }
3689             
3690             if(this.afterDragDrop){
3691                 /**
3692                  * An empty function by default, but provided so that you can perform a custom action
3693                  * after a valid drag drop has occurred by providing an implementation.
3694                  * @param {Roo.dd.DragDrop} target The drop target
3695                  * @param {Event} e The event object
3696                  * @param {String} id The id of the dropped element
3697                  * @method afterDragDrop
3698                  */
3699                 this.afterDragDrop(target, e, id);
3700             }
3701         }
3702         delete this.cachedTarget;
3703     },
3704
3705     /**
3706      * An empty function by default, but provided so that you can perform a custom action before the dragged
3707      * item is dropped onto the target and optionally cancel the onDragDrop.
3708      * @param {Roo.dd.DragDrop} target The drop target
3709      * @param {Event} e The event object
3710      * @param {String} id The id of the dragged element
3711      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712      */
3713     beforeDragDrop : function(target, e, id){
3714         return true;
3715     },
3716
3717     // private
3718     onValidDrop : function(target, e, id){
3719         this.hideProxy();
3720         if(this.afterValidDrop){
3721             /**
3722              * An empty function by default, but provided so that you can perform a custom action
3723              * after a valid drop has occurred by providing an implementation.
3724              * @param {Object} target The target DD 
3725              * @param {Event} e The event object
3726              * @param {String} id The id of the dropped element
3727              * @method afterInvalidDrop
3728              */
3729             this.afterValidDrop(target, e, id);
3730         }
3731     },
3732
3733     // private
3734     getRepairXY : function(e, data){
3735         return this.el.getXY();  
3736     },
3737
3738     // private
3739     onInvalidDrop : function(target, e, id){
3740         this.beforeInvalidDrop(target, e, id);
3741         if(this.cachedTarget){
3742             if(this.cachedTarget.isNotifyTarget){
3743                 this.cachedTarget.notifyOut(this, e, this.dragData);
3744             }
3745             this.cacheTarget = null;
3746         }
3747         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748
3749         if(this.afterInvalidDrop){
3750             /**
3751              * An empty function by default, but provided so that you can perform a custom action
3752              * after an invalid drop has occurred by providing an implementation.
3753              * @param {Event} e The event object
3754              * @param {String} id The id of the dropped element
3755              * @method afterInvalidDrop
3756              */
3757             this.afterInvalidDrop(e, id);
3758         }
3759     },
3760
3761     // private
3762     afterRepair : function(){
3763         if(Roo.enableFx){
3764             this.el.highlight(this.hlColor || "c3daf9");
3765         }
3766         this.dragging = false;
3767     },
3768
3769     /**
3770      * An empty function by default, but provided so that you can perform a custom action after an invalid
3771      * drop has occurred.
3772      * @param {Roo.dd.DragDrop} target The drop target
3773      * @param {Event} e The event object
3774      * @param {String} id The id of the dragged element
3775      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776      */
3777     beforeInvalidDrop : function(target, e, id){
3778         return true;
3779     },
3780
3781     // private
3782     handleMouseDown : function(e){
3783         if(this.dragging) {
3784             return;
3785         }
3786         var data = this.getDragData(e);
3787         if(data && this.onBeforeDrag(data, e) !== false){
3788             this.dragData = data;
3789             this.proxy.stop();
3790             Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3791         } 
3792     },
3793
3794     /**
3795      * An empty function by default, but provided so that you can perform a custom action before the initial
3796      * drag event begins and optionally cancel it.
3797      * @param {Object} data An object containing arbitrary data to be shared with drop targets
3798      * @param {Event} e The event object
3799      * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800      */
3801     onBeforeDrag : function(data, e){
3802         return true;
3803     },
3804
3805     /**
3806      * An empty function by default, but provided so that you can perform a custom action once the initial
3807      * drag event has begun.  The drag cannot be canceled from this function.
3808      * @param {Number} x The x position of the click on the dragged object
3809      * @param {Number} y The y position of the click on the dragged object
3810      */
3811     onStartDrag : Roo.emptyFn,
3812
3813     // private - YUI override
3814     startDrag : function(x, y){
3815         this.proxy.reset();
3816         this.dragging = true;
3817         this.proxy.update("");
3818         this.onInitDrag(x, y);
3819         this.proxy.show();
3820     },
3821
3822     // private
3823     onInitDrag : function(x, y){
3824         var clone = this.el.dom.cloneNode(true);
3825         clone.id = Roo.id(); // prevent duplicate ids
3826         this.proxy.update(clone);
3827         this.onStartDrag(x, y);
3828         return true;
3829     },
3830
3831     /**
3832      * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3833      * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834      */
3835     getProxy : function(){
3836         return this.proxy;  
3837     },
3838
3839     /**
3840      * Hides the drag source's {@link Roo.dd.StatusProxy}
3841      */
3842     hideProxy : function(){
3843         this.proxy.hide();  
3844         this.proxy.reset(true);
3845         this.dragging = false;
3846     },
3847
3848     // private
3849     triggerCacheRefresh : function(){
3850         Roo.dd.DDM.refreshCache(this.groups);
3851     },
3852
3853     // private - override to prevent hiding
3854     b4EndDrag: function(e) {
3855     },
3856
3857     // private - override to prevent moving
3858     endDrag : function(e){
3859         this.onEndDrag(this.dragData, e);
3860     },
3861
3862     // private
3863     onEndDrag : function(data, e){
3864     },
3865     
3866     // private - pin to cursor
3867     autoOffset : function(x, y) {
3868         this.setDelta(-12, -20);
3869     }    
3870 });/*
3871  * Based on:
3872  * Ext JS Library 1.1.1
3873  * Copyright(c) 2006-2007, Ext JS, LLC.
3874  *
3875  * Originally Released Under LGPL - original licence link has changed is not relivant.
3876  *
3877  * Fork - LGPL
3878  * <script type="text/javascript">
3879  */
3880
3881
3882 /**
3883  * @class Roo.dd.DropTarget
3884  * @extends Roo.dd.DDTarget
3885  * A simple class that provides the basic implementation needed to make any element a drop target that can have
3886  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
3887  * @constructor
3888  * @param {String/HTMLElement/Element} el The container element
3889  * @param {Object} config
3890  */
3891 Roo.dd.DropTarget = function(el, config){
3892     this.el = Roo.get(el);
3893     
3894     var listeners = false; ;
3895     if (config & config.listeners) {
3896         listeners= config.listeners;
3897         delete config.listeners;
3898     }
3899     Roo.apply(this, config);
3900     
3901     if(this.containerScroll){
3902         Roo.dd.ScrollManager.register(this.el);
3903     }
3904     this.addEvents( {
3905          /**
3906          * @scope Roo.dd.DropTarget
3907          */
3908          
3909          /**
3910          * @event enter
3911          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3912          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
3913          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
3914          * 
3915          * IMPORTANT : it should set this.overClass and this.dropAllowed
3916          * 
3917          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3918          * @param {Event} e The event
3919          * @param {Object} data An object containing arbitrary data supplied by the drag source
3920          */
3921         "enter" : true,
3922         
3923          /**
3924          * @event over
3925          * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3926          * This method will be called on every mouse movement while the drag source is over the drop target.
3927          * This default implementation simply returns the dropAllowed config value.
3928          * 
3929          * IMPORTANT : it should set this.dropAllowed
3930          * 
3931          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3932          * @param {Event} e The event
3933          * @param {Object} data An object containing arbitrary data supplied by the drag source
3934          
3935          */
3936         "over" : true,
3937         /**
3938          * @event out
3939          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3940          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
3941          * overClass (if any) from the drop element.
3942          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3943          * @param {Event} e The event
3944          * @param {Object} data An object containing arbitrary data supplied by the drag source
3945          */
3946          "out" : true,
3947          
3948         /**
3949          * @event drop
3950          * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3951          * been dropped on it.  This method has no default implementation and returns false, so you must provide an
3952          * implementation that does something to process the drop event and returns true so that the drag source's
3953          * repair action does not run.
3954          * 
3955          * IMPORTANT : it should set this.success
3956          * 
3957          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3958          * @param {Event} e The event
3959          * @param {Object} data An object containing arbitrary data supplied by the drag source
3960         */
3961          "drop" : true
3962     });
3963             
3964      
3965     Roo.dd.DropTarget.superclass.constructor.call(  this, 
3966         this.el.dom, 
3967         this.ddGroup || this.group,
3968         {
3969             isTarget: true,
3970             listeners : listeners || {} 
3971            
3972         
3973         }
3974     );
3975
3976 };
3977
3978 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3979     /**
3980      * @cfg {String} overClass
3981      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3982      */
3983      /**
3984      * @cfg {String} ddGroup
3985      * The drag drop group to handle drop events for
3986      */
3987      
3988     /**
3989      * @cfg {String} dropAllowed
3990      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3991      */
3992     dropAllowed : "x-dd-drop-ok",
3993     /**
3994      * @cfg {String} dropNotAllowed
3995      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3996      */
3997     dropNotAllowed : "x-dd-drop-nodrop",
3998     /**
3999      * @cfg {boolean} success
4000      * set this after drop listener.. 
4001      */
4002     success : false,
4003     /**
4004      * @cfg {boolean} valid
4005      * if the drop point is valid for over/enter..
4006      */
4007     valid : false,
4008     // private
4009     isTarget : true,
4010
4011     // private
4012     isNotifyTarget : true,
4013     
4014     /**
4015      * @hide
4016      */
4017     notifyEnter : function(dd, e, data){
4018         this.valid = true;
4019         this.fireEvent('enter', this, dd, e, data);
4020         if(this.overClass){
4021             this.el.addClass(this.overClass);
4022         }
4023         return this.valid ? this.dropAllowed : this.dropNotAllowed;
4024     },
4025
4026     /**
4027      * @hide
4028      */
4029     notifyOver : function(dd, e, data){
4030         this.valid = true;
4031         this.fireEvent('over', this, dd, e, data);
4032         return this.valid ? this.dropAllowed : this.dropNotAllowed;
4033     },
4034
4035     /**
4036      * @hide
4037      */
4038     notifyOut : function(dd, e, data){
4039         this.fireEvent('out', this, dd, e, data);
4040         if(this.overClass){
4041             this.el.removeClass(this.overClass);
4042         }
4043     },
4044
4045     /**
4046      * @hide
4047      */
4048     notifyDrop : function(dd, e, data){
4049         this.success = false;
4050         this.fireEvent('drop', this, dd, e, data);
4051         return this.success;
4052     }
4053 });/*
4054  * Based on:
4055  * Ext JS Library 1.1.1
4056  * Copyright(c) 2006-2007, Ext JS, LLC.
4057  *
4058  * Originally Released Under LGPL - original licence link has changed is not relivant.
4059  *
4060  * Fork - LGPL
4061  * <script type="text/javascript">
4062  */
4063
4064
4065 /**
4066  * @class Roo.dd.DragZone
4067  * @extends Roo.dd.DragSource
4068  * This class provides a container DD instance that proxies for multiple child node sources.<br />
4069  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4070  * @constructor
4071  * @param {String/HTMLElement/Element} el The container element
4072  * @param {Object} config
4073  */
4074 Roo.dd.DragZone = function(el, config){
4075     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4076     if(this.containerScroll){
4077         Roo.dd.ScrollManager.register(this.el);
4078     }
4079 };
4080
4081 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4082     /**
4083      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4084      * for auto scrolling during drag operations.
4085      */
4086     /**
4087      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4088      * method after a failed drop (defaults to "c3daf9" - light blue)
4089      */
4090
4091     /**
4092      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4093      * for a valid target to drag based on the mouse down. Override this method
4094      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4095      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4096      * @param {EventObject} e The mouse down event
4097      * @return {Object} The dragData
4098      */
4099     getDragData : function(e){
4100         return Roo.dd.Registry.getHandleFromEvent(e);
4101     },
4102     
4103     /**
4104      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4105      * this.dragData.ddel
4106      * @param {Number} x The x position of the click on the dragged object
4107      * @param {Number} y The y position of the click on the dragged object
4108      * @return {Boolean} true to continue the drag, false to cancel
4109      */
4110     onInitDrag : function(x, y){
4111         this.proxy.update(this.dragData.ddel.cloneNode(true));
4112         this.onStartDrag(x, y);
4113         return true;
4114     },
4115     
4116     /**
4117      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
4118      */
4119     afterRepair : function(){
4120         if(Roo.enableFx){
4121             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4122         }
4123         this.dragging = false;
4124     },
4125
4126     /**
4127      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4128      * the XY of this.dragData.ddel
4129      * @param {EventObject} e The mouse up event
4130      * @return {Array} The xy location (e.g. [100, 200])
4131      */
4132     getRepairXY : function(e){
4133         return Roo.Element.fly(this.dragData.ddel).getXY();  
4134     }
4135 });/*
4136  * Based on:
4137  * Ext JS Library 1.1.1
4138  * Copyright(c) 2006-2007, Ext JS, LLC.
4139  *
4140  * Originally Released Under LGPL - original licence link has changed is not relivant.
4141  *
4142  * Fork - LGPL
4143  * <script type="text/javascript">
4144  */
4145 /**
4146  * @class Roo.dd.DropZone
4147  * @extends Roo.dd.DropTarget
4148  * This class provides a container DD instance that proxies for multiple child node targets.<br />
4149  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4150  * @constructor
4151  * @param {String/HTMLElement/Element} el The container element
4152  * @param {Object} config
4153  */
4154 Roo.dd.DropZone = function(el, config){
4155     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4156 };
4157
4158 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4159     /**
4160      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
4161      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4162      * provide your own custom lookup.
4163      * @param {Event} e The event
4164      * @return {Object} data The custom data
4165      */
4166     getTargetFromEvent : function(e){
4167         return Roo.dd.Registry.getTargetFromEvent(e);
4168     },
4169
4170     /**
4171      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4172      * that it has registered.  This method has no default implementation and should be overridden to provide
4173      * node-specific processing if necessary.
4174      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
4175      * {@link #getTargetFromEvent} for this node)
4176      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4177      * @param {Event} e The event
4178      * @param {Object} data An object containing arbitrary data supplied by the drag source
4179      */
4180     onNodeEnter : function(n, dd, e, data){
4181         
4182     },
4183
4184     /**
4185      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4186      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
4187      * overridden to provide the proper feedback.
4188      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4189      * {@link #getTargetFromEvent} for this node)
4190      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4191      * @param {Event} e The event
4192      * @param {Object} data An object containing arbitrary data supplied by the drag source
4193      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4194      * underlying {@link Roo.dd.StatusProxy} can be updated
4195      */
4196     onNodeOver : function(n, dd, e, data){
4197         return this.dropAllowed;
4198     },
4199
4200     /**
4201      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4202      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
4203      * node-specific processing if necessary.
4204      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4205      * {@link #getTargetFromEvent} for this node)
4206      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4207      * @param {Event} e The event
4208      * @param {Object} data An object containing arbitrary data supplied by the drag source
4209      */
4210     onNodeOut : function(n, dd, e, data){
4211         
4212     },
4213
4214     /**
4215      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4216      * the drop node.  The default implementation returns false, so it should be overridden to provide the
4217      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4218      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4219      * {@link #getTargetFromEvent} for this node)
4220      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4221      * @param {Event} e The event
4222      * @param {Object} data An object containing arbitrary data supplied by the drag source
4223      * @return {Boolean} True if the drop was valid, else false
4224      */
4225     onNodeDrop : function(n, dd, e, data){
4226         return false;
4227     },
4228
4229     /**
4230      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4231      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
4232      * it should be overridden to provide the proper feedback if necessary.
4233      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4234      * @param {Event} e The event
4235      * @param {Object} data An object containing arbitrary data supplied by the drag source
4236      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4237      * underlying {@link Roo.dd.StatusProxy} can be updated
4238      */
4239     onContainerOver : function(dd, e, data){
4240         return this.dropNotAllowed;
4241     },
4242
4243     /**
4244      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4245      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
4246      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4247      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
4248      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4249      * @param {Event} e The event
4250      * @param {Object} data An object containing arbitrary data supplied by the drag source
4251      * @return {Boolean} True if the drop was valid, else false
4252      */
4253     onContainerDrop : function(dd, e, data){
4254         return false;
4255     },
4256
4257     /**
4258      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4259      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
4260      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4261      * you should override this method and provide a custom implementation.
4262      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4263      * @param {Event} e The event
4264      * @param {Object} data An object containing arbitrary data supplied by the drag source
4265      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4266      * underlying {@link Roo.dd.StatusProxy} can be updated
4267      */
4268     notifyEnter : function(dd, e, data){
4269         return this.dropNotAllowed;
4270     },
4271
4272     /**
4273      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4274      * This method will be called on every mouse movement while the drag source is over the drop zone.
4275      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4276      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4277      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4278      * registered node, it will call {@link #onContainerOver}.
4279      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4280      * @param {Event} e The event
4281      * @param {Object} data An object containing arbitrary data supplied by the drag source
4282      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4283      * underlying {@link Roo.dd.StatusProxy} can be updated
4284      */
4285     notifyOver : function(dd, e, data){
4286         var n = this.getTargetFromEvent(e);
4287         if(!n){ // not over valid drop target
4288             if(this.lastOverNode){
4289                 this.onNodeOut(this.lastOverNode, dd, e, data);
4290                 this.lastOverNode = null;
4291             }
4292             return this.onContainerOver(dd, e, data);
4293         }
4294         if(this.lastOverNode != n){
4295             if(this.lastOverNode){
4296                 this.onNodeOut(this.lastOverNode, dd, e, data);
4297             }
4298             this.onNodeEnter(n, dd, e, data);
4299             this.lastOverNode = n;
4300         }
4301         return this.onNodeOver(n, dd, e, data);
4302     },
4303
4304     /**
4305      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4306      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
4307      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4308      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4309      * @param {Event} e The event
4310      * @param {Object} data An object containing arbitrary data supplied by the drag zone
4311      */
4312     notifyOut : function(dd, e, data){
4313         if(this.lastOverNode){
4314             this.onNodeOut(this.lastOverNode, dd, e, data);
4315             this.lastOverNode = null;
4316         }
4317     },
4318
4319     /**
4320      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4321      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
4322      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4323      * otherwise it will call {@link #onContainerDrop}.
4324      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4325      * @param {Event} e The event
4326      * @param {Object} data An object containing arbitrary data supplied by the drag source
4327      * @return {Boolean} True if the drop was valid, else false
4328      */
4329     notifyDrop : function(dd, e, data){
4330         if(this.lastOverNode){
4331             this.onNodeOut(this.lastOverNode, dd, e, data);
4332             this.lastOverNode = null;
4333         }
4334         var n = this.getTargetFromEvent(e);
4335         return n ?
4336             this.onNodeDrop(n, dd, e, data) :
4337             this.onContainerDrop(dd, e, data);
4338     },
4339
4340     // private
4341     triggerCacheRefresh : function(){
4342         Roo.dd.DDM.refreshCache(this.groups);
4343     }  
4344 });/*
4345  * Based on:
4346  * Ext JS Library 1.1.1
4347  * Copyright(c) 2006-2007, Ext JS, LLC.
4348  *
4349  * Originally Released Under LGPL - original licence link has changed is not relivant.
4350  *
4351  * Fork - LGPL
4352  * <script type="text/javascript">
4353  */
4354
4355
4356 /**
4357  * @class Roo.data.SortTypes
4358  * @singleton
4359  * Defines the default sorting (casting?) comparison functions used when sorting data.
4360  */
4361 Roo.data.SortTypes = {
4362     /**
4363      * Default sort that does nothing
4364      * @param {Mixed} s The value being converted
4365      * @return {Mixed} The comparison value
4366      */
4367     none : function(s){
4368         return s;
4369     },
4370     
4371     /**
4372      * The regular expression used to strip tags
4373      * @type {RegExp}
4374      * @property
4375      */
4376     stripTagsRE : /<\/?[^>]+>/gi,
4377     
4378     /**
4379      * Strips all HTML tags to sort on text only
4380      * @param {Mixed} s The value being converted
4381      * @return {String} The comparison value
4382      */
4383     asText : function(s){
4384         return String(s).replace(this.stripTagsRE, "");
4385     },
4386     
4387     /**
4388      * Strips all HTML tags to sort on text only - Case insensitive
4389      * @param {Mixed} s The value being converted
4390      * @return {String} The comparison value
4391      */
4392     asUCText : function(s){
4393         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4394     },
4395     
4396     /**
4397      * Case insensitive string
4398      * @param {Mixed} s The value being converted
4399      * @return {String} The comparison value
4400      */
4401     asUCString : function(s) {
4402         return String(s).toUpperCase();
4403     },
4404     
4405     /**
4406      * Date sorting
4407      * @param {Mixed} s The value being converted
4408      * @return {Number} The comparison value
4409      */
4410     asDate : function(s) {
4411         if(!s){
4412             return 0;
4413         }
4414         if(s instanceof Date){
4415             return s.getTime();
4416         }
4417         return Date.parse(String(s));
4418     },
4419     
4420     /**
4421      * Float sorting
4422      * @param {Mixed} s The value being converted
4423      * @return {Float} The comparison value
4424      */
4425     asFloat : function(s) {
4426         var val = parseFloat(String(s).replace(/,/g, ""));
4427         if(isNaN(val)) val = 0;
4428         return val;
4429     },
4430     
4431     /**
4432      * Integer sorting
4433      * @param {Mixed} s The value being converted
4434      * @return {Number} The comparison value
4435      */
4436     asInt : function(s) {
4437         var val = parseInt(String(s).replace(/,/g, ""));
4438         if(isNaN(val)) val = 0;
4439         return val;
4440     }
4441 };/*
4442  * Based on:
4443  * Ext JS Library 1.1.1
4444  * Copyright(c) 2006-2007, Ext JS, LLC.
4445  *
4446  * Originally Released Under LGPL - original licence link has changed is not relivant.
4447  *
4448  * Fork - LGPL
4449  * <script type="text/javascript">
4450  */
4451
4452 /**
4453 * @class Roo.data.Record
4454  * Instances of this class encapsulate both record <em>definition</em> information, and record
4455  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4456  * to access Records cached in an {@link Roo.data.Store} object.<br>
4457  * <p>
4458  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4459  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4460  * objects.<br>
4461  * <p>
4462  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4463  * @constructor
4464  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4465  * {@link #create}. The parameters are the same.
4466  * @param {Array} data An associative Array of data values keyed by the field name.
4467  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4468  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4469  * not specified an integer id is generated.
4470  */
4471 Roo.data.Record = function(data, id){
4472     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4473     this.data = data;
4474 };
4475
4476 /**
4477  * Generate a constructor for a specific record layout.
4478  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4479  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4480  * Each field definition object may contain the following properties: <ul>
4481  * <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,
4482  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4483  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4484  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4485  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4486  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4487  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4488  * this may be omitted.</p></li>
4489  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4490  * <ul><li>auto (Default, implies no conversion)</li>
4491  * <li>string</li>
4492  * <li>int</li>
4493  * <li>float</li>
4494  * <li>boolean</li>
4495  * <li>date</li></ul></p></li>
4496  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4497  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4498  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4499  * by the Reader into an object that will be stored in the Record. It is passed the
4500  * following parameters:<ul>
4501  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4502  * </ul></p></li>
4503  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4504  * </ul>
4505  * <br>usage:<br><pre><code>
4506 var TopicRecord = Roo.data.Record.create(
4507     {name: 'title', mapping: 'topic_title'},
4508     {name: 'author', mapping: 'username'},
4509     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4510     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4511     {name: 'lastPoster', mapping: 'user2'},
4512     {name: 'excerpt', mapping: 'post_text'}
4513 );
4514
4515 var myNewRecord = new TopicRecord({
4516     title: 'Do my job please',
4517     author: 'noobie',
4518     totalPosts: 1,
4519     lastPost: new Date(),
4520     lastPoster: 'Animal',
4521     excerpt: 'No way dude!'
4522 });
4523 myStore.add(myNewRecord);
4524 </code></pre>
4525  * @method create
4526  * @static
4527  */
4528 Roo.data.Record.create = function(o){
4529     var f = function(){
4530         f.superclass.constructor.apply(this, arguments);
4531     };
4532     Roo.extend(f, Roo.data.Record);
4533     var p = f.prototype;
4534     p.fields = new Roo.util.MixedCollection(false, function(field){
4535         return field.name;
4536     });
4537     for(var i = 0, len = o.length; i < len; i++){
4538         p.fields.add(new Roo.data.Field(o[i]));
4539     }
4540     f.getField = function(name){
4541         return p.fields.get(name);  
4542     };
4543     return f;
4544 };
4545
4546 Roo.data.Record.AUTO_ID = 1000;
4547 Roo.data.Record.EDIT = 'edit';
4548 Roo.data.Record.REJECT = 'reject';
4549 Roo.data.Record.COMMIT = 'commit';
4550
4551 Roo.data.Record.prototype = {
4552     /**
4553      * Readonly flag - true if this record has been modified.
4554      * @type Boolean
4555      */
4556     dirty : false,
4557     editing : false,
4558     error: null,
4559     modified: null,
4560
4561     // private
4562     join : function(store){
4563         this.store = store;
4564     },
4565
4566     /**
4567      * Set the named field to the specified value.
4568      * @param {String} name The name of the field to set.
4569      * @param {Object} value The value to set the field to.
4570      */
4571     set : function(name, value){
4572         if(this.data[name] == value){
4573             return;
4574         }
4575         this.dirty = true;
4576         if(!this.modified){
4577             this.modified = {};
4578         }
4579         if(typeof this.modified[name] == 'undefined'){
4580             this.modified[name] = this.data[name];
4581         }
4582         this.data[name] = value;
4583         if(!this.editing){
4584             this.store.afterEdit(this);
4585         }       
4586     },
4587
4588     /**
4589      * Get the value of the named field.
4590      * @param {String} name The name of the field to get the value of.
4591      * @return {Object} The value of the field.
4592      */
4593     get : function(name){
4594         return this.data[name]; 
4595     },
4596
4597     // private
4598     beginEdit : function(){
4599         this.editing = true;
4600         this.modified = {}; 
4601     },
4602
4603     // private
4604     cancelEdit : function(){
4605         this.editing = false;
4606         delete this.modified;
4607     },
4608
4609     // private
4610     endEdit : function(){
4611         this.editing = false;
4612         if(this.dirty && this.store){
4613             this.store.afterEdit(this);
4614         }
4615     },
4616
4617     /**
4618      * Usually called by the {@link Roo.data.Store} which owns the Record.
4619      * Rejects all changes made to the Record since either creation, or the last commit operation.
4620      * Modified fields are reverted to their original values.
4621      * <p>
4622      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4623      * of reject operations.
4624      */
4625     reject : function(){
4626         var m = this.modified;
4627         for(var n in m){
4628             if(typeof m[n] != "function"){
4629                 this.data[n] = m[n];
4630             }
4631         }
4632         this.dirty = false;
4633         delete this.modified;
4634         this.editing = false;
4635         if(this.store){
4636             this.store.afterReject(this);
4637         }
4638     },
4639
4640     /**
4641      * Usually called by the {@link Roo.data.Store} which owns the Record.
4642      * Commits all changes made to the Record since either creation, or the last commit operation.
4643      * <p>
4644      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4645      * of commit operations.
4646      */
4647     commit : function(){
4648         this.dirty = false;
4649         delete this.modified;
4650         this.editing = false;
4651         if(this.store){
4652             this.store.afterCommit(this);
4653         }
4654     },
4655
4656     // private
4657     hasError : function(){
4658         return this.error != null;
4659     },
4660
4661     // private
4662     clearError : function(){
4663         this.error = null;
4664     },
4665
4666     /**
4667      * Creates a copy of this record.
4668      * @param {String} id (optional) A new record id if you don't want to use this record's id
4669      * @return {Record}
4670      */
4671     copy : function(newId) {
4672         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4673     }
4674 };/*
4675  * Based on:
4676  * Ext JS Library 1.1.1
4677  * Copyright(c) 2006-2007, Ext JS, LLC.
4678  *
4679  * Originally Released Under LGPL - original licence link has changed is not relivant.
4680  *
4681  * Fork - LGPL
4682  * <script type="text/javascript">
4683  */
4684
4685
4686
4687 /**
4688  * @class Roo.data.Store
4689  * @extends Roo.util.Observable
4690  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4691  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4692  * <p>
4693  * 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
4694  * has no knowledge of the format of the data returned by the Proxy.<br>
4695  * <p>
4696  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4697  * instances from the data object. These records are cached and made available through accessor functions.
4698  * @constructor
4699  * Creates a new Store.
4700  * @param {Object} config A config object containing the objects needed for the Store to access data,
4701  * and read the data into Records.
4702  */
4703 Roo.data.Store = function(config){
4704     this.data = new Roo.util.MixedCollection(false);
4705     this.data.getKey = function(o){
4706         return o.id;
4707     };
4708     this.baseParams = {};
4709     // private
4710     this.paramNames = {
4711         "start" : "start",
4712         "limit" : "limit",
4713         "sort" : "sort",
4714         "dir" : "dir"
4715     };
4716
4717     if(config && config.data){
4718         this.inlineData = config.data;
4719         delete config.data;
4720     }
4721
4722     Roo.apply(this, config);
4723     
4724     if(this.reader){ // reader passed
4725         this.reader = Roo.factory(this.reader, Roo.data);
4726         this.reader.xmodule = this.xmodule || false;
4727         if(!this.recordType){
4728             this.recordType = this.reader.recordType;
4729         }
4730         if(this.reader.onMetaChange){
4731             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4732         }
4733     }
4734
4735     if(this.recordType){
4736         this.fields = this.recordType.prototype.fields;
4737     }
4738     this.modified = [];
4739
4740     this.addEvents({
4741         /**
4742          * @event datachanged
4743          * Fires when the data cache has changed, and a widget which is using this Store
4744          * as a Record cache should refresh its view.
4745          * @param {Store} this
4746          */
4747         datachanged : true,
4748         /**
4749          * @event metachange
4750          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4751          * @param {Store} this
4752          * @param {Object} meta The JSON metadata
4753          */
4754         metachange : true,
4755         /**
4756          * @event add
4757          * Fires when Records have been added to the Store
4758          * @param {Store} this
4759          * @param {Roo.data.Record[]} records The array of Records added
4760          * @param {Number} index The index at which the record(s) were added
4761          */
4762         add : true,
4763         /**
4764          * @event remove
4765          * Fires when a Record has been removed from the Store
4766          * @param {Store} this
4767          * @param {Roo.data.Record} record The Record that was removed
4768          * @param {Number} index The index at which the record was removed
4769          */
4770         remove : true,
4771         /**
4772          * @event update
4773          * Fires when a Record has been updated
4774          * @param {Store} this
4775          * @param {Roo.data.Record} record The Record that was updated
4776          * @param {String} operation The update operation being performed.  Value may be one of:
4777          * <pre><code>
4778  Roo.data.Record.EDIT
4779  Roo.data.Record.REJECT
4780  Roo.data.Record.COMMIT
4781          * </code></pre>
4782          */
4783         update : true,
4784         /**
4785          * @event clear
4786          * Fires when the data cache has been cleared.
4787          * @param {Store} this
4788          */
4789         clear : true,
4790         /**
4791          * @event beforeload
4792          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4793          * the load action will be canceled.
4794          * @param {Store} this
4795          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4796          */
4797         beforeload : true,
4798         /**
4799          * @event load
4800          * Fires after a new set of Records has been loaded.
4801          * @param {Store} this
4802          * @param {Roo.data.Record[]} records The Records that were loaded
4803          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4804          */
4805         load : true,
4806         /**
4807          * @event loadexception
4808          * Fires if an exception occurs in the Proxy during loading.
4809          * Called with the signature of the Proxy's "loadexception" event.
4810          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4811          * 
4812          * @param {Proxy} 
4813          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4814          * @param {Object} load options 
4815          * @param {Object} jsonData from your request (normally this contains the Exception)
4816          */
4817         loadexception : true
4818     });
4819     
4820     if(this.proxy){
4821         this.proxy = Roo.factory(this.proxy, Roo.data);
4822         this.proxy.xmodule = this.xmodule || false;
4823         this.relayEvents(this.proxy,  ["loadexception"]);
4824     }
4825     this.sortToggle = {};
4826
4827     Roo.data.Store.superclass.constructor.call(this);
4828
4829     if(this.inlineData){
4830         this.loadData(this.inlineData);
4831         delete this.inlineData;
4832     }
4833 };
4834 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4835      /**
4836     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4837     * without a remote query - used by combo/forms at present.
4838     */
4839     
4840     /**
4841     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4842     */
4843     /**
4844     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4845     */
4846     /**
4847     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4848     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4849     */
4850     /**
4851     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4852     * on any HTTP request
4853     */
4854     /**
4855     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4856     */
4857     /**
4858     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4859     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4860     */
4861     remoteSort : false,
4862
4863     /**
4864     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4865      * loaded or when a record is removed. (defaults to false).
4866     */
4867     pruneModifiedRecords : false,
4868
4869     // private
4870     lastOptions : null,
4871
4872     /**
4873      * Add Records to the Store and fires the add event.
4874      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4875      */
4876     add : function(records){
4877         records = [].concat(records);
4878         for(var i = 0, len = records.length; i < len; i++){
4879             records[i].join(this);
4880         }
4881         var index = this.data.length;
4882         this.data.addAll(records);
4883         this.fireEvent("add", this, records, index);
4884     },
4885
4886     /**
4887      * Remove a Record from the Store and fires the remove event.
4888      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4889      */
4890     remove : function(record){
4891         var index = this.data.indexOf(record);
4892         this.data.removeAt(index);
4893         if(this.pruneModifiedRecords){
4894             this.modified.remove(record);
4895         }
4896         this.fireEvent("remove", this, record, index);
4897     },
4898
4899     /**
4900      * Remove all Records from the Store and fires the clear event.
4901      */
4902     removeAll : function(){
4903         this.data.clear();
4904         if(this.pruneModifiedRecords){
4905             this.modified = [];
4906         }
4907         this.fireEvent("clear", this);
4908     },
4909
4910     /**
4911      * Inserts Records to the Store at the given index and fires the add event.
4912      * @param {Number} index The start index at which to insert the passed Records.
4913      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4914      */
4915     insert : function(index, records){
4916         records = [].concat(records);
4917         for(var i = 0, len = records.length; i < len; i++){
4918             this.data.insert(index, records[i]);
4919             records[i].join(this);
4920         }
4921         this.fireEvent("add", this, records, index);
4922     },
4923
4924     /**
4925      * Get the index within the cache of the passed Record.
4926      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4927      * @return {Number} The index of the passed Record. Returns -1 if not found.
4928      */
4929     indexOf : function(record){
4930         return this.data.indexOf(record);
4931     },
4932
4933     /**
4934      * Get the index within the cache of the Record with the passed id.
4935      * @param {String} id The id of the Record to find.
4936      * @return {Number} The index of the Record. Returns -1 if not found.
4937      */
4938     indexOfId : function(id){
4939         return this.data.indexOfKey(id);
4940     },
4941
4942     /**
4943      * Get the Record with the specified id.
4944      * @param {String} id The id of the Record to find.
4945      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4946      */
4947     getById : function(id){
4948         return this.data.key(id);
4949     },
4950
4951     /**
4952      * Get the Record at the specified index.
4953      * @param {Number} index The index of the Record to find.
4954      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4955      */
4956     getAt : function(index){
4957         return this.data.itemAt(index);
4958     },
4959
4960     /**
4961      * Returns a range of Records between specified indices.
4962      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4963      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4964      * @return {Roo.data.Record[]} An array of Records
4965      */
4966     getRange : function(start, end){
4967         return this.data.getRange(start, end);
4968     },
4969
4970     // private
4971     storeOptions : function(o){
4972         o = Roo.apply({}, o);
4973         delete o.callback;
4974         delete o.scope;
4975         this.lastOptions = o;
4976     },
4977
4978     /**
4979      * Loads the Record cache from the configured Proxy using the configured Reader.
4980      * <p>
4981      * If using remote paging, then the first load call must specify the <em>start</em>
4982      * and <em>limit</em> properties in the options.params property to establish the initial
4983      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4984      * <p>
4985      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4986      * and this call will return before the new data has been loaded. Perform any post-processing
4987      * in a callback function, or in a "load" event handler.</strong>
4988      * <p>
4989      * @param {Object} options An object containing properties which control loading options:<ul>
4990      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4991      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4992      * passed the following arguments:<ul>
4993      * <li>r : Roo.data.Record[]</li>
4994      * <li>options: Options object from the load call</li>
4995      * <li>success: Boolean success indicator</li></ul></li>
4996      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4997      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4998      * </ul>
4999      */
5000     load : function(options){
5001         options = options || {};
5002         if(this.fireEvent("beforeload", this, options) !== false){
5003             this.storeOptions(options);
5004             var p = Roo.apply(options.params || {}, this.baseParams);
5005             // if meta was not loaded from remote source.. try requesting it.
5006             if (!this.reader.metaFromRemote) {
5007                 p._requestMeta = 1;
5008             }
5009             if(this.sortInfo && this.remoteSort){
5010                 var pn = this.paramNames;
5011                 p[pn["sort"]] = this.sortInfo.field;
5012                 p[pn["dir"]] = this.sortInfo.direction;
5013             }
5014             this.proxy.load(p, this.reader, this.loadRecords, this, options);
5015         }
5016     },
5017
5018     /**
5019      * Reloads the Record cache from the configured Proxy using the configured Reader and
5020      * the options from the last load operation performed.
5021      * @param {Object} options (optional) An object containing properties which may override the options
5022      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5023      * the most recently used options are reused).
5024      */
5025     reload : function(options){
5026         this.load(Roo.applyIf(options||{}, this.lastOptions));
5027     },
5028
5029     // private
5030     // Called as a callback by the Reader during a load operation.
5031     loadRecords : function(o, options, success){
5032         if(!o || success === false){
5033             if(success !== false){
5034                 this.fireEvent("load", this, [], options);
5035             }
5036             if(options.callback){
5037                 options.callback.call(options.scope || this, [], options, false);
5038             }
5039             return;
5040         }
5041         // if data returned failure - throw an exception.
5042         if (o.success === false) {
5043             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5044             return;
5045         }
5046         var r = o.records, t = o.totalRecords || r.length;
5047         if(!options || options.add !== true){
5048             if(this.pruneModifiedRecords){
5049                 this.modified = [];
5050             }
5051             for(var i = 0, len = r.length; i < len; i++){
5052                 r[i].join(this);
5053             }
5054             if(this.snapshot){
5055                 this.data = this.snapshot;
5056                 delete this.snapshot;
5057             }
5058             this.data.clear();
5059             this.data.addAll(r);
5060             this.totalLength = t;
5061             this.applySort();
5062             this.fireEvent("datachanged", this);
5063         }else{
5064             this.totalLength = Math.max(t, this.data.length+r.length);
5065             this.add(r);
5066         }
5067         this.fireEvent("load", this, r, options);
5068         if(options.callback){
5069             options.callback.call(options.scope || this, r, options, true);
5070         }
5071     },
5072
5073     /**
5074      * Loads data from a passed data block. A Reader which understands the format of the data
5075      * must have been configured in the constructor.
5076      * @param {Object} data The data block from which to read the Records.  The format of the data expected
5077      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5078      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5079      */
5080     loadData : function(o, append){
5081         var r = this.reader.readRecords(o);
5082         this.loadRecords(r, {add: append}, true);
5083     },
5084
5085     /**
5086      * Gets the number of cached records.
5087      * <p>
5088      * <em>If using paging, this may not be the total size of the dataset. If the data object
5089      * used by the Reader contains the dataset size, then the getTotalCount() function returns
5090      * the data set size</em>
5091      */
5092     getCount : function(){
5093         return this.data.length || 0;
5094     },
5095
5096     /**
5097      * Gets the total number of records in the dataset as returned by the server.
5098      * <p>
5099      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5100      * the dataset size</em>
5101      */
5102     getTotalCount : function(){
5103         return this.totalLength || 0;
5104     },
5105
5106     /**
5107      * Returns the sort state of the Store as an object with two properties:
5108      * <pre><code>
5109  field {String} The name of the field by which the Records are sorted
5110  direction {String} The sort order, "ASC" or "DESC"
5111      * </code></pre>
5112      */
5113     getSortState : function(){
5114         return this.sortInfo;
5115     },
5116
5117     // private
5118     applySort : function(){
5119         if(this.sortInfo && !this.remoteSort){
5120             var s = this.sortInfo, f = s.field;
5121             var st = this.fields.get(f).sortType;
5122             var fn = function(r1, r2){
5123                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5124                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5125             };
5126             this.data.sort(s.direction, fn);
5127             if(this.snapshot && this.snapshot != this.data){
5128                 this.snapshot.sort(s.direction, fn);
5129             }
5130         }
5131     },
5132
5133     /**
5134      * Sets the default sort column and order to be used by the next load operation.
5135      * @param {String} fieldName The name of the field to sort by.
5136      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5137      */
5138     setDefaultSort : function(field, dir){
5139         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5140     },
5141
5142     /**
5143      * Sort the Records.
5144      * If remote sorting is used, the sort is performed on the server, and the cache is
5145      * reloaded. If local sorting is used, the cache is sorted internally.
5146      * @param {String} fieldName The name of the field to sort by.
5147      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5148      */
5149     sort : function(fieldName, dir){
5150         var f = this.fields.get(fieldName);
5151         if(!dir){
5152             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5153                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5154             }else{
5155                 dir = f.sortDir;
5156             }
5157         }
5158         this.sortToggle[f.name] = dir;
5159         this.sortInfo = {field: f.name, direction: dir};
5160         if(!this.remoteSort){
5161             this.applySort();
5162             this.fireEvent("datachanged", this);
5163         }else{
5164             this.load(this.lastOptions);
5165         }
5166     },
5167
5168     /**
5169      * Calls the specified function for each of the Records in the cache.
5170      * @param {Function} fn The function to call. The Record is passed as the first parameter.
5171      * Returning <em>false</em> aborts and exits the iteration.
5172      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5173      */
5174     each : function(fn, scope){
5175         this.data.each(fn, scope);
5176     },
5177
5178     /**
5179      * Gets all records modified since the last commit.  Modified records are persisted across load operations
5180      * (e.g., during paging).
5181      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5182      */
5183     getModifiedRecords : function(){
5184         return this.modified;
5185     },
5186
5187     // private
5188     createFilterFn : function(property, value, anyMatch){
5189         if(!value.exec){ // not a regex
5190             value = String(value);
5191             if(value.length == 0){
5192                 return false;
5193             }
5194             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5195         }
5196         return function(r){
5197             return value.test(r.data[property]);
5198         };
5199     },
5200
5201     /**
5202      * Sums the value of <i>property</i> for each record between start and end and returns the result.
5203      * @param {String} property A field on your records
5204      * @param {Number} start The record index to start at (defaults to 0)
5205      * @param {Number} end The last record index to include (defaults to length - 1)
5206      * @return {Number} The sum
5207      */
5208     sum : function(property, start, end){
5209         var rs = this.data.items, v = 0;
5210         start = start || 0;
5211         end = (end || end === 0) ? end : rs.length-1;
5212
5213         for(var i = start; i <= end; i++){
5214             v += (rs[i].data[property] || 0);
5215         }
5216         return v;
5217     },
5218
5219     /**
5220      * Filter the records by a specified property.
5221      * @param {String} field A field on your records
5222      * @param {String/RegExp} value Either a string that the field
5223      * should start with or a RegExp to test against the field
5224      * @param {Boolean} anyMatch True to match any part not just the beginning
5225      */
5226     filter : function(property, value, anyMatch){
5227         var fn = this.createFilterFn(property, value, anyMatch);
5228         return fn ? this.filterBy(fn) : this.clearFilter();
5229     },
5230
5231     /**
5232      * Filter by a function. The specified function will be called with each
5233      * record in this data source. If the function returns true the record is included,
5234      * otherwise it is filtered.
5235      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5236      * @param {Object} scope (optional) The scope of the function (defaults to this)
5237      */
5238     filterBy : function(fn, scope){
5239         this.snapshot = this.snapshot || this.data;
5240         this.data = this.queryBy(fn, scope||this);
5241         this.fireEvent("datachanged", this);
5242     },
5243
5244     /**
5245      * Query the records by a specified property.
5246      * @param {String} field A field on your records
5247      * @param {String/RegExp} value Either a string that the field
5248      * should start with or a RegExp to test against the field
5249      * @param {Boolean} anyMatch True to match any part not just the beginning
5250      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5251      */
5252     query : function(property, value, anyMatch){
5253         var fn = this.createFilterFn(property, value, anyMatch);
5254         return fn ? this.queryBy(fn) : this.data.clone();
5255     },
5256
5257     /**
5258      * Query by a function. The specified function will be called with each
5259      * record in this data source. If the function returns true the record is included
5260      * in the results.
5261      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5262      * @param {Object} scope (optional) The scope of the function (defaults to this)
5263       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5264      **/
5265     queryBy : function(fn, scope){
5266         var data = this.snapshot || this.data;
5267         return data.filterBy(fn, scope||this);
5268     },
5269
5270     /**
5271      * Collects unique values for a particular dataIndex from this store.
5272      * @param {String} dataIndex The property to collect
5273      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5274      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5275      * @return {Array} An array of the unique values
5276      **/
5277     collect : function(dataIndex, allowNull, bypassFilter){
5278         var d = (bypassFilter === true && this.snapshot) ?
5279                 this.snapshot.items : this.data.items;
5280         var v, sv, r = [], l = {};
5281         for(var i = 0, len = d.length; i < len; i++){
5282             v = d[i].data[dataIndex];
5283             sv = String(v);
5284             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5285                 l[sv] = true;
5286                 r[r.length] = v;
5287             }
5288         }
5289         return r;
5290     },
5291
5292     /**
5293      * Revert to a view of the Record cache with no filtering applied.
5294      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5295      */
5296     clearFilter : function(suppressEvent){
5297         if(this.snapshot && this.snapshot != this.data){
5298             this.data = this.snapshot;
5299             delete this.snapshot;
5300             if(suppressEvent !== true){
5301                 this.fireEvent("datachanged", this);
5302             }
5303         }
5304     },
5305
5306     // private
5307     afterEdit : function(record){
5308         if(this.modified.indexOf(record) == -1){
5309             this.modified.push(record);
5310         }
5311         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5312     },
5313
5314     // private
5315     afterReject : function(record){
5316         this.modified.remove(record);
5317         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5318     },
5319
5320     // private
5321     afterCommit : function(record){
5322         this.modified.remove(record);
5323         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5324     },
5325
5326     /**
5327      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5328      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5329      */
5330     commitChanges : function(){
5331         var m = this.modified.slice(0);
5332         this.modified = [];
5333         for(var i = 0, len = m.length; i < len; i++){
5334             m[i].commit();
5335         }
5336     },
5337
5338     /**
5339      * Cancel outstanding changes on all changed records.
5340      */
5341     rejectChanges : function(){
5342         var m = this.modified.slice(0);
5343         this.modified = [];
5344         for(var i = 0, len = m.length; i < len; i++){
5345             m[i].reject();
5346         }
5347     },
5348
5349     onMetaChange : function(meta, rtype, o){
5350         this.recordType = rtype;
5351         this.fields = rtype.prototype.fields;
5352         delete this.snapshot;
5353         this.sortInfo = meta.sortInfo || this.sortInfo;
5354         this.modified = [];
5355         this.fireEvent('metachange', this, this.reader.meta);
5356     }
5357 });/*
5358  * Based on:
5359  * Ext JS Library 1.1.1
5360  * Copyright(c) 2006-2007, Ext JS, LLC.
5361  *
5362  * Originally Released Under LGPL - original licence link has changed is not relivant.
5363  *
5364  * Fork - LGPL
5365  * <script type="text/javascript">
5366  */
5367
5368 /**
5369  * @class Roo.data.SimpleStore
5370  * @extends Roo.data.Store
5371  * Small helper class to make creating Stores from Array data easier.
5372  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5373  * @cfg {Array} fields An array of field definition objects, or field name strings.
5374  * @cfg {Array} data The multi-dimensional array of data
5375  * @constructor
5376  * @param {Object} config
5377  */
5378 Roo.data.SimpleStore = function(config){
5379     Roo.data.SimpleStore.superclass.constructor.call(this, {
5380         isLocal : true,
5381         reader: new Roo.data.ArrayReader({
5382                 id: config.id
5383             },
5384             Roo.data.Record.create(config.fields)
5385         ),
5386         proxy : new Roo.data.MemoryProxy(config.data)
5387     });
5388     this.load();
5389 };
5390 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5391  * Based on:
5392  * Ext JS Library 1.1.1
5393  * Copyright(c) 2006-2007, Ext JS, LLC.
5394  *
5395  * Originally Released Under LGPL - original licence link has changed is not relivant.
5396  *
5397  * Fork - LGPL
5398  * <script type="text/javascript">
5399  */
5400
5401 /**
5402 /**
5403  * @extends Roo.data.Store
5404  * @class Roo.data.JsonStore
5405  * Small helper class to make creating Stores for JSON data easier. <br/>
5406 <pre><code>
5407 var store = new Roo.data.JsonStore({
5408     url: 'get-images.php',
5409     root: 'images',
5410     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5411 });
5412 </code></pre>
5413  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5414  * JsonReader and HttpProxy (unless inline data is provided).</b>
5415  * @cfg {Array} fields An array of field definition objects, or field name strings.
5416  * @constructor
5417  * @param {Object} config
5418  */
5419 Roo.data.JsonStore = function(c){
5420     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5421         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5422         reader: new Roo.data.JsonReader(c, c.fields)
5423     }));
5424 };
5425 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5426  * Based on:
5427  * Ext JS Library 1.1.1
5428  * Copyright(c) 2006-2007, Ext JS, LLC.
5429  *
5430  * Originally Released Under LGPL - original licence link has changed is not relivant.
5431  *
5432  * Fork - LGPL
5433  * <script type="text/javascript">
5434  */
5435
5436  
5437 Roo.data.Field = function(config){
5438     if(typeof config == "string"){
5439         config = {name: config};
5440     }
5441     Roo.apply(this, config);
5442     
5443     if(!this.type){
5444         this.type = "auto";
5445     }
5446     
5447     var st = Roo.data.SortTypes;
5448     // named sortTypes are supported, here we look them up
5449     if(typeof this.sortType == "string"){
5450         this.sortType = st[this.sortType];
5451     }
5452     
5453     // set default sortType for strings and dates
5454     if(!this.sortType){
5455         switch(this.type){
5456             case "string":
5457                 this.sortType = st.asUCString;
5458                 break;
5459             case "date":
5460                 this.sortType = st.asDate;
5461                 break;
5462             default:
5463                 this.sortType = st.none;
5464         }
5465     }
5466
5467     // define once
5468     var stripRe = /[\$,%]/g;
5469
5470     // prebuilt conversion function for this field, instead of
5471     // switching every time we're reading a value
5472     if(!this.convert){
5473         var cv, dateFormat = this.dateFormat;
5474         switch(this.type){
5475             case "":
5476             case "auto":
5477             case undefined:
5478                 cv = function(v){ return v; };
5479                 break;
5480             case "string":
5481                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5482                 break;
5483             case "int":
5484                 cv = function(v){
5485                     return v !== undefined && v !== null && v !== '' ?
5486                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5487                     };
5488                 break;
5489             case "float":
5490                 cv = function(v){
5491                     return v !== undefined && v !== null && v !== '' ?
5492                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5493                     };
5494                 break;
5495             case "bool":
5496             case "boolean":
5497                 cv = function(v){ return v === true || v === "true" || v == 1; };
5498                 break;
5499             case "date":
5500                 cv = function(v){
5501                     if(!v){
5502                         return '';
5503                     }
5504                     if(v instanceof Date){
5505                         return v;
5506                     }
5507                     if(dateFormat){
5508                         if(dateFormat == "timestamp"){
5509                             return new Date(v*1000);
5510                         }
5511                         return Date.parseDate(v, dateFormat);
5512                     }
5513                     var parsed = Date.parse(v);
5514                     return parsed ? new Date(parsed) : null;
5515                 };
5516              break;
5517             
5518         }
5519         this.convert = cv;
5520     }
5521 };
5522
5523 Roo.data.Field.prototype = {
5524     dateFormat: null,
5525     defaultValue: "",
5526     mapping: null,
5527     sortType : null,
5528     sortDir : "ASC"
5529 };/*
5530  * Based on:
5531  * Ext JS Library 1.1.1
5532  * Copyright(c) 2006-2007, Ext JS, LLC.
5533  *
5534  * Originally Released Under LGPL - original licence link has changed is not relivant.
5535  *
5536  * Fork - LGPL
5537  * <script type="text/javascript">
5538  */
5539  
5540 // Base class for reading structured data from a data source.  This class is intended to be
5541 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5542
5543 /**
5544  * @class Roo.data.DataReader
5545  * Base class for reading structured data from a data source.  This class is intended to be
5546  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5547  */
5548
5549 Roo.data.DataReader = function(meta, recordType){
5550     
5551     this.meta = meta;
5552     
5553     this.recordType = recordType instanceof Array ? 
5554         Roo.data.Record.create(recordType) : recordType;
5555 };
5556
5557 Roo.data.DataReader.prototype = {
5558      /**
5559      * Create an empty record
5560      * @param {Object} data (optional) - overlay some values
5561      * @return {Roo.data.Record} record created.
5562      */
5563     newRow :  function(d) {
5564         var da =  {};
5565         this.recordType.prototype.fields.each(function(c) {
5566             switch( c.type) {
5567                 case 'int' : da[c.name] = 0; break;
5568                 case 'date' : da[c.name] = new Date(); break;
5569                 case 'float' : da[c.name] = 0.0; break;
5570                 case 'boolean' : da[c.name] = false; break;
5571                 default : da[c.name] = ""; break;
5572             }
5573             
5574         });
5575         return new this.recordType(Roo.apply(da, d));
5576     }
5577     
5578 };/*
5579  * Based on:
5580  * Ext JS Library 1.1.1
5581  * Copyright(c) 2006-2007, Ext JS, LLC.
5582  *
5583  * Originally Released Under LGPL - original licence link has changed is not relivant.
5584  *
5585  * Fork - LGPL
5586  * <script type="text/javascript">
5587  */
5588
5589 /**
5590  * @class Roo.data.DataProxy
5591  * @extends Roo.data.Observable
5592  * This class is an abstract base class for implementations which provide retrieval of
5593  * unformatted data objects.<br>
5594  * <p>
5595  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5596  * (of the appropriate type which knows how to parse the data object) to provide a block of
5597  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5598  * <p>
5599  * Custom implementations must implement the load method as described in
5600  * {@link Roo.data.HttpProxy#load}.
5601  */
5602 Roo.data.DataProxy = function(){
5603     this.addEvents({
5604         /**
5605          * @event beforeload
5606          * Fires before a network request is made to retrieve a data object.
5607          * @param {Object} This DataProxy object.
5608          * @param {Object} params The params parameter to the load function.
5609          */
5610         beforeload : true,
5611         /**
5612          * @event load
5613          * Fires before the load method's callback is called.
5614          * @param {Object} This DataProxy object.
5615          * @param {Object} o The data object.
5616          * @param {Object} arg The callback argument object passed to the load function.
5617          */
5618         load : true,
5619         /**
5620          * @event loadexception
5621          * Fires if an Exception occurs during data retrieval.
5622          * @param {Object} This DataProxy object.
5623          * @param {Object} o The data object.
5624          * @param {Object} arg The callback argument object passed to the load function.
5625          * @param {Object} e The Exception.
5626          */
5627         loadexception : true
5628     });
5629     Roo.data.DataProxy.superclass.constructor.call(this);
5630 };
5631
5632 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5633
5634     /**
5635      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5636      */
5637 /*
5638  * Based on:
5639  * Ext JS Library 1.1.1
5640  * Copyright(c) 2006-2007, Ext JS, LLC.
5641  *
5642  * Originally Released Under LGPL - original licence link has changed is not relivant.
5643  *
5644  * Fork - LGPL
5645  * <script type="text/javascript">
5646  */
5647 /**
5648  * @class Roo.data.MemoryProxy
5649  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5650  * to the Reader when its load method is called.
5651  * @constructor
5652  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5653  */
5654 Roo.data.MemoryProxy = function(data){
5655     if (data.data) {
5656         data = data.data;
5657     }
5658     Roo.data.MemoryProxy.superclass.constructor.call(this);
5659     this.data = data;
5660 };
5661
5662 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5663     /**
5664      * Load data from the requested source (in this case an in-memory
5665      * data object passed to the constructor), read the data object into
5666      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5667      * process that block using the passed callback.
5668      * @param {Object} params This parameter is not used by the MemoryProxy class.
5669      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5670      * object into a block of Roo.data.Records.
5671      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5672      * The function must be passed <ul>
5673      * <li>The Record block object</li>
5674      * <li>The "arg" argument from the load function</li>
5675      * <li>A boolean success indicator</li>
5676      * </ul>
5677      * @param {Object} scope The scope in which to call the callback
5678      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5679      */
5680     load : function(params, reader, callback, scope, arg){
5681         params = params || {};
5682         var result;
5683         try {
5684             result = reader.readRecords(this.data);
5685         }catch(e){
5686             this.fireEvent("loadexception", this, arg, null, e);
5687             callback.call(scope, null, arg, false);
5688             return;
5689         }
5690         callback.call(scope, result, arg, true);
5691     },
5692     
5693     // private
5694     update : function(params, records){
5695         
5696     }
5697 });/*
5698  * Based on:
5699  * Ext JS Library 1.1.1
5700  * Copyright(c) 2006-2007, Ext JS, LLC.
5701  *
5702  * Originally Released Under LGPL - original licence link has changed is not relivant.
5703  *
5704  * Fork - LGPL
5705  * <script type="text/javascript">
5706  */
5707 /**
5708  * @class Roo.data.HttpProxy
5709  * @extends Roo.data.DataProxy
5710  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5711  * configured to reference a certain URL.<br><br>
5712  * <p>
5713  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5714  * from which the running page was served.<br><br>
5715  * <p>
5716  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5717  * <p>
5718  * Be aware that to enable the browser to parse an XML document, the server must set
5719  * the Content-Type header in the HTTP response to "text/xml".
5720  * @constructor
5721  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5722  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5723  * will be used to make the request.
5724  */
5725 Roo.data.HttpProxy = function(conn){
5726     Roo.data.HttpProxy.superclass.constructor.call(this);
5727     // is conn a conn config or a real conn?
5728     this.conn = conn;
5729     this.useAjax = !conn || !conn.events;
5730   
5731 };
5732
5733 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5734     // thse are take from connection...
5735     
5736     /**
5737      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5738      */
5739     /**
5740      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5741      * extra parameters to each request made by this object. (defaults to undefined)
5742      */
5743     /**
5744      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5745      *  to each request made by this object. (defaults to undefined)
5746      */
5747     /**
5748      * @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)
5749      */
5750     /**
5751      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5752      */
5753      /**
5754      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5755      * @type Boolean
5756      */
5757   
5758
5759     /**
5760      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5761      * @type Boolean
5762      */
5763     /**
5764      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5765      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5766      * a finer-grained basis than the DataProxy events.
5767      */
5768     getConnection : function(){
5769         return this.useAjax ? Roo.Ajax : this.conn;
5770     },
5771
5772     /**
5773      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5774      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5775      * process that block using the passed callback.
5776      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5777      * for the request to the remote server.
5778      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5779      * object into a block of Roo.data.Records.
5780      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5781      * The function must be passed <ul>
5782      * <li>The Record block object</li>
5783      * <li>The "arg" argument from the load function</li>
5784      * <li>A boolean success indicator</li>
5785      * </ul>
5786      * @param {Object} scope The scope in which to call the callback
5787      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5788      */
5789     load : function(params, reader, callback, scope, arg){
5790         if(this.fireEvent("beforeload", this, params) !== false){
5791             var  o = {
5792                 params : params || {},
5793                 request: {
5794                     callback : callback,
5795                     scope : scope,
5796                     arg : arg
5797                 },
5798                 reader: reader,
5799                 callback : this.loadResponse,
5800                 scope: this
5801             };
5802             if(this.useAjax){
5803                 Roo.applyIf(o, this.conn);
5804                 if(this.activeRequest){
5805                     Roo.Ajax.abort(this.activeRequest);
5806                 }
5807                 this.activeRequest = Roo.Ajax.request(o);
5808             }else{
5809                 this.conn.request(o);
5810             }
5811         }else{
5812             callback.call(scope||this, null, arg, false);
5813         }
5814     },
5815
5816     // private
5817     loadResponse : function(o, success, response){
5818         delete this.activeRequest;
5819         if(!success){
5820             this.fireEvent("loadexception", this, o, response);
5821             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5822             return;
5823         }
5824         var result;
5825         try {
5826             result = o.reader.read(response);
5827         }catch(e){
5828             this.fireEvent("loadexception", this, o, response, e);
5829             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5830             return;
5831         }
5832         
5833         this.fireEvent("load", this, o, o.request.arg);
5834         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5835     },
5836
5837     // private
5838     update : function(dataSet){
5839
5840     },
5841
5842     // private
5843     updateResponse : function(dataSet){
5844
5845     }
5846 });/*
5847  * Based on:
5848  * Ext JS Library 1.1.1
5849  * Copyright(c) 2006-2007, Ext JS, LLC.
5850  *
5851  * Originally Released Under LGPL - original licence link has changed is not relivant.
5852  *
5853  * Fork - LGPL
5854  * <script type="text/javascript">
5855  */
5856
5857 /**
5858  * @class Roo.data.ScriptTagProxy
5859  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5860  * other than the originating domain of the running page.<br><br>
5861  * <p>
5862  * <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
5863  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5864  * <p>
5865  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5866  * source code that is used as the source inside a &lt;script> tag.<br><br>
5867  * <p>
5868  * In order for the browser to process the returned data, the server must wrap the data object
5869  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5870  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5871  * depending on whether the callback name was passed:
5872  * <p>
5873  * <pre><code>
5874 boolean scriptTag = false;
5875 String cb = request.getParameter("callback");
5876 if (cb != null) {
5877     scriptTag = true;
5878     response.setContentType("text/javascript");
5879 } else {
5880     response.setContentType("application/x-json");
5881 }
5882 Writer out = response.getWriter();
5883 if (scriptTag) {
5884     out.write(cb + "(");
5885 }
5886 out.print(dataBlock.toJsonString());
5887 if (scriptTag) {
5888     out.write(");");
5889 }
5890 </pre></code>
5891  *
5892  * @constructor
5893  * @param {Object} config A configuration object.
5894  */
5895 Roo.data.ScriptTagProxy = function(config){
5896     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5897     Roo.apply(this, config);
5898     this.head = document.getElementsByTagName("head")[0];
5899 };
5900
5901 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5902
5903 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5904     /**
5905      * @cfg {String} url The URL from which to request the data object.
5906      */
5907     /**
5908      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5909      */
5910     timeout : 30000,
5911     /**
5912      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5913      * the server the name of the callback function set up by the load call to process the returned data object.
5914      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5915      * javascript output which calls this named function passing the data object as its only parameter.
5916      */
5917     callbackParam : "callback",
5918     /**
5919      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5920      * name to the request.
5921      */
5922     nocache : true,
5923
5924     /**
5925      * Load data from the configured URL, read the data object into
5926      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5927      * process that block using the passed callback.
5928      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5929      * for the request to the remote server.
5930      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5931      * object into a block of Roo.data.Records.
5932      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5933      * The function must be passed <ul>
5934      * <li>The Record block object</li>
5935      * <li>The "arg" argument from the load function</li>
5936      * <li>A boolean success indicator</li>
5937      * </ul>
5938      * @param {Object} scope The scope in which to call the callback
5939      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5940      */
5941     load : function(params, reader, callback, scope, arg){
5942         if(this.fireEvent("beforeload", this, params) !== false){
5943
5944             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5945
5946             var url = this.url;
5947             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5948             if(this.nocache){
5949                 url += "&_dc=" + (new Date().getTime());
5950             }
5951             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5952             var trans = {
5953                 id : transId,
5954                 cb : "stcCallback"+transId,
5955                 scriptId : "stcScript"+transId,
5956                 params : params,
5957                 arg : arg,
5958                 url : url,
5959                 callback : callback,
5960                 scope : scope,
5961                 reader : reader
5962             };
5963             var conn = this;
5964
5965             window[trans.cb] = function(o){
5966                 conn.handleResponse(o, trans);
5967             };
5968
5969             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5970
5971             if(this.autoAbort !== false){
5972                 this.abort();
5973             }
5974
5975             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5976
5977             var script = document.createElement("script");
5978             script.setAttribute("src", url);
5979             script.setAttribute("type", "text/javascript");
5980             script.setAttribute("id", trans.scriptId);
5981             this.head.appendChild(script);
5982
5983             this.trans = trans;
5984         }else{
5985             callback.call(scope||this, null, arg, false);
5986         }
5987     },
5988
5989     // private
5990     isLoading : function(){
5991         return this.trans ? true : false;
5992     },
5993
5994     /**
5995      * Abort the current server request.
5996      */
5997     abort : function(){
5998         if(this.isLoading()){
5999             this.destroyTrans(this.trans);
6000         }
6001     },
6002
6003     // private
6004     destroyTrans : function(trans, isLoaded){
6005         this.head.removeChild(document.getElementById(trans.scriptId));
6006         clearTimeout(trans.timeoutId);
6007         if(isLoaded){
6008             window[trans.cb] = undefined;
6009             try{
6010                 delete window[trans.cb];
6011             }catch(e){}
6012         }else{
6013             // if hasn't been loaded, wait for load to remove it to prevent script error
6014             window[trans.cb] = function(){
6015                 window[trans.cb] = undefined;
6016                 try{
6017                     delete window[trans.cb];
6018                 }catch(e){}
6019             };
6020         }
6021     },
6022
6023     // private
6024     handleResponse : function(o, trans){
6025         this.trans = false;
6026         this.destroyTrans(trans, true);
6027         var result;
6028         try {
6029             result = trans.reader.readRecords(o);
6030         }catch(e){
6031             this.fireEvent("loadexception", this, o, trans.arg, e);
6032             trans.callback.call(trans.scope||window, null, trans.arg, false);
6033             return;
6034         }
6035         this.fireEvent("load", this, o, trans.arg);
6036         trans.callback.call(trans.scope||window, result, trans.arg, true);
6037     },
6038
6039     // private
6040     handleFailure : function(trans){
6041         this.trans = false;
6042         this.destroyTrans(trans, false);
6043         this.fireEvent("loadexception", this, null, trans.arg);
6044         trans.callback.call(trans.scope||window, null, trans.arg, false);
6045     }
6046 });/*
6047  * Based on:
6048  * Ext JS Library 1.1.1
6049  * Copyright(c) 2006-2007, Ext JS, LLC.
6050  *
6051  * Originally Released Under LGPL - original licence link has changed is not relivant.
6052  *
6053  * Fork - LGPL
6054  * <script type="text/javascript">
6055  */
6056
6057 /**
6058  * @class Roo.data.JsonReader
6059  * @extends Roo.data.DataReader
6060  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6061  * based on mappings in a provided Roo.data.Record constructor.
6062  * 
6063  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6064  * in the reply previously. 
6065  * 
6066  * <p>
6067  * Example code:
6068  * <pre><code>
6069 var RecordDef = Roo.data.Record.create([
6070     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6071     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6072 ]);
6073 var myReader = new Roo.data.JsonReader({
6074     totalProperty: "results",    // The property which contains the total dataset size (optional)
6075     root: "rows",                // The property which contains an Array of row objects
6076     id: "id"                     // The property within each row object that provides an ID for the record (optional)
6077 }, RecordDef);
6078 </code></pre>
6079  * <p>
6080  * This would consume a JSON file like this:
6081  * <pre><code>
6082 { 'results': 2, 'rows': [
6083     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6084     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6085 }
6086 </code></pre>
6087  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6088  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6089  * paged from the remote server.
6090  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6091  * @cfg {String} root name of the property which contains the Array of row objects.
6092  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6093  * @constructor
6094  * Create a new JsonReader
6095  * @param {Object} meta Metadata configuration options
6096  * @param {Object} recordType Either an Array of field definition objects,
6097  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6098  */
6099 Roo.data.JsonReader = function(meta, recordType){
6100     
6101     meta = meta || {};
6102     // set some defaults:
6103     Roo.applyIf(meta, {
6104         totalProperty: 'total',
6105         successProperty : 'success',
6106         root : 'data',
6107         id : 'id'
6108     });
6109     
6110     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6111 };
6112 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6113     
6114     /**
6115      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
6116      * Used by Store query builder to append _requestMeta to params.
6117      * 
6118      */
6119     metaFromRemote : false,
6120     /**
6121      * This method is only used by a DataProxy which has retrieved data from a remote server.
6122      * @param {Object} response The XHR object which contains the JSON data in its responseText.
6123      * @return {Object} data A data block which is used by an Roo.data.Store object as
6124      * a cache of Roo.data.Records.
6125      */
6126     read : function(response){
6127         var json = response.responseText;
6128        
6129         var o = /* eval:var:o */ eval("("+json+")");
6130         if(!o) {
6131             throw {message: "JsonReader.read: Json object not found"};
6132         }
6133         
6134         if(o.metaData){
6135             
6136             delete this.ef;
6137             this.metaFromRemote = true;
6138             this.meta = o.metaData;
6139             this.recordType = Roo.data.Record.create(o.metaData.fields);
6140             this.onMetaChange(this.meta, this.recordType, o);
6141         }
6142         return this.readRecords(o);
6143     },
6144
6145     // private function a store will implement
6146     onMetaChange : function(meta, recordType, o){
6147
6148     },
6149
6150     /**
6151          * @ignore
6152          */
6153     simpleAccess: function(obj, subsc) {
6154         return obj[subsc];
6155     },
6156
6157         /**
6158          * @ignore
6159          */
6160     getJsonAccessor: function(){
6161         var re = /[\[\.]/;
6162         return function(expr) {
6163             try {
6164                 return(re.test(expr))
6165                     ? new Function("obj", "return obj." + expr)
6166                     : function(obj){
6167                         return obj[expr];
6168                     };
6169             } catch(e){}
6170             return Roo.emptyFn;
6171         };
6172     }(),
6173
6174     /**
6175      * Create a data block containing Roo.data.Records from an XML document.
6176      * @param {Object} o An object which contains an Array of row objects in the property specified
6177      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6178      * which contains the total size of the dataset.
6179      * @return {Object} data A data block which is used by an Roo.data.Store object as
6180      * a cache of Roo.data.Records.
6181      */
6182     readRecords : function(o){
6183         /**
6184          * After any data loads, the raw JSON data is available for further custom processing.
6185          * @type Object
6186          */
6187         this.jsonData = o;
6188         var s = this.meta, Record = this.recordType,
6189             f = Record.prototype.fields, fi = f.items, fl = f.length;
6190
6191 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
6192         if (!this.ef) {
6193             if(s.totalProperty) {
6194                     this.getTotal = this.getJsonAccessor(s.totalProperty);
6195                 }
6196                 if(s.successProperty) {
6197                     this.getSuccess = this.getJsonAccessor(s.successProperty);
6198                 }
6199                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6200                 if (s.id) {
6201                         var g = this.getJsonAccessor(s.id);
6202                         this.getId = function(rec) {
6203                                 var r = g(rec);
6204                                 return (r === undefined || r === "") ? null : r;
6205                         };
6206                 } else {
6207                         this.getId = function(){return null;};
6208                 }
6209             this.ef = [];
6210             for(var jj = 0; jj < fl; jj++){
6211                 f = fi[jj];
6212                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6213                 this.ef[jj] = this.getJsonAccessor(map);
6214             }
6215         }
6216
6217         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6218         if(s.totalProperty){
6219             var vt = parseInt(this.getTotal(o), 10);
6220             if(!isNaN(vt)){
6221                 totalRecords = vt;
6222             }
6223         }
6224         if(s.successProperty){
6225             var vs = this.getSuccess(o);
6226             if(vs === false || vs === 'false'){
6227                 success = false;
6228             }
6229         }
6230         var records = [];
6231             for(var i = 0; i < c; i++){
6232                     var n = root[i];
6233                 var values = {};
6234                 var id = this.getId(n);
6235                 for(var j = 0; j < fl; j++){
6236                     f = fi[j];
6237                 var v = this.ef[j](n);
6238                 if (!f.convert) {
6239                     Roo.log('missing convert for ' + f.name);
6240                     Roo.log(f);
6241                     continue;
6242                 }
6243                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6244                 }
6245                 var record = new Record(values, id);
6246                 record.json = n;
6247                 records[i] = record;
6248             }
6249             return {
6250                 success : success,
6251                 records : records,
6252                 totalRecords : totalRecords
6253             };
6254     }
6255 });/*
6256  * Based on:
6257  * Ext JS Library 1.1.1
6258  * Copyright(c) 2006-2007, Ext JS, LLC.
6259  *
6260  * Originally Released Under LGPL - original licence link has changed is not relivant.
6261  *
6262  * Fork - LGPL
6263  * <script type="text/javascript">
6264  */
6265
6266 /**
6267  * @class Roo.data.XmlReader
6268  * @extends Roo.data.DataReader
6269  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6270  * based on mappings in a provided Roo.data.Record constructor.<br><br>
6271  * <p>
6272  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6273  * header in the HTTP response must be set to "text/xml".</em>
6274  * <p>
6275  * Example code:
6276  * <pre><code>
6277 var RecordDef = Roo.data.Record.create([
6278    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6279    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6280 ]);
6281 var myReader = new Roo.data.XmlReader({
6282    totalRecords: "results", // The element which contains the total dataset size (optional)
6283    record: "row",           // The repeated element which contains row information
6284    id: "id"                 // The element within the row that provides an ID for the record (optional)
6285 }, RecordDef);
6286 </code></pre>
6287  * <p>
6288  * This would consume an XML file like this:
6289  * <pre><code>
6290 &lt;?xml?>
6291 &lt;dataset>
6292  &lt;results>2&lt;/results>
6293  &lt;row>
6294    &lt;id>1&lt;/id>
6295    &lt;name>Bill&lt;/name>
6296    &lt;occupation>Gardener&lt;/occupation>
6297  &lt;/row>
6298  &lt;row>
6299    &lt;id>2&lt;/id>
6300    &lt;name>Ben&lt;/name>
6301    &lt;occupation>Horticulturalist&lt;/occupation>
6302  &lt;/row>
6303 &lt;/dataset>
6304 </code></pre>
6305  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6306  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6307  * paged from the remote server.
6308  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6309  * @cfg {String} success The DomQuery path to the success attribute used by forms.
6310  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6311  * a record identifier value.
6312  * @constructor
6313  * Create a new XmlReader
6314  * @param {Object} meta Metadata configuration options
6315  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
6316  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6317  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
6318  */
6319 Roo.data.XmlReader = function(meta, recordType){
6320     meta = meta || {};
6321     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6322 };
6323 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6324     /**
6325      * This method is only used by a DataProxy which has retrieved data from a remote server.
6326          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
6327          * to contain a method called 'responseXML' that returns an XML document object.
6328      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6329      * a cache of Roo.data.Records.
6330      */
6331     read : function(response){
6332         var doc = response.responseXML;
6333         if(!doc) {
6334             throw {message: "XmlReader.read: XML Document not available"};
6335         }
6336         return this.readRecords(doc);
6337     },
6338
6339     /**
6340      * Create a data block containing Roo.data.Records from an XML document.
6341          * @param {Object} doc A parsed XML document.
6342      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6343      * a cache of Roo.data.Records.
6344      */
6345     readRecords : function(doc){
6346         /**
6347          * After any data loads/reads, the raw XML Document is available for further custom processing.
6348          * @type XMLDocument
6349          */
6350         this.xmlData = doc;
6351         var root = doc.documentElement || doc;
6352         var q = Roo.DomQuery;
6353         var recordType = this.recordType, fields = recordType.prototype.fields;
6354         var sid = this.meta.id;
6355         var totalRecords = 0, success = true;
6356         if(this.meta.totalRecords){
6357             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6358         }
6359         
6360         if(this.meta.success){
6361             var sv = q.selectValue(this.meta.success, root, true);
6362             success = sv !== false && sv !== 'false';
6363         }
6364         var records = [];
6365         var ns = q.select(this.meta.record, root);
6366         for(var i = 0, len = ns.length; i < len; i++) {
6367                 var n = ns[i];
6368                 var values = {};
6369                 var id = sid ? q.selectValue(sid, n) : undefined;
6370                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6371                     var f = fields.items[j];
6372                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6373                     v = f.convert(v);
6374                     values[f.name] = v;
6375                 }
6376                 var record = new recordType(values, id);
6377                 record.node = n;
6378                 records[records.length] = record;
6379             }
6380
6381             return {
6382                 success : success,
6383                 records : records,
6384                 totalRecords : totalRecords || records.length
6385             };
6386     }
6387 });/*
6388  * Based on:
6389  * Ext JS Library 1.1.1
6390  * Copyright(c) 2006-2007, Ext JS, LLC.
6391  *
6392  * Originally Released Under LGPL - original licence link has changed is not relivant.
6393  *
6394  * Fork - LGPL
6395  * <script type="text/javascript">
6396  */
6397
6398 /**
6399  * @class Roo.data.ArrayReader
6400  * @extends Roo.data.DataReader
6401  * Data reader class to create an Array of Roo.data.Record objects from an Array.
6402  * Each element of that Array represents a row of data fields. The
6403  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6404  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6405  * <p>
6406  * Example code:.
6407  * <pre><code>
6408 var RecordDef = Roo.data.Record.create([
6409     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
6410     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
6411 ]);
6412 var myReader = new Roo.data.ArrayReader({
6413     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
6414 }, RecordDef);
6415 </code></pre>
6416  * <p>
6417  * This would consume an Array like this:
6418  * <pre><code>
6419 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6420   </code></pre>
6421  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6422  * @constructor
6423  * Create a new JsonReader
6424  * @param {Object} meta Metadata configuration options.
6425  * @param {Object} recordType Either an Array of field definition objects
6426  * as specified to {@link Roo.data.Record#create},
6427  * or an {@link Roo.data.Record} object
6428  * created using {@link Roo.data.Record#create}.
6429  */
6430 Roo.data.ArrayReader = function(meta, recordType){
6431     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6432 };
6433
6434 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6435     /**
6436      * Create a data block containing Roo.data.Records from an XML document.
6437      * @param {Object} o An Array of row objects which represents the dataset.
6438      * @return {Object} data A data block which is used by an Roo.data.Store object as
6439      * a cache of Roo.data.Records.
6440      */
6441     readRecords : function(o){
6442         var sid = this.meta ? this.meta.id : null;
6443         var recordType = this.recordType, fields = recordType.prototype.fields;
6444         var records = [];
6445         var root = o;
6446             for(var i = 0; i < root.length; i++){
6447                     var n = root[i];
6448                 var values = {};
6449                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6450                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6451                 var f = fields.items[j];
6452                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6453                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6454                 v = f.convert(v);
6455                 values[f.name] = v;
6456             }
6457                 var record = new recordType(values, id);
6458                 record.json = n;
6459                 records[records.length] = record;
6460             }
6461             return {
6462                 records : records,
6463                 totalRecords : records.length
6464             };
6465     }
6466 });/*
6467  * Based on:
6468  * Ext JS Library 1.1.1
6469  * Copyright(c) 2006-2007, Ext JS, LLC.
6470  *
6471  * Originally Released Under LGPL - original licence link has changed is not relivant.
6472  *
6473  * Fork - LGPL
6474  * <script type="text/javascript">
6475  */
6476
6477
6478 /**
6479  * @class Roo.data.Tree
6480  * @extends Roo.util.Observable
6481  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6482  * in the tree have most standard DOM functionality.
6483  * @constructor
6484  * @param {Node} root (optional) The root node
6485  */
6486 Roo.data.Tree = function(root){
6487    this.nodeHash = {};
6488    /**
6489     * The root node for this tree
6490     * @type Node
6491     */
6492    this.root = null;
6493    if(root){
6494        this.setRootNode(root);
6495    }
6496    this.addEvents({
6497        /**
6498         * @event append
6499         * Fires when a new child node is appended to a node in this tree.
6500         * @param {Tree} tree The owner tree
6501         * @param {Node} parent The parent node
6502         * @param {Node} node The newly appended node
6503         * @param {Number} index The index of the newly appended node
6504         */
6505        "append" : true,
6506        /**
6507         * @event remove
6508         * Fires when a child node is removed from a node in this tree.
6509         * @param {Tree} tree The owner tree
6510         * @param {Node} parent The parent node
6511         * @param {Node} node The child node removed
6512         */
6513        "remove" : true,
6514        /**
6515         * @event move
6516         * Fires when a node is moved to a new location in the tree
6517         * @param {Tree} tree The owner tree
6518         * @param {Node} node The node moved
6519         * @param {Node} oldParent The old parent of this node
6520         * @param {Node} newParent The new parent of this node
6521         * @param {Number} index The index it was moved to
6522         */
6523        "move" : true,
6524        /**
6525         * @event insert
6526         * Fires when a new child node is inserted in a node in this tree.
6527         * @param {Tree} tree The owner tree
6528         * @param {Node} parent The parent node
6529         * @param {Node} node The child node inserted
6530         * @param {Node} refNode The child node the node was inserted before
6531         */
6532        "insert" : true,
6533        /**
6534         * @event beforeappend
6535         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6536         * @param {Tree} tree The owner tree
6537         * @param {Node} parent The parent node
6538         * @param {Node} node The child node to be appended
6539         */
6540        "beforeappend" : true,
6541        /**
6542         * @event beforeremove
6543         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6544         * @param {Tree} tree The owner tree
6545         * @param {Node} parent The parent node
6546         * @param {Node} node The child node to be removed
6547         */
6548        "beforeremove" : true,
6549        /**
6550         * @event beforemove
6551         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6552         * @param {Tree} tree The owner tree
6553         * @param {Node} node The node being moved
6554         * @param {Node} oldParent The parent of the node
6555         * @param {Node} newParent The new parent the node is moving to
6556         * @param {Number} index The index it is being moved to
6557         */
6558        "beforemove" : true,
6559        /**
6560         * @event beforeinsert
6561         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6562         * @param {Tree} tree The owner tree
6563         * @param {Node} parent The parent node
6564         * @param {Node} node The child node to be inserted
6565         * @param {Node} refNode The child node the node is being inserted before
6566         */
6567        "beforeinsert" : true
6568    });
6569
6570     Roo.data.Tree.superclass.constructor.call(this);
6571 };
6572
6573 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6574     pathSeparator: "/",
6575
6576     proxyNodeEvent : function(){
6577         return this.fireEvent.apply(this, arguments);
6578     },
6579
6580     /**
6581      * Returns the root node for this tree.
6582      * @return {Node}
6583      */
6584     getRootNode : function(){
6585         return this.root;
6586     },
6587
6588     /**
6589      * Sets the root node for this tree.
6590      * @param {Node} node
6591      * @return {Node}
6592      */
6593     setRootNode : function(node){
6594         this.root = node;
6595         node.ownerTree = this;
6596         node.isRoot = true;
6597         this.registerNode(node);
6598         return node;
6599     },
6600
6601     /**
6602      * Gets a node in this tree by its id.
6603      * @param {String} id
6604      * @return {Node}
6605      */
6606     getNodeById : function(id){
6607         return this.nodeHash[id];
6608     },
6609
6610     registerNode : function(node){
6611         this.nodeHash[node.id] = node;
6612     },
6613
6614     unregisterNode : function(node){
6615         delete this.nodeHash[node.id];
6616     },
6617
6618     toString : function(){
6619         return "[Tree"+(this.id?" "+this.id:"")+"]";
6620     }
6621 });
6622
6623 /**
6624  * @class Roo.data.Node
6625  * @extends Roo.util.Observable
6626  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6627  * @cfg {String} id The id for this node. If one is not specified, one is generated.
6628  * @constructor
6629  * @param {Object} attributes The attributes/config for the node
6630  */
6631 Roo.data.Node = function(attributes){
6632     /**
6633      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6634      * @type {Object}
6635      */
6636     this.attributes = attributes || {};
6637     this.leaf = this.attributes.leaf;
6638     /**
6639      * The node id. @type String
6640      */
6641     this.id = this.attributes.id;
6642     if(!this.id){
6643         this.id = Roo.id(null, "ynode-");
6644         this.attributes.id = this.id;
6645     }
6646     /**
6647      * All child nodes of this node. @type Array
6648      */
6649     this.childNodes = [];
6650     if(!this.childNodes.indexOf){ // indexOf is a must
6651         this.childNodes.indexOf = function(o){
6652             for(var i = 0, len = this.length; i < len; i++){
6653                 if(this[i] == o) {
6654                     return i;
6655                 }
6656             }
6657             return -1;
6658         };
6659     }
6660     /**
6661      * The parent node for this node. @type Node
6662      */
6663     this.parentNode = null;
6664     /**
6665      * The first direct child node of this node, or null if this node has no child nodes. @type Node
6666      */
6667     this.firstChild = null;
6668     /**
6669      * The last direct child node of this node, or null if this node has no child nodes. @type Node
6670      */
6671     this.lastChild = null;
6672     /**
6673      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6674      */
6675     this.previousSibling = null;
6676     /**
6677      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6678      */
6679     this.nextSibling = null;
6680
6681     this.addEvents({
6682        /**
6683         * @event append
6684         * Fires when a new child node is appended
6685         * @param {Tree} tree The owner tree
6686         * @param {Node} this This node
6687         * @param {Node} node The newly appended node
6688         * @param {Number} index The index of the newly appended node
6689         */
6690        "append" : true,
6691        /**
6692         * @event remove
6693         * Fires when a child node is removed
6694         * @param {Tree} tree The owner tree
6695         * @param {Node} this This node
6696         * @param {Node} node The removed node
6697         */
6698        "remove" : true,
6699        /**
6700         * @event move
6701         * Fires when this node is moved to a new location in the tree
6702         * @param {Tree} tree The owner tree
6703         * @param {Node} this This node
6704         * @param {Node} oldParent The old parent of this node
6705         * @param {Node} newParent The new parent of this node
6706         * @param {Number} index The index it was moved to
6707         */
6708        "move" : true,
6709        /**
6710         * @event insert
6711         * Fires when a new child node is inserted.
6712         * @param {Tree} tree The owner tree
6713         * @param {Node} this This node
6714         * @param {Node} node The child node inserted
6715         * @param {Node} refNode The child node the node was inserted before
6716         */
6717        "insert" : true,
6718        /**
6719         * @event beforeappend
6720         * Fires before a new child is appended, return false to cancel the append.
6721         * @param {Tree} tree The owner tree
6722         * @param {Node} this This node
6723         * @param {Node} node The child node to be appended
6724         */
6725        "beforeappend" : true,
6726        /**
6727         * @event beforeremove
6728         * Fires before a child is removed, return false to cancel the remove.
6729         * @param {Tree} tree The owner tree
6730         * @param {Node} this This node
6731         * @param {Node} node The child node to be removed
6732         */
6733        "beforeremove" : true,
6734        /**
6735         * @event beforemove
6736         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6737         * @param {Tree} tree The owner tree
6738         * @param {Node} this This node
6739         * @param {Node} oldParent The parent of this node
6740         * @param {Node} newParent The new parent this node is moving to
6741         * @param {Number} index The index it is being moved to
6742         */
6743        "beforemove" : true,
6744        /**
6745         * @event beforeinsert
6746         * Fires before a new child is inserted, return false to cancel the insert.
6747         * @param {Tree} tree The owner tree
6748         * @param {Node} this This node
6749         * @param {Node} node The child node to be inserted
6750         * @param {Node} refNode The child node the node is being inserted before
6751         */
6752        "beforeinsert" : true
6753    });
6754     this.listeners = this.attributes.listeners;
6755     Roo.data.Node.superclass.constructor.call(this);
6756 };
6757
6758 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6759     fireEvent : function(evtName){
6760         // first do standard event for this node
6761         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6762             return false;
6763         }
6764         // then bubble it up to the tree if the event wasn't cancelled
6765         var ot = this.getOwnerTree();
6766         if(ot){
6767             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6768                 return false;
6769             }
6770         }
6771         return true;
6772     },
6773
6774     /**
6775      * Returns true if this node is a leaf
6776      * @return {Boolean}
6777      */
6778     isLeaf : function(){
6779         return this.leaf === true;
6780     },
6781
6782     // private
6783     setFirstChild : function(node){
6784         this.firstChild = node;
6785     },
6786
6787     //private
6788     setLastChild : function(node){
6789         this.lastChild = node;
6790     },
6791
6792
6793     /**
6794      * Returns true if this node is the last child of its parent
6795      * @return {Boolean}
6796      */
6797     isLast : function(){
6798        return (!this.parentNode ? true : this.parentNode.lastChild == this);
6799     },
6800
6801     /**
6802      * Returns true if this node is the first child of its parent
6803      * @return {Boolean}
6804      */
6805     isFirst : function(){
6806        return (!this.parentNode ? true : this.parentNode.firstChild == this);
6807     },
6808
6809     hasChildNodes : function(){
6810         return !this.isLeaf() && this.childNodes.length > 0;
6811     },
6812
6813     /**
6814      * Insert node(s) as the last child node of this node.
6815      * @param {Node/Array} node The node or Array of nodes to append
6816      * @return {Node} The appended node if single append, or null if an array was passed
6817      */
6818     appendChild : function(node){
6819         var multi = false;
6820         if(node instanceof Array){
6821             multi = node;
6822         }else if(arguments.length > 1){
6823             multi = arguments;
6824         }
6825         // if passed an array or multiple args do them one by one
6826         if(multi){
6827             for(var i = 0, len = multi.length; i < len; i++) {
6828                 this.appendChild(multi[i]);
6829             }
6830         }else{
6831             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6832                 return false;
6833             }
6834             var index = this.childNodes.length;
6835             var oldParent = node.parentNode;
6836             // it's a move, make sure we move it cleanly
6837             if(oldParent){
6838                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6839                     return false;
6840                 }
6841                 oldParent.removeChild(node);
6842             }
6843             index = this.childNodes.length;
6844             if(index == 0){
6845                 this.setFirstChild(node);
6846             }
6847             this.childNodes.push(node);
6848             node.parentNode = this;
6849             var ps = this.childNodes[index-1];
6850             if(ps){
6851                 node.previousSibling = ps;
6852                 ps.nextSibling = node;
6853             }else{
6854                 node.previousSibling = null;
6855             }
6856             node.nextSibling = null;
6857             this.setLastChild(node);
6858             node.setOwnerTree(this.getOwnerTree());
6859             this.fireEvent("append", this.ownerTree, this, node, index);
6860             if(oldParent){
6861                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6862             }
6863             return node;
6864         }
6865     },
6866
6867     /**
6868      * Removes a child node from this node.
6869      * @param {Node} node The node to remove
6870      * @return {Node} The removed node
6871      */
6872     removeChild : function(node){
6873         var index = this.childNodes.indexOf(node);
6874         if(index == -1){
6875             return false;
6876         }
6877         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6878             return false;
6879         }
6880
6881         // remove it from childNodes collection
6882         this.childNodes.splice(index, 1);
6883
6884         // update siblings
6885         if(node.previousSibling){
6886             node.previousSibling.nextSibling = node.nextSibling;
6887         }
6888         if(node.nextSibling){
6889             node.nextSibling.previousSibling = node.previousSibling;
6890         }
6891
6892         // update child refs
6893         if(this.firstChild == node){
6894             this.setFirstChild(node.nextSibling);
6895         }
6896         if(this.lastChild == node){
6897             this.setLastChild(node.previousSibling);
6898         }
6899
6900         node.setOwnerTree(null);
6901         // clear any references from the node
6902         node.parentNode = null;
6903         node.previousSibling = null;
6904         node.nextSibling = null;
6905         this.fireEvent("remove", this.ownerTree, this, node);
6906         return node;
6907     },
6908
6909     /**
6910      * Inserts the first node before the second node in this nodes childNodes collection.
6911      * @param {Node} node The node to insert
6912      * @param {Node} refNode The node to insert before (if null the node is appended)
6913      * @return {Node} The inserted node
6914      */
6915     insertBefore : function(node, refNode){
6916         if(!refNode){ // like standard Dom, refNode can be null for append
6917             return this.appendChild(node);
6918         }
6919         // nothing to do
6920         if(node == refNode){
6921             return false;
6922         }
6923
6924         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6925             return false;
6926         }
6927         var index = this.childNodes.indexOf(refNode);
6928         var oldParent = node.parentNode;
6929         var refIndex = index;
6930
6931         // when moving internally, indexes will change after remove
6932         if(oldParent == this && this.childNodes.indexOf(node) < index){
6933             refIndex--;
6934         }
6935
6936         // it's a move, make sure we move it cleanly
6937         if(oldParent){
6938             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6939                 return false;
6940             }
6941             oldParent.removeChild(node);
6942         }
6943         if(refIndex == 0){
6944             this.setFirstChild(node);
6945         }
6946         this.childNodes.splice(refIndex, 0, node);
6947         node.parentNode = this;
6948         var ps = this.childNodes[refIndex-1];
6949         if(ps){
6950             node.previousSibling = ps;
6951             ps.nextSibling = node;
6952         }else{
6953             node.previousSibling = null;
6954         }
6955         node.nextSibling = refNode;
6956         refNode.previousSibling = node;
6957         node.setOwnerTree(this.getOwnerTree());
6958         this.fireEvent("insert", this.ownerTree, this, node, refNode);
6959         if(oldParent){
6960             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6961         }
6962         return node;
6963     },
6964
6965     /**
6966      * Returns the child node at the specified index.
6967      * @param {Number} index
6968      * @return {Node}
6969      */
6970     item : function(index){
6971         return this.childNodes[index];
6972     },
6973
6974     /**
6975      * Replaces one child node in this node with another.
6976      * @param {Node} newChild The replacement node
6977      * @param {Node} oldChild The node to replace
6978      * @return {Node} The replaced node
6979      */
6980     replaceChild : function(newChild, oldChild){
6981         this.insertBefore(newChild, oldChild);
6982         this.removeChild(oldChild);
6983         return oldChild;
6984     },
6985
6986     /**
6987      * Returns the index of a child node
6988      * @param {Node} node
6989      * @return {Number} The index of the node or -1 if it was not found
6990      */
6991     indexOf : function(child){
6992         return this.childNodes.indexOf(child);
6993     },
6994
6995     /**
6996      * Returns the tree this node is in.
6997      * @return {Tree}
6998      */
6999     getOwnerTree : function(){
7000         // if it doesn't have one, look for one
7001         if(!this.ownerTree){
7002             var p = this;
7003             while(p){
7004                 if(p.ownerTree){
7005                     this.ownerTree = p.ownerTree;
7006                     break;
7007                 }
7008                 p = p.parentNode;
7009             }
7010         }
7011         return this.ownerTree;
7012     },
7013
7014     /**
7015      * Returns depth of this node (the root node has a depth of 0)
7016      * @return {Number}
7017      */
7018     getDepth : function(){
7019         var depth = 0;
7020         var p = this;
7021         while(p.parentNode){
7022             ++depth;
7023             p = p.parentNode;
7024         }
7025         return depth;
7026     },
7027
7028     // private
7029     setOwnerTree : function(tree){
7030         // if it's move, we need to update everyone
7031         if(tree != this.ownerTree){
7032             if(this.ownerTree){
7033                 this.ownerTree.unregisterNode(this);
7034             }
7035             this.ownerTree = tree;
7036             var cs = this.childNodes;
7037             for(var i = 0, len = cs.length; i < len; i++) {
7038                 cs[i].setOwnerTree(tree);
7039             }
7040             if(tree){
7041                 tree.registerNode(this);
7042             }
7043         }
7044     },
7045
7046     /**
7047      * Returns the path for this node. The path can be used to expand or select this node programmatically.
7048      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7049      * @return {String} The path
7050      */
7051     getPath : function(attr){
7052         attr = attr || "id";
7053         var p = this.parentNode;
7054         var b = [this.attributes[attr]];
7055         while(p){
7056             b.unshift(p.attributes[attr]);
7057             p = p.parentNode;
7058         }
7059         var sep = this.getOwnerTree().pathSeparator;
7060         return sep + b.join(sep);
7061     },
7062
7063     /**
7064      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7065      * function call will be the scope provided or the current node. The arguments to the function
7066      * will be the args provided or the current node. If the function returns false at any point,
7067      * the bubble is stopped.
7068      * @param {Function} fn The function to call
7069      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7070      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7071      */
7072     bubble : function(fn, scope, args){
7073         var p = this;
7074         while(p){
7075             if(fn.call(scope || p, args || p) === false){
7076                 break;
7077             }
7078             p = p.parentNode;
7079         }
7080     },
7081
7082     /**
7083      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7084      * function call will be the scope provided or the current node. The arguments to the function
7085      * will be the args provided or the current node. If the function returns false at any point,
7086      * the cascade is stopped on that branch.
7087      * @param {Function} fn The function to call
7088      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7089      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7090      */
7091     cascade : function(fn, scope, args){
7092         if(fn.call(scope || this, args || this) !== false){
7093             var cs = this.childNodes;
7094             for(var i = 0, len = cs.length; i < len; i++) {
7095                 cs[i].cascade(fn, scope, args);
7096             }
7097         }
7098     },
7099
7100     /**
7101      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7102      * function call will be the scope provided or the current node. The arguments to the function
7103      * will be the args provided or the current node. If the function returns false at any point,
7104      * the iteration stops.
7105      * @param {Function} fn The function to call
7106      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7107      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7108      */
7109     eachChild : function(fn, scope, args){
7110         var cs = this.childNodes;
7111         for(var i = 0, len = cs.length; i < len; i++) {
7112                 if(fn.call(scope || this, args || cs[i]) === false){
7113                     break;
7114                 }
7115         }
7116     },
7117
7118     /**
7119      * Finds the first child that has the attribute with the specified value.
7120      * @param {String} attribute The attribute name
7121      * @param {Mixed} value The value to search for
7122      * @return {Node} The found child or null if none was found
7123      */
7124     findChild : function(attribute, value){
7125         var cs = this.childNodes;
7126         for(var i = 0, len = cs.length; i < len; i++) {
7127                 if(cs[i].attributes[attribute] == value){
7128                     return cs[i];
7129                 }
7130         }
7131         return null;
7132     },
7133
7134     /**
7135      * Finds the first child by a custom function. The child matches if the function passed
7136      * returns true.
7137      * @param {Function} fn
7138      * @param {Object} scope (optional)
7139      * @return {Node} The found child or null if none was found
7140      */
7141     findChildBy : function(fn, scope){
7142         var cs = this.childNodes;
7143         for(var i = 0, len = cs.length; i < len; i++) {
7144                 if(fn.call(scope||cs[i], cs[i]) === true){
7145                     return cs[i];
7146                 }
7147         }
7148         return null;
7149     },
7150
7151     /**
7152      * Sorts this nodes children using the supplied sort function
7153      * @param {Function} fn
7154      * @param {Object} scope (optional)
7155      */
7156     sort : function(fn, scope){
7157         var cs = this.childNodes;
7158         var len = cs.length;
7159         if(len > 0){
7160             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7161             cs.sort(sortFn);
7162             for(var i = 0; i < len; i++){
7163                 var n = cs[i];
7164                 n.previousSibling = cs[i-1];
7165                 n.nextSibling = cs[i+1];
7166                 if(i == 0){
7167                     this.setFirstChild(n);
7168                 }
7169                 if(i == len-1){
7170                     this.setLastChild(n);
7171                 }
7172             }
7173         }
7174     },
7175
7176     /**
7177      * Returns true if this node is an ancestor (at any point) of the passed node.
7178      * @param {Node} node
7179      * @return {Boolean}
7180      */
7181     contains : function(node){
7182         return node.isAncestor(this);
7183     },
7184
7185     /**
7186      * Returns true if the passed node is an ancestor (at any point) of this node.
7187      * @param {Node} node
7188      * @return {Boolean}
7189      */
7190     isAncestor : function(node){
7191         var p = this.parentNode;
7192         while(p){
7193             if(p == node){
7194                 return true;
7195             }
7196             p = p.parentNode;
7197         }
7198         return false;
7199     },
7200
7201     toString : function(){
7202         return "[Node"+(this.id?" "+this.id:"")+"]";
7203     }
7204 });/*
7205  * Based on:
7206  * Ext JS Library 1.1.1
7207  * Copyright(c) 2006-2007, Ext JS, LLC.
7208  *
7209  * Originally Released Under LGPL - original licence link has changed is not relivant.
7210  *
7211  * Fork - LGPL
7212  * <script type="text/javascript">
7213  */
7214  
7215
7216 /**
7217  * @class Roo.ComponentMgr
7218  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7219  * @singleton
7220  */
7221 Roo.ComponentMgr = function(){
7222     var all = new Roo.util.MixedCollection();
7223
7224     return {
7225         /**
7226          * Registers a component.
7227          * @param {Roo.Component} c The component
7228          */
7229         register : function(c){
7230             all.add(c);
7231         },
7232
7233         /**
7234          * Unregisters a component.
7235          * @param {Roo.Component} c The component
7236          */
7237         unregister : function(c){
7238             all.remove(c);
7239         },
7240
7241         /**
7242          * Returns a component by id
7243          * @param {String} id The component id
7244          */
7245         get : function(id){
7246             return all.get(id);
7247         },
7248
7249         /**
7250          * Registers a function that will be called when a specified component is added to ComponentMgr
7251          * @param {String} id The component id
7252          * @param {Funtction} fn The callback function
7253          * @param {Object} scope The scope of the callback
7254          */
7255         onAvailable : function(id, fn, scope){
7256             all.on("add", function(index, o){
7257                 if(o.id == id){
7258                     fn.call(scope || o, o);
7259                     all.un("add", fn, scope);
7260                 }
7261             });
7262         }
7263     };
7264 }();/*
7265  * Based on:
7266  * Ext JS Library 1.1.1
7267  * Copyright(c) 2006-2007, Ext JS, LLC.
7268  *
7269  * Originally Released Under LGPL - original licence link has changed is not relivant.
7270  *
7271  * Fork - LGPL
7272  * <script type="text/javascript">
7273  */
7274  
7275 /**
7276  * @class Roo.Component
7277  * @extends Roo.util.Observable
7278  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
7279  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
7280  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7281  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7282  * All visual components (widgets) that require rendering into a layout should subclass Component.
7283  * @constructor
7284  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
7285  * 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
7286  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
7287  */
7288 Roo.Component = function(config){
7289     config = config || {};
7290     if(config.tagName || config.dom || typeof config == "string"){ // element object
7291         config = {el: config, id: config.id || config};
7292     }
7293     this.initialConfig = config;
7294
7295     Roo.apply(this, config);
7296     this.addEvents({
7297         /**
7298          * @event disable
7299          * Fires after the component is disabled.
7300              * @param {Roo.Component} this
7301              */
7302         disable : true,
7303         /**
7304          * @event enable
7305          * Fires after the component is enabled.
7306              * @param {Roo.Component} this
7307              */
7308         enable : true,
7309         /**
7310          * @event beforeshow
7311          * Fires before the component is shown.  Return false to stop the show.
7312              * @param {Roo.Component} this
7313              */
7314         beforeshow : true,
7315         /**
7316          * @event show
7317          * Fires after the component is shown.
7318              * @param {Roo.Component} this
7319              */
7320         show : true,
7321         /**
7322          * @event beforehide
7323          * Fires before the component is hidden. Return false to stop the hide.
7324              * @param {Roo.Component} this
7325              */
7326         beforehide : true,
7327         /**
7328          * @event hide
7329          * Fires after the component is hidden.
7330              * @param {Roo.Component} this
7331              */
7332         hide : true,
7333         /**
7334          * @event beforerender
7335          * Fires before the component is rendered. Return false to stop the render.
7336              * @param {Roo.Component} this
7337              */
7338         beforerender : true,
7339         /**
7340          * @event render
7341          * Fires after the component is rendered.
7342              * @param {Roo.Component} this
7343              */
7344         render : true,
7345         /**
7346          * @event beforedestroy
7347          * Fires before the component is destroyed. Return false to stop the destroy.
7348              * @param {Roo.Component} this
7349              */
7350         beforedestroy : true,
7351         /**
7352          * @event destroy
7353          * Fires after the component is destroyed.
7354              * @param {Roo.Component} this
7355              */
7356         destroy : true
7357     });
7358     if(!this.id){
7359         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7360     }
7361     Roo.ComponentMgr.register(this);
7362     Roo.Component.superclass.constructor.call(this);
7363     this.initComponent();
7364     if(this.renderTo){ // not supported by all components yet. use at your own risk!
7365         this.render(this.renderTo);
7366         delete this.renderTo;
7367     }
7368 };
7369
7370 // private
7371 Roo.Component.AUTO_ID = 1000;
7372
7373 Roo.extend(Roo.Component, Roo.util.Observable, {
7374     /**
7375      * @property {Boolean} hidden
7376      * true if this component is hidden. Read-only.
7377      */
7378     hidden : false,
7379     /**
7380      * true if this component is disabled. Read-only.
7381      */
7382     disabled : false,
7383     /**
7384      * true if this component has been rendered. Read-only.
7385      */
7386     rendered : false,
7387     
7388     /** @cfg {String} disableClass
7389      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7390      */
7391     disabledClass : "x-item-disabled",
7392         /** @cfg {Boolean} allowDomMove
7393          * Whether the component can move the Dom node when rendering (defaults to true).
7394          */
7395     allowDomMove : true,
7396     /** @cfg {String} hideMode
7397      * How this component should hidden. Supported values are
7398      * "visibility" (css visibility), "offsets" (negative offset position) and
7399      * "display" (css display) - defaults to "display".
7400      */
7401     hideMode: 'display',
7402
7403     // private
7404     ctype : "Roo.Component",
7405
7406     /** @cfg {String} actionMode 
7407      * which property holds the element that used for  hide() / show() / disable() / enable()
7408      * default is 'el' 
7409      */
7410     actionMode : "el",
7411
7412     // private
7413     getActionEl : function(){
7414         return this[this.actionMode];
7415     },
7416
7417     initComponent : Roo.emptyFn,
7418     /**
7419      * If this is a lazy rendering component, render it to its container element.
7420      * @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.
7421      */
7422     render : function(container, position){
7423         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7424             if(!container && this.el){
7425                 this.el = Roo.get(this.el);
7426                 container = this.el.dom.parentNode;
7427                 this.allowDomMove = false;
7428             }
7429             this.container = Roo.get(container);
7430             this.rendered = true;
7431             if(position !== undefined){
7432                 if(typeof position == 'number'){
7433                     position = this.container.dom.childNodes[position];
7434                 }else{
7435                     position = Roo.getDom(position);
7436                 }
7437             }
7438             this.onRender(this.container, position || null);
7439             if(this.cls){
7440                 this.el.addClass(this.cls);
7441                 delete this.cls;
7442             }
7443             if(this.style){
7444                 this.el.applyStyles(this.style);
7445                 delete this.style;
7446             }
7447             this.fireEvent("render", this);
7448             this.afterRender(this.container);
7449             if(this.hidden){
7450                 this.hide();
7451             }
7452             if(this.disabled){
7453                 this.disable();
7454             }
7455         }
7456         return this;
7457     },
7458
7459     // private
7460     // default function is not really useful
7461     onRender : function(ct, position){
7462         if(this.el){
7463             this.el = Roo.get(this.el);
7464             if(this.allowDomMove !== false){
7465                 ct.dom.insertBefore(this.el.dom, position);
7466             }
7467         }
7468     },
7469
7470     // private
7471     getAutoCreate : function(){
7472         var cfg = typeof this.autoCreate == "object" ?
7473                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7474         if(this.id && !cfg.id){
7475             cfg.id = this.id;
7476         }
7477         return cfg;
7478     },
7479
7480     // private
7481     afterRender : Roo.emptyFn,
7482
7483     /**
7484      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7485      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7486      */
7487     destroy : function(){
7488         if(this.fireEvent("beforedestroy", this) !== false){
7489             this.purgeListeners();
7490             this.beforeDestroy();
7491             if(this.rendered){
7492                 this.el.removeAllListeners();
7493                 this.el.remove();
7494                 if(this.actionMode == "container"){
7495                     this.container.remove();
7496                 }
7497             }
7498             this.onDestroy();
7499             Roo.ComponentMgr.unregister(this);
7500             this.fireEvent("destroy", this);
7501         }
7502     },
7503
7504         // private
7505     beforeDestroy : function(){
7506
7507     },
7508
7509         // private
7510         onDestroy : function(){
7511
7512     },
7513
7514     /**
7515      * Returns the underlying {@link Roo.Element}.
7516      * @return {Roo.Element} The element
7517      */
7518     getEl : function(){
7519         return this.el;
7520     },
7521
7522     /**
7523      * Returns the id of this component.
7524      * @return {String}
7525      */
7526     getId : function(){
7527         return this.id;
7528     },
7529
7530     /**
7531      * Try to focus this component.
7532      * @param {Boolean} selectText True to also select the text in this component (if applicable)
7533      * @return {Roo.Component} this
7534      */
7535     focus : function(selectText){
7536         if(this.rendered){
7537             this.el.focus();
7538             if(selectText === true){
7539                 this.el.dom.select();
7540             }
7541         }
7542         return this;
7543     },
7544
7545     // private
7546     blur : function(){
7547         if(this.rendered){
7548             this.el.blur();
7549         }
7550         return this;
7551     },
7552
7553     /**
7554      * Disable this component.
7555      * @return {Roo.Component} this
7556      */
7557     disable : function(){
7558         if(this.rendered){
7559             this.onDisable();
7560         }
7561         this.disabled = true;
7562         this.fireEvent("disable", this);
7563         return this;
7564     },
7565
7566         // private
7567     onDisable : function(){
7568         this.getActionEl().addClass(this.disabledClass);
7569         this.el.dom.disabled = true;
7570     },
7571
7572     /**
7573      * Enable this component.
7574      * @return {Roo.Component} this
7575      */
7576     enable : function(){
7577         if(this.rendered){
7578             this.onEnable();
7579         }
7580         this.disabled = false;
7581         this.fireEvent("enable", this);
7582         return this;
7583     },
7584
7585         // private
7586     onEnable : function(){
7587         this.getActionEl().removeClass(this.disabledClass);
7588         this.el.dom.disabled = false;
7589     },
7590
7591     /**
7592      * Convenience function for setting disabled/enabled by boolean.
7593      * @param {Boolean} disabled
7594      */
7595     setDisabled : function(disabled){
7596         this[disabled ? "disable" : "enable"]();
7597     },
7598
7599     /**
7600      * Show this component.
7601      * @return {Roo.Component} this
7602      */
7603     show: function(){
7604         if(this.fireEvent("beforeshow", this) !== false){
7605             this.hidden = false;
7606             if(this.rendered){
7607                 this.onShow();
7608             }
7609             this.fireEvent("show", this);
7610         }
7611         return this;
7612     },
7613
7614     // private
7615     onShow : function(){
7616         var ae = this.getActionEl();
7617         if(this.hideMode == 'visibility'){
7618             ae.dom.style.visibility = "visible";
7619         }else if(this.hideMode == 'offsets'){
7620             ae.removeClass('x-hidden');
7621         }else{
7622             ae.dom.style.display = "";
7623         }
7624     },
7625
7626     /**
7627      * Hide this component.
7628      * @return {Roo.Component} this
7629      */
7630     hide: function(){
7631         if(this.fireEvent("beforehide", this) !== false){
7632             this.hidden = true;
7633             if(this.rendered){
7634                 this.onHide();
7635             }
7636             this.fireEvent("hide", this);
7637         }
7638         return this;
7639     },
7640
7641     // private
7642     onHide : function(){
7643         var ae = this.getActionEl();
7644         if(this.hideMode == 'visibility'){
7645             ae.dom.style.visibility = "hidden";
7646         }else if(this.hideMode == 'offsets'){
7647             ae.addClass('x-hidden');
7648         }else{
7649             ae.dom.style.display = "none";
7650         }
7651     },
7652
7653     /**
7654      * Convenience function to hide or show this component by boolean.
7655      * @param {Boolean} visible True to show, false to hide
7656      * @return {Roo.Component} this
7657      */
7658     setVisible: function(visible){
7659         if(visible) {
7660             this.show();
7661         }else{
7662             this.hide();
7663         }
7664         return this;
7665     },
7666
7667     /**
7668      * Returns true if this component is visible.
7669      */
7670     isVisible : function(){
7671         return this.getActionEl().isVisible();
7672     },
7673
7674     cloneConfig : function(overrides){
7675         overrides = overrides || {};
7676         var id = overrides.id || Roo.id();
7677         var cfg = Roo.applyIf(overrides, this.initialConfig);
7678         cfg.id = id; // prevent dup id
7679         return new this.constructor(cfg);
7680     }
7681 });/*
7682  * Based on:
7683  * Ext JS Library 1.1.1
7684  * Copyright(c) 2006-2007, Ext JS, LLC.
7685  *
7686  * Originally Released Under LGPL - original licence link has changed is not relivant.
7687  *
7688  * Fork - LGPL
7689  * <script type="text/javascript">
7690  */
7691  (function(){ 
7692 /**
7693  * @class Roo.Layer
7694  * @extends Roo.Element
7695  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7696  * automatic maintaining of shadow/shim positions.
7697  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7698  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7699  * you can pass a string with a CSS class name. False turns off the shadow.
7700  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7701  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7702  * @cfg {String} cls CSS class to add to the element
7703  * @cfg {Number} zindex Starting z-index (defaults to 11000)
7704  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7705  * @constructor
7706  * @param {Object} config An object with config options.
7707  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7708  */
7709
7710 Roo.Layer = function(config, existingEl){
7711     config = config || {};
7712     var dh = Roo.DomHelper;
7713     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7714     if(existingEl){
7715         this.dom = Roo.getDom(existingEl);
7716     }
7717     if(!this.dom){
7718         var o = config.dh || {tag: "div", cls: "x-layer"};
7719         this.dom = dh.append(pel, o);
7720     }
7721     if(config.cls){
7722         this.addClass(config.cls);
7723     }
7724     this.constrain = config.constrain !== false;
7725     this.visibilityMode = Roo.Element.VISIBILITY;
7726     if(config.id){
7727         this.id = this.dom.id = config.id;
7728     }else{
7729         this.id = Roo.id(this.dom);
7730     }
7731     this.zindex = config.zindex || this.getZIndex();
7732     this.position("absolute", this.zindex);
7733     if(config.shadow){
7734         this.shadowOffset = config.shadowOffset || 4;
7735         this.shadow = new Roo.Shadow({
7736             offset : this.shadowOffset,
7737             mode : config.shadow
7738         });
7739     }else{
7740         this.shadowOffset = 0;
7741     }
7742     this.useShim = config.shim !== false && Roo.useShims;
7743     this.useDisplay = config.useDisplay;
7744     this.hide();
7745 };
7746
7747 var supr = Roo.Element.prototype;
7748
7749 // shims are shared among layer to keep from having 100 iframes
7750 var shims = [];
7751
7752 Roo.extend(Roo.Layer, Roo.Element, {
7753
7754     getZIndex : function(){
7755         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7756     },
7757
7758     getShim : function(){
7759         if(!this.useShim){
7760             return null;
7761         }
7762         if(this.shim){
7763             return this.shim;
7764         }
7765         var shim = shims.shift();
7766         if(!shim){
7767             shim = this.createShim();
7768             shim.enableDisplayMode('block');
7769             shim.dom.style.display = 'none';
7770             shim.dom.style.visibility = 'visible';
7771         }
7772         var pn = this.dom.parentNode;
7773         if(shim.dom.parentNode != pn){
7774             pn.insertBefore(shim.dom, this.dom);
7775         }
7776         shim.setStyle('z-index', this.getZIndex()-2);
7777         this.shim = shim;
7778         return shim;
7779     },
7780
7781     hideShim : function(){
7782         if(this.shim){
7783             this.shim.setDisplayed(false);
7784             shims.push(this.shim);
7785             delete this.shim;
7786         }
7787     },
7788
7789     disableShadow : function(){
7790         if(this.shadow){
7791             this.shadowDisabled = true;
7792             this.shadow.hide();
7793             this.lastShadowOffset = this.shadowOffset;
7794             this.shadowOffset = 0;
7795         }
7796     },
7797
7798     enableShadow : function(show){
7799         if(this.shadow){
7800             this.shadowDisabled = false;
7801             this.shadowOffset = this.lastShadowOffset;
7802             delete this.lastShadowOffset;
7803             if(show){
7804                 this.sync(true);
7805             }
7806         }
7807     },
7808
7809     // private
7810     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7811     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7812     sync : function(doShow){
7813         var sw = this.shadow;
7814         if(!this.updating && this.isVisible() && (sw || this.useShim)){
7815             var sh = this.getShim();
7816
7817             var w = this.getWidth(),
7818                 h = this.getHeight();
7819
7820             var l = this.getLeft(true),
7821                 t = this.getTop(true);
7822
7823             if(sw && !this.shadowDisabled){
7824                 if(doShow && !sw.isVisible()){
7825                     sw.show(this);
7826                 }else{
7827                     sw.realign(l, t, w, h);
7828                 }
7829                 if(sh){
7830                     if(doShow){
7831                        sh.show();
7832                     }
7833                     // fit the shim behind the shadow, so it is shimmed too
7834                     var a = sw.adjusts, s = sh.dom.style;
7835                     s.left = (Math.min(l, l+a.l))+"px";
7836                     s.top = (Math.min(t, t+a.t))+"px";
7837                     s.width = (w+a.w)+"px";
7838                     s.height = (h+a.h)+"px";
7839                 }
7840             }else if(sh){
7841                 if(doShow){
7842                    sh.show();
7843                 }
7844                 sh.setSize(w, h);
7845                 sh.setLeftTop(l, t);
7846             }
7847             
7848         }
7849     },
7850
7851     // private
7852     destroy : function(){
7853         this.hideShim();
7854         if(this.shadow){
7855             this.shadow.hide();
7856         }
7857         this.removeAllListeners();
7858         var pn = this.dom.parentNode;
7859         if(pn){
7860             pn.removeChild(this.dom);
7861         }
7862         Roo.Element.uncache(this.id);
7863     },
7864
7865     remove : function(){
7866         this.destroy();
7867     },
7868
7869     // private
7870     beginUpdate : function(){
7871         this.updating = true;
7872     },
7873
7874     // private
7875     endUpdate : function(){
7876         this.updating = false;
7877         this.sync(true);
7878     },
7879
7880     // private
7881     hideUnders : function(negOffset){
7882         if(this.shadow){
7883             this.shadow.hide();
7884         }
7885         this.hideShim();
7886     },
7887
7888     // private
7889     constrainXY : function(){
7890         if(this.constrain){
7891             var vw = Roo.lib.Dom.getViewWidth(),
7892                 vh = Roo.lib.Dom.getViewHeight();
7893             var s = Roo.get(document).getScroll();
7894
7895             var xy = this.getXY();
7896             var x = xy[0], y = xy[1];   
7897             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7898             // only move it if it needs it
7899             var moved = false;
7900             // first validate right/bottom
7901             if((x + w) > vw+s.left){
7902                 x = vw - w - this.shadowOffset;
7903                 moved = true;
7904             }
7905             if((y + h) > vh+s.top){
7906                 y = vh - h - this.shadowOffset;
7907                 moved = true;
7908             }
7909             // then make sure top/left isn't negative
7910             if(x < s.left){
7911                 x = s.left;
7912                 moved = true;
7913             }
7914             if(y < s.top){
7915                 y = s.top;
7916                 moved = true;
7917             }
7918             if(moved){
7919                 if(this.avoidY){
7920                     var ay = this.avoidY;
7921                     if(y <= ay && (y+h) >= ay){
7922                         y = ay-h-5;   
7923                     }
7924                 }
7925                 xy = [x, y];
7926                 this.storeXY(xy);
7927                 supr.setXY.call(this, xy);
7928                 this.sync();
7929             }
7930         }
7931     },
7932
7933     isVisible : function(){
7934         return this.visible;    
7935     },
7936
7937     // private
7938     showAction : function(){
7939         this.visible = true; // track visibility to prevent getStyle calls
7940         if(this.useDisplay === true){
7941             this.setDisplayed("");
7942         }else if(this.lastXY){
7943             supr.setXY.call(this, this.lastXY);
7944         }else if(this.lastLT){
7945             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7946         }
7947     },
7948
7949     // private
7950     hideAction : function(){
7951         this.visible = false;
7952         if(this.useDisplay === true){
7953             this.setDisplayed(false);
7954         }else{
7955             this.setLeftTop(-10000,-10000);
7956         }
7957     },
7958
7959     // overridden Element method
7960     setVisible : function(v, a, d, c, e){
7961         if(v){
7962             this.showAction();
7963         }
7964         if(a && v){
7965             var cb = function(){
7966                 this.sync(true);
7967                 if(c){
7968                     c();
7969                 }
7970             }.createDelegate(this);
7971             supr.setVisible.call(this, true, true, d, cb, e);
7972         }else{
7973             if(!v){
7974                 this.hideUnders(true);
7975             }
7976             var cb = c;
7977             if(a){
7978                 cb = function(){
7979                     this.hideAction();
7980                     if(c){
7981                         c();
7982                     }
7983                 }.createDelegate(this);
7984             }
7985             supr.setVisible.call(this, v, a, d, cb, e);
7986             if(v){
7987                 this.sync(true);
7988             }else if(!a){
7989                 this.hideAction();
7990             }
7991         }
7992     },
7993
7994     storeXY : function(xy){
7995         delete this.lastLT;
7996         this.lastXY = xy;
7997     },
7998
7999     storeLeftTop : function(left, top){
8000         delete this.lastXY;
8001         this.lastLT = [left, top];
8002     },
8003
8004     // private
8005     beforeFx : function(){
8006         this.beforeAction();
8007         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8008     },
8009
8010     // private
8011     afterFx : function(){
8012         Roo.Layer.superclass.afterFx.apply(this, arguments);
8013         this.sync(this.isVisible());
8014     },
8015
8016     // private
8017     beforeAction : function(){
8018         if(!this.updating && this.shadow){
8019             this.shadow.hide();
8020         }
8021     },
8022
8023     // overridden Element method
8024     setLeft : function(left){
8025         this.storeLeftTop(left, this.getTop(true));
8026         supr.setLeft.apply(this, arguments);
8027         this.sync();
8028     },
8029
8030     setTop : function(top){
8031         this.storeLeftTop(this.getLeft(true), top);
8032         supr.setTop.apply(this, arguments);
8033         this.sync();
8034     },
8035
8036     setLeftTop : function(left, top){
8037         this.storeLeftTop(left, top);
8038         supr.setLeftTop.apply(this, arguments);
8039         this.sync();
8040     },
8041
8042     setXY : function(xy, a, d, c, e){
8043         this.fixDisplay();
8044         this.beforeAction();
8045         this.storeXY(xy);
8046         var cb = this.createCB(c);
8047         supr.setXY.call(this, xy, a, d, cb, e);
8048         if(!a){
8049             cb();
8050         }
8051     },
8052
8053     // private
8054     createCB : function(c){
8055         var el = this;
8056         return function(){
8057             el.constrainXY();
8058             el.sync(true);
8059             if(c){
8060                 c();
8061             }
8062         };
8063     },
8064
8065     // overridden Element method
8066     setX : function(x, a, d, c, e){
8067         this.setXY([x, this.getY()], a, d, c, e);
8068     },
8069
8070     // overridden Element method
8071     setY : function(y, a, d, c, e){
8072         this.setXY([this.getX(), y], a, d, c, e);
8073     },
8074
8075     // overridden Element method
8076     setSize : function(w, h, a, d, c, e){
8077         this.beforeAction();
8078         var cb = this.createCB(c);
8079         supr.setSize.call(this, w, h, a, d, cb, e);
8080         if(!a){
8081             cb();
8082         }
8083     },
8084
8085     // overridden Element method
8086     setWidth : function(w, a, d, c, e){
8087         this.beforeAction();
8088         var cb = this.createCB(c);
8089         supr.setWidth.call(this, w, a, d, cb, e);
8090         if(!a){
8091             cb();
8092         }
8093     },
8094
8095     // overridden Element method
8096     setHeight : function(h, a, d, c, e){
8097         this.beforeAction();
8098         var cb = this.createCB(c);
8099         supr.setHeight.call(this, h, a, d, cb, e);
8100         if(!a){
8101             cb();
8102         }
8103     },
8104
8105     // overridden Element method
8106     setBounds : function(x, y, w, h, a, d, c, e){
8107         this.beforeAction();
8108         var cb = this.createCB(c);
8109         if(!a){
8110             this.storeXY([x, y]);
8111             supr.setXY.call(this, [x, y]);
8112             supr.setSize.call(this, w, h, a, d, cb, e);
8113             cb();
8114         }else{
8115             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8116         }
8117         return this;
8118     },
8119     
8120     /**
8121      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8122      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8123      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8124      * @param {Number} zindex The new z-index to set
8125      * @return {this} The Layer
8126      */
8127     setZIndex : function(zindex){
8128         this.zindex = zindex;
8129         this.setStyle("z-index", zindex + 2);
8130         if(this.shadow){
8131             this.shadow.setZIndex(zindex + 1);
8132         }
8133         if(this.shim){
8134             this.shim.setStyle("z-index", zindex);
8135         }
8136     }
8137 });
8138 })();/*
8139  * Based on:
8140  * Ext JS Library 1.1.1
8141  * Copyright(c) 2006-2007, Ext JS, LLC.
8142  *
8143  * Originally Released Under LGPL - original licence link has changed is not relivant.
8144  *
8145  * Fork - LGPL
8146  * <script type="text/javascript">
8147  */
8148
8149
8150 /**
8151  * @class Roo.Shadow
8152  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
8153  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
8154  * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8155  * @constructor
8156  * Create a new Shadow
8157  * @param {Object} config The config object
8158  */
8159 Roo.Shadow = function(config){
8160     Roo.apply(this, config);
8161     if(typeof this.mode != "string"){
8162         this.mode = this.defaultMode;
8163     }
8164     var o = this.offset, a = {h: 0};
8165     var rad = Math.floor(this.offset/2);
8166     switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8167         case "drop":
8168             a.w = 0;
8169             a.l = a.t = o;
8170             a.t -= 1;
8171             if(Roo.isIE){
8172                 a.l -= this.offset + rad;
8173                 a.t -= this.offset + rad;
8174                 a.w -= rad;
8175                 a.h -= rad;
8176                 a.t += 1;
8177             }
8178         break;
8179         case "sides":
8180             a.w = (o*2);
8181             a.l = -o;
8182             a.t = o-1;
8183             if(Roo.isIE){
8184                 a.l -= (this.offset - rad);
8185                 a.t -= this.offset + rad;
8186                 a.l += 1;
8187                 a.w -= (this.offset - rad)*2;
8188                 a.w -= rad + 1;
8189                 a.h -= 1;
8190             }
8191         break;
8192         case "frame":
8193             a.w = a.h = (o*2);
8194             a.l = a.t = -o;
8195             a.t += 1;
8196             a.h -= 2;
8197             if(Roo.isIE){
8198                 a.l -= (this.offset - rad);
8199                 a.t -= (this.offset - rad);
8200                 a.l += 1;
8201                 a.w -= (this.offset + rad + 1);
8202                 a.h -= (this.offset + rad);
8203                 a.h += 1;
8204             }
8205         break;
8206     };
8207
8208     this.adjusts = a;
8209 };
8210
8211 Roo.Shadow.prototype = {
8212     /**
8213      * @cfg {String} mode
8214      * The shadow display mode.  Supports the following options:<br />
8215      * sides: Shadow displays on both sides and bottom only<br />
8216      * frame: Shadow displays equally on all four sides<br />
8217      * drop: Traditional bottom-right drop shadow (default)
8218      */
8219     /**
8220      * @cfg {String} offset
8221      * The number of pixels to offset the shadow from the element (defaults to 4)
8222      */
8223     offset: 4,
8224
8225     // private
8226     defaultMode: "drop",
8227
8228     /**
8229      * Displays the shadow under the target element
8230      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8231      */
8232     show : function(target){
8233         target = Roo.get(target);
8234         if(!this.el){
8235             this.el = Roo.Shadow.Pool.pull();
8236             if(this.el.dom.nextSibling != target.dom){
8237                 this.el.insertBefore(target);
8238             }
8239         }
8240         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8241         if(Roo.isIE){
8242             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8243         }
8244         this.realign(
8245             target.getLeft(true),
8246             target.getTop(true),
8247             target.getWidth(),
8248             target.getHeight()
8249         );
8250         this.el.dom.style.display = "block";
8251     },
8252
8253     /**
8254      * Returns true if the shadow is visible, else false
8255      */
8256     isVisible : function(){
8257         return this.el ? true : false;  
8258     },
8259
8260     /**
8261      * Direct alignment when values are already available. Show must be called at least once before
8262      * calling this method to ensure it is initialized.
8263      * @param {Number} left The target element left position
8264      * @param {Number} top The target element top position
8265      * @param {Number} width The target element width
8266      * @param {Number} height The target element height
8267      */
8268     realign : function(l, t, w, h){
8269         if(!this.el){
8270             return;
8271         }
8272         var a = this.adjusts, d = this.el.dom, s = d.style;
8273         var iea = 0;
8274         s.left = (l+a.l)+"px";
8275         s.top = (t+a.t)+"px";
8276         var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8277  
8278         if(s.width != sws || s.height != shs){
8279             s.width = sws;
8280             s.height = shs;
8281             if(!Roo.isIE){
8282                 var cn = d.childNodes;
8283                 var sww = Math.max(0, (sw-12))+"px";
8284                 cn[0].childNodes[1].style.width = sww;
8285                 cn[1].childNodes[1].style.width = sww;
8286                 cn[2].childNodes[1].style.width = sww;
8287                 cn[1].style.height = Math.max(0, (sh-12))+"px";
8288             }
8289         }
8290     },
8291
8292     /**
8293      * Hides this shadow
8294      */
8295     hide : function(){
8296         if(this.el){
8297             this.el.dom.style.display = "none";
8298             Roo.Shadow.Pool.push(this.el);
8299             delete this.el;
8300         }
8301     },
8302
8303     /**
8304      * Adjust the z-index of this shadow
8305      * @param {Number} zindex The new z-index
8306      */
8307     setZIndex : function(z){
8308         this.zIndex = z;
8309         if(this.el){
8310             this.el.setStyle("z-index", z);
8311         }
8312     }
8313 };
8314
8315 // Private utility class that manages the internal Shadow cache
8316 Roo.Shadow.Pool = function(){
8317     var p = [];
8318     var markup = Roo.isIE ?
8319                  '<div class="x-ie-shadow"></div>' :
8320                  '<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>';
8321     return {
8322         pull : function(){
8323             var sh = p.shift();
8324             if(!sh){
8325                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8326                 sh.autoBoxAdjust = false;
8327             }
8328             return sh;
8329         },
8330
8331         push : function(sh){
8332             p.push(sh);
8333         }
8334     };
8335 }();/*
8336  * Based on:
8337  * Ext JS Library 1.1.1
8338  * Copyright(c) 2006-2007, Ext JS, LLC.
8339  *
8340  * Originally Released Under LGPL - original licence link has changed is not relivant.
8341  *
8342  * Fork - LGPL
8343  * <script type="text/javascript">
8344  */
8345
8346 /**
8347  * @class Roo.BoxComponent
8348  * @extends Roo.Component
8349  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
8350  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
8351  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8352  * layout containers.
8353  * @constructor
8354  * @param {Roo.Element/String/Object} config The configuration options.
8355  */
8356 Roo.BoxComponent = function(config){
8357     Roo.Component.call(this, config);
8358     this.addEvents({
8359         /**
8360          * @event resize
8361          * Fires after the component is resized.
8362              * @param {Roo.Component} this
8363              * @param {Number} adjWidth The box-adjusted width that was set
8364              * @param {Number} adjHeight The box-adjusted height that was set
8365              * @param {Number} rawWidth The width that was originally specified
8366              * @param {Number} rawHeight The height that was originally specified
8367              */
8368         resize : true,
8369         /**
8370          * @event move
8371          * Fires after the component is moved.
8372              * @param {Roo.Component} this
8373              * @param {Number} x The new x position
8374              * @param {Number} y The new y position
8375              */
8376         move : true
8377     });
8378 };
8379
8380 Roo.extend(Roo.BoxComponent, Roo.Component, {
8381     // private, set in afterRender to signify that the component has been rendered
8382     boxReady : false,
8383     // private, used to defer height settings to subclasses
8384     deferHeight: false,
8385     /** @cfg {Number} width
8386      * width (optional) size of component
8387      */
8388      /** @cfg {Number} height
8389      * height (optional) size of component
8390      */
8391      
8392     /**
8393      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
8394      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8395      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8396      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8397      * @return {Roo.BoxComponent} this
8398      */
8399     setSize : function(w, h){
8400         // support for standard size objects
8401         if(typeof w == 'object'){
8402             h = w.height;
8403             w = w.width;
8404         }
8405         // not rendered
8406         if(!this.boxReady){
8407             this.width = w;
8408             this.height = h;
8409             return this;
8410         }
8411
8412         // prevent recalcs when not needed
8413         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8414             return this;
8415         }
8416         this.lastSize = {width: w, height: h};
8417
8418         var adj = this.adjustSize(w, h);
8419         var aw = adj.width, ah = adj.height;
8420         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8421             var rz = this.getResizeEl();
8422             if(!this.deferHeight && aw !== undefined && ah !== undefined){
8423                 rz.setSize(aw, ah);
8424             }else if(!this.deferHeight && ah !== undefined){
8425                 rz.setHeight(ah);
8426             }else if(aw !== undefined){
8427                 rz.setWidth(aw);
8428             }
8429             this.onResize(aw, ah, w, h);
8430             this.fireEvent('resize', this, aw, ah, w, h);
8431         }
8432         return this;
8433     },
8434
8435     /**
8436      * Gets the current size of the component's underlying element.
8437      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8438      */
8439     getSize : function(){
8440         return this.el.getSize();
8441     },
8442
8443     /**
8444      * Gets the current XY position of the component's underlying element.
8445      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8446      * @return {Array} The XY position of the element (e.g., [100, 200])
8447      */
8448     getPosition : function(local){
8449         if(local === true){
8450             return [this.el.getLeft(true), this.el.getTop(true)];
8451         }
8452         return this.xy || this.el.getXY();
8453     },
8454
8455     /**
8456      * Gets the current box measurements of the component's underlying element.
8457      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8458      * @returns {Object} box An object in the format {x, y, width, height}
8459      */
8460     getBox : function(local){
8461         var s = this.el.getSize();
8462         if(local){
8463             s.x = this.el.getLeft(true);
8464             s.y = this.el.getTop(true);
8465         }else{
8466             var xy = this.xy || this.el.getXY();
8467             s.x = xy[0];
8468             s.y = xy[1];
8469         }
8470         return s;
8471     },
8472
8473     /**
8474      * Sets the current box measurements of the component's underlying element.
8475      * @param {Object} box An object in the format {x, y, width, height}
8476      * @returns {Roo.BoxComponent} this
8477      */
8478     updateBox : function(box){
8479         this.setSize(box.width, box.height);
8480         this.setPagePosition(box.x, box.y);
8481         return this;
8482     },
8483
8484     // protected
8485     getResizeEl : function(){
8486         return this.resizeEl || this.el;
8487     },
8488
8489     // protected
8490     getPositionEl : function(){
8491         return this.positionEl || this.el;
8492     },
8493
8494     /**
8495      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
8496      * This method fires the move event.
8497      * @param {Number} left The new left
8498      * @param {Number} top The new top
8499      * @returns {Roo.BoxComponent} this
8500      */
8501     setPosition : function(x, y){
8502         this.x = x;
8503         this.y = y;
8504         if(!this.boxReady){
8505             return this;
8506         }
8507         var adj = this.adjustPosition(x, y);
8508         var ax = adj.x, ay = adj.y;
8509
8510         var el = this.getPositionEl();
8511         if(ax !== undefined || ay !== undefined){
8512             if(ax !== undefined && ay !== undefined){
8513                 el.setLeftTop(ax, ay);
8514             }else if(ax !== undefined){
8515                 el.setLeft(ax);
8516             }else if(ay !== undefined){
8517                 el.setTop(ay);
8518             }
8519             this.onPosition(ax, ay);
8520             this.fireEvent('move', this, ax, ay);
8521         }
8522         return this;
8523     },
8524
8525     /**
8526      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
8527      * This method fires the move event.
8528      * @param {Number} x The new x position
8529      * @param {Number} y The new y position
8530      * @returns {Roo.BoxComponent} this
8531      */
8532     setPagePosition : function(x, y){
8533         this.pageX = x;
8534         this.pageY = y;
8535         if(!this.boxReady){
8536             return;
8537         }
8538         if(x === undefined || y === undefined){ // cannot translate undefined points
8539             return;
8540         }
8541         var p = this.el.translatePoints(x, y);
8542         this.setPosition(p.left, p.top);
8543         return this;
8544     },
8545
8546     // private
8547     onRender : function(ct, position){
8548         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8549         if(this.resizeEl){
8550             this.resizeEl = Roo.get(this.resizeEl);
8551         }
8552         if(this.positionEl){
8553             this.positionEl = Roo.get(this.positionEl);
8554         }
8555     },
8556
8557     // private
8558     afterRender : function(){
8559         Roo.BoxComponent.superclass.afterRender.call(this);
8560         this.boxReady = true;
8561         this.setSize(this.width, this.height);
8562         if(this.x || this.y){
8563             this.setPosition(this.x, this.y);
8564         }
8565         if(this.pageX || this.pageY){
8566             this.setPagePosition(this.pageX, this.pageY);
8567         }
8568     },
8569
8570     /**
8571      * Force the component's size to recalculate based on the underlying element's current height and width.
8572      * @returns {Roo.BoxComponent} this
8573      */
8574     syncSize : function(){
8575         delete this.lastSize;
8576         this.setSize(this.el.getWidth(), this.el.getHeight());
8577         return this;
8578     },
8579
8580     /**
8581      * Called after the component is resized, this method is empty by default but can be implemented by any
8582      * subclass that needs to perform custom logic after a resize occurs.
8583      * @param {Number} adjWidth The box-adjusted width that was set
8584      * @param {Number} adjHeight The box-adjusted height that was set
8585      * @param {Number} rawWidth The width that was originally specified
8586      * @param {Number} rawHeight The height that was originally specified
8587      */
8588     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8589
8590     },
8591
8592     /**
8593      * Called after the component is moved, this method is empty by default but can be implemented by any
8594      * subclass that needs to perform custom logic after a move occurs.
8595      * @param {Number} x The new x position
8596      * @param {Number} y The new y position
8597      */
8598     onPosition : function(x, y){
8599
8600     },
8601
8602     // private
8603     adjustSize : function(w, h){
8604         if(this.autoWidth){
8605             w = 'auto';
8606         }
8607         if(this.autoHeight){
8608             h = 'auto';
8609         }
8610         return {width : w, height: h};
8611     },
8612
8613     // private
8614     adjustPosition : function(x, y){
8615         return {x : x, y: y};
8616     }
8617 });/*
8618  * Based on:
8619  * Ext JS Library 1.1.1
8620  * Copyright(c) 2006-2007, Ext JS, LLC.
8621  *
8622  * Originally Released Under LGPL - original licence link has changed is not relivant.
8623  *
8624  * Fork - LGPL
8625  * <script type="text/javascript">
8626  */
8627
8628
8629 /**
8630  * @class Roo.SplitBar
8631  * @extends Roo.util.Observable
8632  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8633  * <br><br>
8634  * Usage:
8635  * <pre><code>
8636 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8637                    Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8638 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8639 split.minSize = 100;
8640 split.maxSize = 600;
8641 split.animate = true;
8642 split.on('moved', splitterMoved);
8643 </code></pre>
8644  * @constructor
8645  * Create a new SplitBar
8646  * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
8647  * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
8648  * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8649  * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
8650                         Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8651                         position of the SplitBar).
8652  */
8653 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8654     
8655     /** @private */
8656     this.el = Roo.get(dragElement, true);
8657     this.el.dom.unselectable = "on";
8658     /** @private */
8659     this.resizingEl = Roo.get(resizingElement, true);
8660
8661     /**
8662      * @private
8663      * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8664      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8665      * @type Number
8666      */
8667     this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8668     
8669     /**
8670      * The minimum size of the resizing element. (Defaults to 0)
8671      * @type Number
8672      */
8673     this.minSize = 0;
8674     
8675     /**
8676      * The maximum size of the resizing element. (Defaults to 2000)
8677      * @type Number
8678      */
8679     this.maxSize = 2000;
8680     
8681     /**
8682      * Whether to animate the transition to the new size
8683      * @type Boolean
8684      */
8685     this.animate = false;
8686     
8687     /**
8688      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8689      * @type Boolean
8690      */
8691     this.useShim = false;
8692     
8693     /** @private */
8694     this.shim = null;
8695     
8696     if(!existingProxy){
8697         /** @private */
8698         this.proxy = Roo.SplitBar.createProxy(this.orientation);
8699     }else{
8700         this.proxy = Roo.get(existingProxy).dom;
8701     }
8702     /** @private */
8703     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8704     
8705     /** @private */
8706     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8707     
8708     /** @private */
8709     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8710     
8711     /** @private */
8712     this.dragSpecs = {};
8713     
8714     /**
8715      * @private The adapter to use to positon and resize elements
8716      */
8717     this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8718     this.adapter.init(this);
8719     
8720     if(this.orientation == Roo.SplitBar.HORIZONTAL){
8721         /** @private */
8722         this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8723         this.el.addClass("x-splitbar-h");
8724     }else{
8725         /** @private */
8726         this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8727         this.el.addClass("x-splitbar-v");
8728     }
8729     
8730     this.addEvents({
8731         /**
8732          * @event resize
8733          * Fires when the splitter is moved (alias for {@link #event-moved})
8734          * @param {Roo.SplitBar} this
8735          * @param {Number} newSize the new width or height
8736          */
8737         "resize" : true,
8738         /**
8739          * @event moved
8740          * Fires when the splitter is moved
8741          * @param {Roo.SplitBar} this
8742          * @param {Number} newSize the new width or height
8743          */
8744         "moved" : true,
8745         /**
8746          * @event beforeresize
8747          * Fires before the splitter is dragged
8748          * @param {Roo.SplitBar} this
8749          */
8750         "beforeresize" : true,
8751
8752         "beforeapply" : true
8753     });
8754
8755     Roo.util.Observable.call(this);
8756 };
8757
8758 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8759     onStartProxyDrag : function(x, y){
8760         this.fireEvent("beforeresize", this);
8761         if(!this.overlay){
8762             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
8763             o.unselectable();
8764             o.enableDisplayMode("block");
8765             // all splitbars share the same overlay
8766             Roo.SplitBar.prototype.overlay = o;
8767         }
8768         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8769         this.overlay.show();
8770         Roo.get(this.proxy).setDisplayed("block");
8771         var size = this.adapter.getElementSize(this);
8772         this.activeMinSize = this.getMinimumSize();;
8773         this.activeMaxSize = this.getMaximumSize();;
8774         var c1 = size - this.activeMinSize;
8775         var c2 = Math.max(this.activeMaxSize - size, 0);
8776         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8777             this.dd.resetConstraints();
8778             this.dd.setXConstraint(
8779                 this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
8780                 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8781             );
8782             this.dd.setYConstraint(0, 0);
8783         }else{
8784             this.dd.resetConstraints();
8785             this.dd.setXConstraint(0, 0);
8786             this.dd.setYConstraint(
8787                 this.placement == Roo.SplitBar.TOP ? c1 : c2, 
8788                 this.placement == Roo.SplitBar.TOP ? c2 : c1
8789             );
8790          }
8791         this.dragSpecs.startSize = size;
8792         this.dragSpecs.startPoint = [x, y];
8793         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8794     },
8795     
8796     /** 
8797      * @private Called after the drag operation by the DDProxy
8798      */
8799     onEndProxyDrag : function(e){
8800         Roo.get(this.proxy).setDisplayed(false);
8801         var endPoint = Roo.lib.Event.getXY(e);
8802         if(this.overlay){
8803             this.overlay.hide();
8804         }
8805         var newSize;
8806         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8807             newSize = this.dragSpecs.startSize + 
8808                 (this.placement == Roo.SplitBar.LEFT ?
8809                     endPoint[0] - this.dragSpecs.startPoint[0] :
8810                     this.dragSpecs.startPoint[0] - endPoint[0]
8811                 );
8812         }else{
8813             newSize = this.dragSpecs.startSize + 
8814                 (this.placement == Roo.SplitBar.TOP ?
8815                     endPoint[1] - this.dragSpecs.startPoint[1] :
8816                     this.dragSpecs.startPoint[1] - endPoint[1]
8817                 );
8818         }
8819         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8820         if(newSize != this.dragSpecs.startSize){
8821             if(this.fireEvent('beforeapply', this, newSize) !== false){
8822                 this.adapter.setElementSize(this, newSize);
8823                 this.fireEvent("moved", this, newSize);
8824                 this.fireEvent("resize", this, newSize);
8825             }
8826         }
8827     },
8828     
8829     /**
8830      * Get the adapter this SplitBar uses
8831      * @return The adapter object
8832      */
8833     getAdapter : function(){
8834         return this.adapter;
8835     },
8836     
8837     /**
8838      * Set the adapter this SplitBar uses
8839      * @param {Object} adapter A SplitBar adapter object
8840      */
8841     setAdapter : function(adapter){
8842         this.adapter = adapter;
8843         this.adapter.init(this);
8844     },
8845     
8846     /**
8847      * Gets the minimum size for the resizing element
8848      * @return {Number} The minimum size
8849      */
8850     getMinimumSize : function(){
8851         return this.minSize;
8852     },
8853     
8854     /**
8855      * Sets the minimum size for the resizing element
8856      * @param {Number} minSize The minimum size
8857      */
8858     setMinimumSize : function(minSize){
8859         this.minSize = minSize;
8860     },
8861     
8862     /**
8863      * Gets the maximum size for the resizing element
8864      * @return {Number} The maximum size
8865      */
8866     getMaximumSize : function(){
8867         return this.maxSize;
8868     },
8869     
8870     /**
8871      * Sets the maximum size for the resizing element
8872      * @param {Number} maxSize The maximum size
8873      */
8874     setMaximumSize : function(maxSize){
8875         this.maxSize = maxSize;
8876     },
8877     
8878     /**
8879      * Sets the initialize size for the resizing element
8880      * @param {Number} size The initial size
8881      */
8882     setCurrentSize : function(size){
8883         var oldAnimate = this.animate;
8884         this.animate = false;
8885         this.adapter.setElementSize(this, size);
8886         this.animate = oldAnimate;
8887     },
8888     
8889     /**
8890      * Destroy this splitbar. 
8891      * @param {Boolean} removeEl True to remove the element
8892      */
8893     destroy : function(removeEl){
8894         if(this.shim){
8895             this.shim.remove();
8896         }
8897         this.dd.unreg();
8898         this.proxy.parentNode.removeChild(this.proxy);
8899         if(removeEl){
8900             this.el.remove();
8901         }
8902     }
8903 });
8904
8905 /**
8906  * @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.
8907  */
8908 Roo.SplitBar.createProxy = function(dir){
8909     var proxy = new Roo.Element(document.createElement("div"));
8910     proxy.unselectable();
8911     var cls = 'x-splitbar-proxy';
8912     proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8913     document.body.appendChild(proxy.dom);
8914     return proxy.dom;
8915 };
8916
8917 /** 
8918  * @class Roo.SplitBar.BasicLayoutAdapter
8919  * Default Adapter. It assumes the splitter and resizing element are not positioned
8920  * elements and only gets/sets the width of the element. Generally used for table based layouts.
8921  */
8922 Roo.SplitBar.BasicLayoutAdapter = function(){
8923 };
8924
8925 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8926     // do nothing for now
8927     init : function(s){
8928     
8929     },
8930     /**
8931      * Called before drag operations to get the current size of the resizing element. 
8932      * @param {Roo.SplitBar} s The SplitBar using this adapter
8933      */
8934      getElementSize : function(s){
8935         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8936             return s.resizingEl.getWidth();
8937         }else{
8938             return s.resizingEl.getHeight();
8939         }
8940     },
8941     
8942     /**
8943      * Called after drag operations to set the size of the resizing element.
8944      * @param {Roo.SplitBar} s The SplitBar using this adapter
8945      * @param {Number} newSize The new size to set
8946      * @param {Function} onComplete A function to be invoked when resizing is complete
8947      */
8948     setElementSize : function(s, newSize, onComplete){
8949         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8950             if(!s.animate){
8951                 s.resizingEl.setWidth(newSize);
8952                 if(onComplete){
8953                     onComplete(s, newSize);
8954                 }
8955             }else{
8956                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8957             }
8958         }else{
8959             
8960             if(!s.animate){
8961                 s.resizingEl.setHeight(newSize);
8962                 if(onComplete){
8963                     onComplete(s, newSize);
8964                 }
8965             }else{
8966                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8967             }
8968         }
8969     }
8970 };
8971
8972 /** 
8973  *@class Roo.SplitBar.AbsoluteLayoutAdapter
8974  * @extends Roo.SplitBar.BasicLayoutAdapter
8975  * Adapter that  moves the splitter element to align with the resized sizing element. 
8976  * Used with an absolute positioned SplitBar.
8977  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8978  * document.body, make sure you assign an id to the body element.
8979  */
8980 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8981     this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8982     this.container = Roo.get(container);
8983 };
8984
8985 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8986     init : function(s){
8987         this.basic.init(s);
8988     },
8989     
8990     getElementSize : function(s){
8991         return this.basic.getElementSize(s);
8992     },
8993     
8994     setElementSize : function(s, newSize, onComplete){
8995         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8996     },
8997     
8998     moveSplitter : function(s){
8999         var yes = Roo.SplitBar;
9000         switch(s.placement){
9001             case yes.LEFT:
9002                 s.el.setX(s.resizingEl.getRight());
9003                 break;
9004             case yes.RIGHT:
9005                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9006                 break;
9007             case yes.TOP:
9008                 s.el.setY(s.resizingEl.getBottom());
9009                 break;
9010             case yes.BOTTOM:
9011                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9012                 break;
9013         }
9014     }
9015 };
9016
9017 /**
9018  * Orientation constant - Create a vertical SplitBar
9019  * @static
9020  * @type Number
9021  */
9022 Roo.SplitBar.VERTICAL = 1;
9023
9024 /**
9025  * Orientation constant - Create a horizontal SplitBar
9026  * @static
9027  * @type Number
9028  */
9029 Roo.SplitBar.HORIZONTAL = 2;
9030
9031 /**
9032  * Placement constant - The resizing element is to the left of the splitter element
9033  * @static
9034  * @type Number
9035  */
9036 Roo.SplitBar.LEFT = 1;
9037
9038 /**
9039  * Placement constant - The resizing element is to the right of the splitter element
9040  * @static
9041  * @type Number
9042  */
9043 Roo.SplitBar.RIGHT = 2;
9044
9045 /**
9046  * Placement constant - The resizing element is positioned above the splitter element
9047  * @static
9048  * @type Number
9049  */
9050 Roo.SplitBar.TOP = 3;
9051
9052 /**
9053  * Placement constant - The resizing element is positioned under splitter element
9054  * @static
9055  * @type Number
9056  */
9057 Roo.SplitBar.BOTTOM = 4;
9058 /*
9059  * Based on:
9060  * Ext JS Library 1.1.1
9061  * Copyright(c) 2006-2007, Ext JS, LLC.
9062  *
9063  * Originally Released Under LGPL - original licence link has changed is not relivant.
9064  *
9065  * Fork - LGPL
9066  * <script type="text/javascript">
9067  */
9068
9069 /**
9070  * @class Roo.View
9071  * @extends Roo.util.Observable
9072  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
9073  * This class also supports single and multi selection modes. <br>
9074  * Create a data model bound view:
9075  <pre><code>
9076  var store = new Roo.data.Store(...);
9077
9078  var view = new Roo.View({
9079     el : "my-element",
9080     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
9081  
9082     singleSelect: true,
9083     selectedClass: "ydataview-selected",
9084     store: store
9085  });
9086
9087  // listen for node click?
9088  view.on("click", function(vw, index, node, e){
9089  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9090  });
9091
9092  // load XML data
9093  dataModel.load("foobar.xml");
9094  </code></pre>
9095  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9096  * <br><br>
9097  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9098  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9099  * 
9100  * Note: old style constructor is still suported (container, template, config)
9101  * 
9102  * @constructor
9103  * Create a new View
9104  * @param {Object} config The config object
9105  * 
9106  */
9107 Roo.View = function(config, depreciated_tpl, depreciated_config){
9108     
9109     if (typeof(depreciated_tpl) == 'undefined') {
9110         // new way.. - universal constructor.
9111         Roo.apply(this, config);
9112         this.el  = Roo.get(this.el);
9113     } else {
9114         // old format..
9115         this.el  = Roo.get(config);
9116         this.tpl = depreciated_tpl;
9117         Roo.apply(this, depreciated_config);
9118     }
9119      
9120     
9121     if(typeof(this.tpl) == "string"){
9122         this.tpl = new Roo.Template(this.tpl);
9123     } else {
9124         // support xtype ctors..
9125         this.tpl = new Roo.factory(this.tpl, Roo);
9126     }
9127     
9128     
9129     this.tpl.compile();
9130    
9131
9132      
9133     /** @private */
9134     this.addEvents({
9135     /**
9136      * @event beforeclick
9137      * Fires before a click is processed. Returns false to cancel the default action.
9138      * @param {Roo.View} this
9139      * @param {Number} index The index of the target node
9140      * @param {HTMLElement} node The target node
9141      * @param {Roo.EventObject} e The raw event object
9142      */
9143         "beforeclick" : true,
9144     /**
9145      * @event click
9146      * Fires when a template node is clicked.
9147      * @param {Roo.View} this
9148      * @param {Number} index The index of the target node
9149      * @param {HTMLElement} node The target node
9150      * @param {Roo.EventObject} e The raw event object
9151      */
9152         "click" : true,
9153     /**
9154      * @event dblclick
9155      * Fires when a template node is double clicked.
9156      * @param {Roo.View} this
9157      * @param {Number} index The index of the target node
9158      * @param {HTMLElement} node The target node
9159      * @param {Roo.EventObject} e The raw event object
9160      */
9161         "dblclick" : true,
9162     /**
9163      * @event contextmenu
9164      * Fires when a template node is right clicked.
9165      * @param {Roo.View} this
9166      * @param {Number} index The index of the target node
9167      * @param {HTMLElement} node The target node
9168      * @param {Roo.EventObject} e The raw event object
9169      */
9170         "contextmenu" : true,
9171     /**
9172      * @event selectionchange
9173      * Fires when the selected nodes change.
9174      * @param {Roo.View} this
9175      * @param {Array} selections Array of the selected nodes
9176      */
9177         "selectionchange" : true,
9178
9179     /**
9180      * @event beforeselect
9181      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9182      * @param {Roo.View} this
9183      * @param {HTMLElement} node The node to be selected
9184      * @param {Array} selections Array of currently selected nodes
9185      */
9186         "beforeselect" : true
9187     });
9188
9189     this.el.on({
9190         "click": this.onClick,
9191         "dblclick": this.onDblClick,
9192         "contextmenu": this.onContextMenu,
9193         scope:this
9194     });
9195
9196     this.selections = [];
9197     this.nodes = [];
9198     this.cmp = new Roo.CompositeElementLite([]);
9199     if(this.store){
9200         this.store = Roo.factory(this.store, Roo.data);
9201         this.setStore(this.store, true);
9202     }
9203     Roo.View.superclass.constructor.call(this);
9204 };
9205
9206 Roo.extend(Roo.View, Roo.util.Observable, {
9207     
9208      /**
9209      * @cfg {Roo.data.Store} store Data store to load data from.
9210      */
9211     store : false,
9212     
9213     /**
9214      * @cfg {String|Roo.Element} el The container element.
9215      */
9216     el : '',
9217     
9218     /**
9219      * @cfg {String|Roo.Template} tpl The template used by this View 
9220      */
9221     tpl : false,
9222     
9223     /**
9224      * @cfg {String} selectedClass The css class to add to selected nodes
9225      */
9226     selectedClass : "x-view-selected",
9227      /**
9228      * @cfg {String} emptyText The empty text to show when nothing is loaded.
9229      */
9230     emptyText : "",
9231     /**
9232      * @cfg {Boolean} multiSelect Allow multiple selection
9233      */
9234     
9235     multiSelect : false,
9236     /**
9237      * @cfg {Boolean} singleSelect Allow single selection
9238      */
9239     singleSelect:  false,
9240     
9241     /**
9242      * Returns the element this view is bound to.
9243      * @return {Roo.Element}
9244      */
9245     getEl : function(){
9246         return this.el;
9247     },
9248
9249     /**
9250      * Refreshes the view.
9251      */
9252     refresh : function(){
9253         var t = this.tpl;
9254         this.clearSelections();
9255         this.el.update("");
9256         var html = [];
9257         var records = this.store.getRange();
9258         if(records.length < 1){
9259             this.el.update(this.emptyText);
9260             return;
9261         }
9262         for(var i = 0, len = records.length; i < len; i++){
9263             var data = this.prepareData(records[i].data, i, records[i]);
9264             html[html.length] = t.apply(data);
9265         }
9266         this.el.update(html.join(""));
9267         this.nodes = this.el.dom.childNodes;
9268         this.updateIndexes(0);
9269     },
9270
9271     /**
9272      * Function to override to reformat the data that is sent to
9273      * the template for each node.
9274      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9275      * a JSON object for an UpdateManager bound view).
9276      */
9277     prepareData : function(data){
9278         return data;
9279     },
9280
9281     onUpdate : function(ds, record){
9282         this.clearSelections();
9283         var index = this.store.indexOf(record);
9284         var n = this.nodes[index];
9285         this.tpl.insertBefore(n, this.prepareData(record.data));
9286         n.parentNode.removeChild(n);
9287         this.updateIndexes(index, index);
9288     },
9289
9290     onAdd : function(ds, records, index){
9291         this.clearSelections();
9292         if(this.nodes.length == 0){
9293             this.refresh();
9294             return;
9295         }
9296         var n = this.nodes[index];
9297         for(var i = 0, len = records.length; i < len; i++){
9298             var d = this.prepareData(records[i].data);
9299             if(n){
9300                 this.tpl.insertBefore(n, d);
9301             }else{
9302                 this.tpl.append(this.el, d);
9303             }
9304         }
9305         this.updateIndexes(index);
9306     },
9307
9308     onRemove : function(ds, record, index){
9309         this.clearSelections();
9310         this.el.dom.removeChild(this.nodes[index]);
9311         this.updateIndexes(index);
9312     },
9313
9314     /**
9315      * Refresh an individual node.
9316      * @param {Number} index
9317      */
9318     refreshNode : function(index){
9319         this.onUpdate(this.store, this.store.getAt(index));
9320     },
9321
9322     updateIndexes : function(startIndex, endIndex){
9323         var ns = this.nodes;
9324         startIndex = startIndex || 0;
9325         endIndex = endIndex || ns.length - 1;
9326         for(var i = startIndex; i <= endIndex; i++){
9327             ns[i].nodeIndex = i;
9328         }
9329     },
9330
9331     /**
9332      * Changes the data store this view uses and refresh the view.
9333      * @param {Store} store
9334      */
9335     setStore : function(store, initial){
9336         if(!initial && this.store){
9337             this.store.un("datachanged", this.refresh);
9338             this.store.un("add", this.onAdd);
9339             this.store.un("remove", this.onRemove);
9340             this.store.un("update", this.onUpdate);
9341             this.store.un("clear", this.refresh);
9342         }
9343         if(store){
9344           
9345             store.on("datachanged", this.refresh, this);
9346             store.on("add", this.onAdd, this);
9347             store.on("remove", this.onRemove, this);
9348             store.on("update", this.onUpdate, this);
9349             store.on("clear", this.refresh, this);
9350         }
9351         
9352         if(store){
9353             this.refresh();
9354         }
9355     },
9356
9357     /**
9358      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9359      * @param {HTMLElement} node
9360      * @return {HTMLElement} The template node
9361      */
9362     findItemFromChild : function(node){
9363         var el = this.el.dom;
9364         if(!node || node.parentNode == el){
9365                     return node;
9366             }
9367             var p = node.parentNode;
9368             while(p && p != el){
9369             if(p.parentNode == el){
9370                 return p;
9371             }
9372             p = p.parentNode;
9373         }
9374             return null;
9375     },
9376
9377     /** @ignore */
9378     onClick : function(e){
9379         var item = this.findItemFromChild(e.getTarget());
9380         if(item){
9381             var index = this.indexOf(item);
9382             if(this.onItemClick(item, index, e) !== false){
9383                 this.fireEvent("click", this, index, item, e);
9384             }
9385         }else{
9386             this.clearSelections();
9387         }
9388     },
9389
9390     /** @ignore */
9391     onContextMenu : function(e){
9392         var item = this.findItemFromChild(e.getTarget());
9393         if(item){
9394             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9395         }
9396     },
9397
9398     /** @ignore */
9399     onDblClick : function(e){
9400         var item = this.findItemFromChild(e.getTarget());
9401         if(item){
9402             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9403         }
9404     },
9405
9406     onItemClick : function(item, index, e){
9407         if(this.fireEvent("beforeclick", this, index, item, e) === false){
9408             return false;
9409         }
9410         if(this.multiSelect || this.singleSelect){
9411             if(this.multiSelect && e.shiftKey && this.lastSelection){
9412                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9413             }else{
9414                 this.select(item, this.multiSelect && e.ctrlKey);
9415                 this.lastSelection = item;
9416             }
9417             e.preventDefault();
9418         }
9419         return true;
9420     },
9421
9422     /**
9423      * Get the number of selected nodes.
9424      * @return {Number}
9425      */
9426     getSelectionCount : function(){
9427         return this.selections.length;
9428     },
9429
9430     /**
9431      * Get the currently selected nodes.
9432      * @return {Array} An array of HTMLElements
9433      */
9434     getSelectedNodes : function(){
9435         return this.selections;
9436     },
9437
9438     /**
9439      * Get the indexes of the selected nodes.
9440      * @return {Array}
9441      */
9442     getSelectedIndexes : function(){
9443         var indexes = [], s = this.selections;
9444         for(var i = 0, len = s.length; i < len; i++){
9445             indexes.push(s[i].nodeIndex);
9446         }
9447         return indexes;
9448     },
9449
9450     /**
9451      * Clear all selections
9452      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9453      */
9454     clearSelections : function(suppressEvent){
9455         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9456             this.cmp.elements = this.selections;
9457             this.cmp.removeClass(this.selectedClass);
9458             this.selections = [];
9459             if(!suppressEvent){
9460                 this.fireEvent("selectionchange", this, this.selections);
9461             }
9462         }
9463     },
9464
9465     /**
9466      * Returns true if the passed node is selected
9467      * @param {HTMLElement/Number} node The node or node index
9468      * @return {Boolean}
9469      */
9470     isSelected : function(node){
9471         var s = this.selections;
9472         if(s.length < 1){
9473             return false;
9474         }
9475         node = this.getNode(node);
9476         return s.indexOf(node) !== -1;
9477     },
9478
9479     /**
9480      * Selects nodes.
9481      * @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
9482      * @param {Boolean} keepExisting (optional) true to keep existing selections
9483      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9484      */
9485     select : function(nodeInfo, keepExisting, suppressEvent){
9486         if(nodeInfo instanceof Array){
9487             if(!keepExisting){
9488                 this.clearSelections(true);
9489             }
9490             for(var i = 0, len = nodeInfo.length; i < len; i++){
9491                 this.select(nodeInfo[i], true, true);
9492             }
9493         } else{
9494             var node = this.getNode(nodeInfo);
9495             if(node && !this.isSelected(node)){
9496                 if(!keepExisting){
9497                     this.clearSelections(true);
9498                 }
9499                 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9500                     Roo.fly(node).addClass(this.selectedClass);
9501                     this.selections.push(node);
9502                     if(!suppressEvent){
9503                         this.fireEvent("selectionchange", this, this.selections);
9504                     }
9505                 }
9506             }
9507         }
9508     },
9509
9510     /**
9511      * Gets a template node.
9512      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9513      * @return {HTMLElement} The node or null if it wasn't found
9514      */
9515     getNode : function(nodeInfo){
9516         if(typeof nodeInfo == "string"){
9517             return document.getElementById(nodeInfo);
9518         }else if(typeof nodeInfo == "number"){
9519             return this.nodes[nodeInfo];
9520         }
9521         return nodeInfo;
9522     },
9523
9524     /**
9525      * Gets a range template nodes.
9526      * @param {Number} startIndex
9527      * @param {Number} endIndex
9528      * @return {Array} An array of nodes
9529      */
9530     getNodes : function(start, end){
9531         var ns = this.nodes;
9532         start = start || 0;
9533         end = typeof end == "undefined" ? ns.length - 1 : end;
9534         var nodes = [];
9535         if(start <= end){
9536             for(var i = start; i <= end; i++){
9537                 nodes.push(ns[i]);
9538             }
9539         } else{
9540             for(var i = start; i >= end; i--){
9541                 nodes.push(ns[i]);
9542             }
9543         }
9544         return nodes;
9545     },
9546
9547     /**
9548      * Finds the index of the passed node
9549      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9550      * @return {Number} The index of the node or -1
9551      */
9552     indexOf : function(node){
9553         node = this.getNode(node);
9554         if(typeof node.nodeIndex == "number"){
9555             return node.nodeIndex;
9556         }
9557         var ns = this.nodes;
9558         for(var i = 0, len = ns.length; i < len; i++){
9559             if(ns[i] == node){
9560                 return i;
9561             }
9562         }
9563         return -1;
9564     }
9565 });
9566 /*
9567  * Based on:
9568  * Ext JS Library 1.1.1
9569  * Copyright(c) 2006-2007, Ext JS, LLC.
9570  *
9571  * Originally Released Under LGPL - original licence link has changed is not relivant.
9572  *
9573  * Fork - LGPL
9574  * <script type="text/javascript">
9575  */
9576
9577 /**
9578  * @class Roo.JsonView
9579  * @extends Roo.View
9580  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9581 <pre><code>
9582 var view = new Roo.JsonView({
9583     container: "my-element",
9584     tpl: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
9585     multiSelect: true, 
9586     jsonRoot: "data" 
9587 });
9588
9589 // listen for node click?
9590 view.on("click", function(vw, index, node, e){
9591     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9592 });
9593
9594 // direct load of JSON data
9595 view.load("foobar.php");
9596
9597 // Example from my blog list
9598 var tpl = new Roo.Template(
9599     '&lt;div class="entry"&gt;' +
9600     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
9601     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
9602     "&lt;/div&gt;&lt;hr /&gt;"
9603 );
9604
9605 var moreView = new Roo.JsonView({
9606     container :  "entry-list", 
9607     template : tpl,
9608     jsonRoot: "posts"
9609 });
9610 moreView.on("beforerender", this.sortEntries, this);
9611 moreView.load({
9612     url: "/blog/get-posts.php",
9613     params: "allposts=true",
9614     text: "Loading Blog Entries..."
9615 });
9616 </code></pre>
9617
9618 * Note: old code is supported with arguments : (container, template, config)
9619
9620
9621  * @constructor
9622  * Create a new JsonView
9623  * 
9624  * @param {Object} config The config object
9625  * 
9626  */
9627 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9628     
9629     
9630     Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9631
9632     var um = this.el.getUpdateManager();
9633     um.setRenderer(this);
9634     um.on("update", this.onLoad, this);
9635     um.on("failure", this.onLoadException, this);
9636
9637     /**
9638      * @event beforerender
9639      * Fires before rendering of the downloaded JSON data.
9640      * @param {Roo.JsonView} this
9641      * @param {Object} data The JSON data loaded
9642      */
9643     /**
9644      * @event load
9645      * Fires when data is loaded.
9646      * @param {Roo.JsonView} this
9647      * @param {Object} data The JSON data loaded
9648      * @param {Object} response The raw Connect response object
9649      */
9650     /**
9651      * @event loadexception
9652      * Fires when loading fails.
9653      * @param {Roo.JsonView} this
9654      * @param {Object} response The raw Connect response object
9655      */
9656     this.addEvents({
9657         'beforerender' : true,
9658         'load' : true,
9659         'loadexception' : true
9660     });
9661 };
9662 Roo.extend(Roo.JsonView, Roo.View, {
9663     /**
9664      * @type {String} The root property in the loaded JSON object that contains the data
9665      */
9666     jsonRoot : "",
9667
9668     /**
9669      * Refreshes the view.
9670      */
9671     refresh : function(){
9672         this.clearSelections();
9673         this.el.update("");
9674         var html = [];
9675         var o = this.jsonData;
9676         if(o && o.length > 0){
9677             for(var i = 0, len = o.length; i < len; i++){
9678                 var data = this.prepareData(o[i], i, o);
9679                 html[html.length] = this.tpl.apply(data);
9680             }
9681         }else{
9682             html.push(this.emptyText);
9683         }
9684         this.el.update(html.join(""));
9685         this.nodes = this.el.dom.childNodes;
9686         this.updateIndexes(0);
9687     },
9688
9689     /**
9690      * 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.
9691      * @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:
9692      <pre><code>
9693      view.load({
9694          url: "your-url.php",
9695          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9696          callback: yourFunction,
9697          scope: yourObject, //(optional scope)
9698          discardUrl: false,
9699          nocache: false,
9700          text: "Loading...",
9701          timeout: 30,
9702          scripts: false
9703      });
9704      </code></pre>
9705      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9706      * 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.
9707      * @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}
9708      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9709      * @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.
9710      */
9711     load : function(){
9712         var um = this.el.getUpdateManager();
9713         um.update.apply(um, arguments);
9714     },
9715
9716     render : function(el, response){
9717         this.clearSelections();
9718         this.el.update("");
9719         var o;
9720         try{
9721             o = Roo.util.JSON.decode(response.responseText);
9722             if(this.jsonRoot){
9723                 
9724                 o = o[this.jsonRoot];
9725             }
9726         } catch(e){
9727         }
9728         /**
9729          * The current JSON data or null
9730          */
9731         this.jsonData = o;
9732         this.beforeRender();
9733         this.refresh();
9734     },
9735
9736 /**
9737  * Get the number of records in the current JSON dataset
9738  * @return {Number}
9739  */
9740     getCount : function(){
9741         return this.jsonData ? this.jsonData.length : 0;
9742     },
9743
9744 /**
9745  * Returns the JSON object for the specified node(s)
9746  * @param {HTMLElement/Array} node The node or an array of nodes
9747  * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9748  * you get the JSON object for the node
9749  */
9750     getNodeData : function(node){
9751         if(node instanceof Array){
9752             var data = [];
9753             for(var i = 0, len = node.length; i < len; i++){
9754                 data.push(this.getNodeData(node[i]));
9755             }
9756             return data;
9757         }
9758         return this.jsonData[this.indexOf(node)] || null;
9759     },
9760
9761     beforeRender : function(){
9762         this.snapshot = this.jsonData;
9763         if(this.sortInfo){
9764             this.sort.apply(this, this.sortInfo);
9765         }
9766         this.fireEvent("beforerender", this, this.jsonData);
9767     },
9768
9769     onLoad : function(el, o){
9770         this.fireEvent("load", this, this.jsonData, o);
9771     },
9772
9773     onLoadException : function(el, o){
9774         this.fireEvent("loadexception", this, o);
9775     },
9776
9777 /**
9778  * Filter the data by a specific property.
9779  * @param {String} property A property on your JSON objects
9780  * @param {String/RegExp} value Either string that the property values
9781  * should start with, or a RegExp to test against the property
9782  */
9783     filter : function(property, value){
9784         if(this.jsonData){
9785             var data = [];
9786             var ss = this.snapshot;
9787             if(typeof value == "string"){
9788                 var vlen = value.length;
9789                 if(vlen == 0){
9790                     this.clearFilter();
9791                     return;
9792                 }
9793                 value = value.toLowerCase();
9794                 for(var i = 0, len = ss.length; i < len; i++){
9795                     var o = ss[i];
9796                     if(o[property].substr(0, vlen).toLowerCase() == value){
9797                         data.push(o);
9798                     }
9799                 }
9800             } else if(value.exec){ // regex?
9801                 for(var i = 0, len = ss.length; i < len; i++){
9802                     var o = ss[i];
9803                     if(value.test(o[property])){
9804                         data.push(o);
9805                     }
9806                 }
9807             } else{
9808                 return;
9809             }
9810             this.jsonData = data;
9811             this.refresh();
9812         }
9813     },
9814
9815 /**
9816  * Filter by a function. The passed function will be called with each
9817  * object in the current dataset. If the function returns true the value is kept,
9818  * otherwise it is filtered.
9819  * @param {Function} fn
9820  * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9821  */
9822     filterBy : function(fn, scope){
9823         if(this.jsonData){
9824             var data = [];
9825             var ss = this.snapshot;
9826             for(var i = 0, len = ss.length; i < len; i++){
9827                 var o = ss[i];
9828                 if(fn.call(scope || this, o)){
9829                     data.push(o);
9830                 }
9831             }
9832             this.jsonData = data;
9833             this.refresh();
9834         }
9835     },
9836
9837 /**
9838  * Clears the current filter.
9839  */
9840     clearFilter : function(){
9841         if(this.snapshot && this.jsonData != this.snapshot){
9842             this.jsonData = this.snapshot;
9843             this.refresh();
9844         }
9845     },
9846
9847
9848 /**
9849  * Sorts the data for this view and refreshes it.
9850  * @param {String} property A property on your JSON objects to sort on
9851  * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9852  * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9853  */
9854     sort : function(property, dir, sortType){
9855         this.sortInfo = Array.prototype.slice.call(arguments, 0);
9856         if(this.jsonData){
9857             var p = property;
9858             var dsc = dir && dir.toLowerCase() == "desc";
9859             var f = function(o1, o2){
9860                 var v1 = sortType ? sortType(o1[p]) : o1[p];
9861                 var v2 = sortType ? sortType(o2[p]) : o2[p];
9862                 ;
9863                 if(v1 < v2){
9864                     return dsc ? +1 : -1;
9865                 } else if(v1 > v2){
9866                     return dsc ? -1 : +1;
9867                 } else{
9868                     return 0;
9869                 }
9870             };
9871             this.jsonData.sort(f);
9872             this.refresh();
9873             if(this.jsonData != this.snapshot){
9874                 this.snapshot.sort(f);
9875             }
9876         }
9877     }
9878 });/*
9879  * Based on:
9880  * Ext JS Library 1.1.1
9881  * Copyright(c) 2006-2007, Ext JS, LLC.
9882  *
9883  * Originally Released Under LGPL - original licence link has changed is not relivant.
9884  *
9885  * Fork - LGPL
9886  * <script type="text/javascript">
9887  */
9888  
9889
9890 /**
9891  * @class Roo.ColorPalette
9892  * @extends Roo.Component
9893  * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
9894  * Here's an example of typical usage:
9895  * <pre><code>
9896 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
9897 cp.render('my-div');
9898
9899 cp.on('select', function(palette, selColor){
9900     // do something with selColor
9901 });
9902 </code></pre>
9903  * @constructor
9904  * Create a new ColorPalette
9905  * @param {Object} config The config object
9906  */
9907 Roo.ColorPalette = function(config){
9908     Roo.ColorPalette.superclass.constructor.call(this, config);
9909     this.addEvents({
9910         /**
9911              * @event select
9912              * Fires when a color is selected
9913              * @param {ColorPalette} this
9914              * @param {String} color The 6-digit color hex code (without the # symbol)
9915              */
9916         select: true
9917     });
9918
9919     if(this.handler){
9920         this.on("select", this.handler, this.scope, true);
9921     }
9922 };
9923 Roo.extend(Roo.ColorPalette, Roo.Component, {
9924     /**
9925      * @cfg {String} itemCls
9926      * The CSS class to apply to the containing element (defaults to "x-color-palette")
9927      */
9928     itemCls : "x-color-palette",
9929     /**
9930      * @cfg {String} value
9931      * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
9932      * the hex codes are case-sensitive.
9933      */
9934     value : null,
9935     clickEvent:'click',
9936     // private
9937     ctype: "Roo.ColorPalette",
9938
9939     /**
9940      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9941      */
9942     allowReselect : false,
9943
9944     /**
9945      * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
9946      * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
9947      * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9948      * of colors with the width setting until the box is symmetrical.</p>
9949      * <p>You can override individual colors if needed:</p>
9950      * <pre><code>
9951 var cp = new Roo.ColorPalette();
9952 cp.colors[0] = "FF0000";  // change the first box to red
9953 </code></pre>
9954
9955 Or you can provide a custom array of your own for complete control:
9956 <pre><code>
9957 var cp = new Roo.ColorPalette();
9958 cp.colors = ["000000", "993300", "333300"];
9959 </code></pre>
9960      * @type Array
9961      */
9962     colors : [
9963         "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9964         "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9965         "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9966         "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9967         "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9968     ],
9969
9970     // private
9971     onRender : function(container, position){
9972         var t = new Roo.MasterTemplate(
9973             '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
9974         );
9975         var c = this.colors;
9976         for(var i = 0, len = c.length; i < len; i++){
9977             t.add([c[i]]);
9978         }
9979         var el = document.createElement("div");
9980         el.className = this.itemCls;
9981         t.overwrite(el);
9982         container.dom.insertBefore(el, position);
9983         this.el = Roo.get(el);
9984         this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
9985         if(this.clickEvent != 'click'){
9986             this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
9987         }
9988     },
9989
9990     // private
9991     afterRender : function(){
9992         Roo.ColorPalette.superclass.afterRender.call(this);
9993         if(this.value){
9994             var s = this.value;
9995             this.value = null;
9996             this.select(s);
9997         }
9998     },
9999
10000     // private
10001     handleClick : function(e, t){
10002         e.preventDefault();
10003         if(!this.disabled){
10004             var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10005             this.select(c.toUpperCase());
10006         }
10007     },
10008
10009     /**
10010      * Selects the specified color in the palette (fires the select event)
10011      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10012      */
10013     select : function(color){
10014         color = color.replace("#", "");
10015         if(color != this.value || this.allowReselect){
10016             var el = this.el;
10017             if(this.value){
10018                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10019             }
10020             el.child("a.color-"+color).addClass("x-color-palette-sel");
10021             this.value = color;
10022             this.fireEvent("select", this, color);
10023         }
10024     }
10025 });/*
10026  * Based on:
10027  * Ext JS Library 1.1.1
10028  * Copyright(c) 2006-2007, Ext JS, LLC.
10029  *
10030  * Originally Released Under LGPL - original licence link has changed is not relivant.
10031  *
10032  * Fork - LGPL
10033  * <script type="text/javascript">
10034  */
10035  
10036 /**
10037  * @class Roo.DatePicker
10038  * @extends Roo.Component
10039  * Simple date picker class.
10040  * @constructor
10041  * Create a new DatePicker
10042  * @param {Object} config The config object
10043  */
10044 Roo.DatePicker = function(config){
10045     Roo.DatePicker.superclass.constructor.call(this, config);
10046
10047     this.value = config && config.value ?
10048                  config.value.clearTime() : new Date().clearTime();
10049
10050     this.addEvents({
10051         /**
10052              * @event select
10053              * Fires when a date is selected
10054              * @param {DatePicker} this
10055              * @param {Date} date The selected date
10056              */
10057         select: true
10058     });
10059
10060     if(this.handler){
10061         this.on("select", this.handler,  this.scope || this);
10062     }
10063     // build the disabledDatesRE
10064     if(!this.disabledDatesRE && this.disabledDates){
10065         var dd = this.disabledDates;
10066         var re = "(?:";
10067         for(var i = 0; i < dd.length; i++){
10068             re += dd[i];
10069             if(i != dd.length-1) re += "|";
10070         }
10071         this.disabledDatesRE = new RegExp(re + ")");
10072     }
10073 };
10074
10075 Roo.extend(Roo.DatePicker, Roo.Component, {
10076     /**
10077      * @cfg {String} todayText
10078      * The text to display on the button that selects the current date (defaults to "Today")
10079      */
10080     todayText : "Today",
10081     /**
10082      * @cfg {String} okText
10083      * The text to display on the ok button
10084      */
10085     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
10086     /**
10087      * @cfg {String} cancelText
10088      * The text to display on the cancel button
10089      */
10090     cancelText : "Cancel",
10091     /**
10092      * @cfg {String} todayTip
10093      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10094      */
10095     todayTip : "{0} (Spacebar)",
10096     /**
10097      * @cfg {Date} minDate
10098      * Minimum allowable date (JavaScript date object, defaults to null)
10099      */
10100     minDate : null,
10101     /**
10102      * @cfg {Date} maxDate
10103      * Maximum allowable date (JavaScript date object, defaults to null)
10104      */
10105     maxDate : null,
10106     /**
10107      * @cfg {String} minText
10108      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10109      */
10110     minText : "This date is before the minimum date",
10111     /**
10112      * @cfg {String} maxText
10113      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10114      */
10115     maxText : "This date is after the maximum date",
10116     /**
10117      * @cfg {String} format
10118      * The default date format string which can be overriden for localization support.  The format must be
10119      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10120      */
10121     format : "m/d/y",
10122     /**
10123      * @cfg {Array} disabledDays
10124      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10125      */
10126     disabledDays : null,
10127     /**
10128      * @cfg {String} disabledDaysText
10129      * The tooltip to display when the date falls on a disabled day (defaults to "")
10130      */
10131     disabledDaysText : "",
10132     /**
10133      * @cfg {RegExp} disabledDatesRE
10134      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10135      */
10136     disabledDatesRE : null,
10137     /**
10138      * @cfg {String} disabledDatesText
10139      * The tooltip text to display when the date falls on a disabled date (defaults to "")
10140      */
10141     disabledDatesText : "",
10142     /**
10143      * @cfg {Boolean} constrainToViewport
10144      * True to constrain the date picker to the viewport (defaults to true)
10145      */
10146     constrainToViewport : true,
10147     /**
10148      * @cfg {Array} monthNames
10149      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10150      */
10151     monthNames : Date.monthNames,
10152     /**
10153      * @cfg {Array} dayNames
10154      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10155      */
10156     dayNames : Date.dayNames,
10157     /**
10158      * @cfg {String} nextText
10159      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10160      */
10161     nextText: 'Next Month (Control+Right)',
10162     /**
10163      * @cfg {String} prevText
10164      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10165      */
10166     prevText: 'Previous Month (Control+Left)',
10167     /**
10168      * @cfg {String} monthYearText
10169      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10170      */
10171     monthYearText: 'Choose a month (Control+Up/Down to move years)',
10172     /**
10173      * @cfg {Number} startDay
10174      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10175      */
10176     startDay : 0,
10177     /**
10178      * @cfg {Bool} showClear
10179      * Show a clear button (usefull for date form elements that can be blank.)
10180      */
10181     
10182     showClear: false,
10183     
10184     /**
10185      * Sets the value of the date field
10186      * @param {Date} value The date to set
10187      */
10188     setValue : function(value){
10189         var old = this.value;
10190         this.value = value.clearTime(true);
10191         if(this.el){
10192             this.update(this.value);
10193         }
10194     },
10195
10196     /**
10197      * Gets the current selected value of the date field
10198      * @return {Date} The selected date
10199      */
10200     getValue : function(){
10201         return this.value;
10202     },
10203
10204     // private
10205     focus : function(){
10206         if(this.el){
10207             this.update(this.activeDate);
10208         }
10209     },
10210
10211     // private
10212     onRender : function(container, position){
10213         var m = [
10214              '<table cellspacing="0">',
10215                 '<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>',
10216                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10217         var dn = this.dayNames;
10218         for(var i = 0; i < 7; i++){
10219             var d = this.startDay+i;
10220             if(d > 6){
10221                 d = d-7;
10222             }
10223             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10224         }
10225         m[m.length] = "</tr></thead><tbody><tr>";
10226         for(var i = 0; i < 42; i++) {
10227             if(i % 7 == 0 && i != 0){
10228                 m[m.length] = "</tr><tr>";
10229             }
10230             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10231         }
10232         m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10233             '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10234
10235         var el = document.createElement("div");
10236         el.className = "x-date-picker";
10237         el.innerHTML = m.join("");
10238
10239         container.dom.insertBefore(el, position);
10240
10241         this.el = Roo.get(el);
10242         this.eventEl = Roo.get(el.firstChild);
10243
10244         new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10245             handler: this.showPrevMonth,
10246             scope: this,
10247             preventDefault:true,
10248             stopDefault:true
10249         });
10250
10251         new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10252             handler: this.showNextMonth,
10253             scope: this,
10254             preventDefault:true,
10255             stopDefault:true
10256         });
10257
10258         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
10259
10260         this.monthPicker = this.el.down('div.x-date-mp');
10261         this.monthPicker.enableDisplayMode('block');
10262         
10263         var kn = new Roo.KeyNav(this.eventEl, {
10264             "left" : function(e){
10265                 e.ctrlKey ?
10266                     this.showPrevMonth() :
10267                     this.update(this.activeDate.add("d", -1));
10268             },
10269
10270             "right" : function(e){
10271                 e.ctrlKey ?
10272                     this.showNextMonth() :
10273                     this.update(this.activeDate.add("d", 1));
10274             },
10275
10276             "up" : function(e){
10277                 e.ctrlKey ?
10278                     this.showNextYear() :
10279                     this.update(this.activeDate.add("d", -7));
10280             },
10281
10282             "down" : function(e){
10283                 e.ctrlKey ?
10284                     this.showPrevYear() :
10285                     this.update(this.activeDate.add("d", 7));
10286             },
10287
10288             "pageUp" : function(e){
10289                 this.showNextMonth();
10290             },
10291
10292             "pageDown" : function(e){
10293                 this.showPrevMonth();
10294             },
10295
10296             "enter" : function(e){
10297                 e.stopPropagation();
10298                 return true;
10299             },
10300
10301             scope : this
10302         });
10303
10304         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
10305
10306         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
10307
10308         this.el.unselectable();
10309         
10310         this.cells = this.el.select("table.x-date-inner tbody td");
10311         this.textNodes = this.el.query("table.x-date-inner tbody span");
10312
10313         this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10314             text: "&#160;",
10315             tooltip: this.monthYearText
10316         });
10317
10318         this.mbtn.on('click', this.showMonthPicker, this);
10319         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10320
10321
10322         var today = (new Date()).dateFormat(this.format);
10323         
10324         var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10325         if (this.showClear) {
10326             baseTb.add( new Roo.Toolbar.Fill());
10327         }
10328         baseTb.add({
10329             text: String.format(this.todayText, today),
10330             tooltip: String.format(this.todayTip, today),
10331             handler: this.selectToday,
10332             scope: this
10333         });
10334         
10335         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10336             
10337         //});
10338         if (this.showClear) {
10339             
10340             baseTb.add( new Roo.Toolbar.Fill());
10341             baseTb.add({
10342                 text: '&#160;',
10343                 cls: 'x-btn-icon x-btn-clear',
10344                 handler: function() {
10345                     //this.value = '';
10346                     this.fireEvent("select", this, '');
10347                 },
10348                 scope: this
10349             });
10350         }
10351         
10352         
10353         if(Roo.isIE){
10354             this.el.repaint();
10355         }
10356         this.update(this.value);
10357     },
10358
10359     createMonthPicker : function(){
10360         if(!this.monthPicker.dom.firstChild){
10361             var buf = ['<table border="0" cellspacing="0">'];
10362             for(var i = 0; i < 6; i++){
10363                 buf.push(
10364                     '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10365                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10366                     i == 0 ?
10367                     '<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>' :
10368                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10369                 );
10370             }
10371             buf.push(
10372                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10373                     this.okText,
10374                     '</button><button type="button" class="x-date-mp-cancel">',
10375                     this.cancelText,
10376                     '</button></td></tr>',
10377                 '</table>'
10378             );
10379             this.monthPicker.update(buf.join(''));
10380             this.monthPicker.on('click', this.onMonthClick, this);
10381             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10382
10383             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10384             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10385
10386             this.mpMonths.each(function(m, a, i){
10387                 i += 1;
10388                 if((i%2) == 0){
10389                     m.dom.xmonth = 5 + Math.round(i * .5);
10390                 }else{
10391                     m.dom.xmonth = Math.round((i-1) * .5);
10392                 }
10393             });
10394         }
10395     },
10396
10397     showMonthPicker : function(){
10398         this.createMonthPicker();
10399         var size = this.el.getSize();
10400         this.monthPicker.setSize(size);
10401         this.monthPicker.child('table').setSize(size);
10402
10403         this.mpSelMonth = (this.activeDate || this.value).getMonth();
10404         this.updateMPMonth(this.mpSelMonth);
10405         this.mpSelYear = (this.activeDate || this.value).getFullYear();
10406         this.updateMPYear(this.mpSelYear);
10407
10408         this.monthPicker.slideIn('t', {duration:.2});
10409     },
10410
10411     updateMPYear : function(y){
10412         this.mpyear = y;
10413         var ys = this.mpYears.elements;
10414         for(var i = 1; i <= 10; i++){
10415             var td = ys[i-1], y2;
10416             if((i%2) == 0){
10417                 y2 = y + Math.round(i * .5);
10418                 td.firstChild.innerHTML = y2;
10419                 td.xyear = y2;
10420             }else{
10421                 y2 = y - (5-Math.round(i * .5));
10422                 td.firstChild.innerHTML = y2;
10423                 td.xyear = y2;
10424             }
10425             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10426         }
10427     },
10428
10429     updateMPMonth : function(sm){
10430         this.mpMonths.each(function(m, a, i){
10431             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10432         });
10433     },
10434
10435     selectMPMonth: function(m){
10436         
10437     },
10438
10439     onMonthClick : function(e, t){
10440         e.stopEvent();
10441         var el = new Roo.Element(t), pn;
10442         if(el.is('button.x-date-mp-cancel')){
10443             this.hideMonthPicker();
10444         }
10445         else if(el.is('button.x-date-mp-ok')){
10446             this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10447             this.hideMonthPicker();
10448         }
10449         else if(pn = el.up('td.x-date-mp-month', 2)){
10450             this.mpMonths.removeClass('x-date-mp-sel');
10451             pn.addClass('x-date-mp-sel');
10452             this.mpSelMonth = pn.dom.xmonth;
10453         }
10454         else if(pn = el.up('td.x-date-mp-year', 2)){
10455             this.mpYears.removeClass('x-date-mp-sel');
10456             pn.addClass('x-date-mp-sel');
10457             this.mpSelYear = pn.dom.xyear;
10458         }
10459         else if(el.is('a.x-date-mp-prev')){
10460             this.updateMPYear(this.mpyear-10);
10461         }
10462         else if(el.is('a.x-date-mp-next')){
10463             this.updateMPYear(this.mpyear+10);
10464         }
10465     },
10466
10467     onMonthDblClick : function(e, t){
10468         e.stopEvent();
10469         var el = new Roo.Element(t), pn;
10470         if(pn = el.up('td.x-date-mp-month', 2)){
10471             this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10472             this.hideMonthPicker();
10473         }
10474         else if(pn = el.up('td.x-date-mp-year', 2)){
10475             this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10476             this.hideMonthPicker();
10477         }
10478     },
10479
10480     hideMonthPicker : function(disableAnim){
10481         if(this.monthPicker){
10482             if(disableAnim === true){
10483                 this.monthPicker.hide();
10484             }else{
10485                 this.monthPicker.slideOut('t', {duration:.2});
10486             }
10487         }
10488     },
10489
10490     // private
10491     showPrevMonth : function(e){
10492         this.update(this.activeDate.add("mo", -1));
10493     },
10494
10495     // private
10496     showNextMonth : function(e){
10497         this.update(this.activeDate.add("mo", 1));
10498     },
10499
10500     // private
10501     showPrevYear : function(){
10502         this.update(this.activeDate.add("y", -1));
10503     },
10504
10505     // private
10506     showNextYear : function(){
10507         this.update(this.activeDate.add("y", 1));
10508     },
10509
10510     // private
10511     handleMouseWheel : function(e){
10512         var delta = e.getWheelDelta();
10513         if(delta > 0){
10514             this.showPrevMonth();
10515             e.stopEvent();
10516         } else if(delta < 0){
10517             this.showNextMonth();
10518             e.stopEvent();
10519         }
10520     },
10521
10522     // private
10523     handleDateClick : function(e, t){
10524         e.stopEvent();
10525         if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10526             this.setValue(new Date(t.dateValue));
10527             this.fireEvent("select", this, this.value);
10528         }
10529     },
10530
10531     // private
10532     selectToday : function(){
10533         this.setValue(new Date().clearTime());
10534         this.fireEvent("select", this, this.value);
10535     },
10536
10537     // private
10538     update : function(date){
10539         var vd = this.activeDate;
10540         this.activeDate = date;
10541         if(vd && this.el){
10542             var t = date.getTime();
10543             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10544                 this.cells.removeClass("x-date-selected");
10545                 this.cells.each(function(c){
10546                    if(c.dom.firstChild.dateValue == t){
10547                        c.addClass("x-date-selected");
10548                        setTimeout(function(){
10549                             try{c.dom.firstChild.focus();}catch(e){}
10550                        }, 50);
10551                        return false;
10552                    }
10553                 });
10554                 return;
10555             }
10556         }
10557         var days = date.getDaysInMonth();
10558         var firstOfMonth = date.getFirstDateOfMonth();
10559         var startingPos = firstOfMonth.getDay()-this.startDay;
10560
10561         if(startingPos <= this.startDay){
10562             startingPos += 7;
10563         }
10564
10565         var pm = date.add("mo", -1);
10566         var prevStart = pm.getDaysInMonth()-startingPos;
10567
10568         var cells = this.cells.elements;
10569         var textEls = this.textNodes;
10570         days += startingPos;
10571
10572         // convert everything to numbers so it's fast
10573         var day = 86400000;
10574         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10575         var today = new Date().clearTime().getTime();
10576         var sel = date.clearTime().getTime();
10577         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10578         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10579         var ddMatch = this.disabledDatesRE;
10580         var ddText = this.disabledDatesText;
10581         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10582         var ddaysText = this.disabledDaysText;
10583         var format = this.format;
10584
10585         var setCellClass = function(cal, cell){
10586             cell.title = "";
10587             var t = d.getTime();
10588             cell.firstChild.dateValue = t;
10589             if(t == today){
10590                 cell.className += " x-date-today";
10591                 cell.title = cal.todayText;
10592             }
10593             if(t == sel){
10594                 cell.className += " x-date-selected";
10595                 setTimeout(function(){
10596                     try{cell.firstChild.focus();}catch(e){}
10597                 }, 50);
10598             }
10599             // disabling
10600             if(t < min) {
10601                 cell.className = " x-date-disabled";
10602                 cell.title = cal.minText;
10603                 return;
10604             }
10605             if(t > max) {
10606                 cell.className = " x-date-disabled";
10607                 cell.title = cal.maxText;
10608                 return;
10609             }
10610             if(ddays){
10611                 if(ddays.indexOf(d.getDay()) != -1){
10612                     cell.title = ddaysText;
10613                     cell.className = " x-date-disabled";
10614                 }
10615             }
10616             if(ddMatch && format){
10617                 var fvalue = d.dateFormat(format);
10618                 if(ddMatch.test(fvalue)){
10619                     cell.title = ddText.replace("%0", fvalue);
10620                     cell.className = " x-date-disabled";
10621                 }
10622             }
10623         };
10624
10625         var i = 0;
10626         for(; i < startingPos; i++) {
10627             textEls[i].innerHTML = (++prevStart);
10628             d.setDate(d.getDate()+1);
10629             cells[i].className = "x-date-prevday";
10630             setCellClass(this, cells[i]);
10631         }
10632         for(; i < days; i++){
10633             intDay = i - startingPos + 1;
10634             textEls[i].innerHTML = (intDay);
10635             d.setDate(d.getDate()+1);
10636             cells[i].className = "x-date-active";
10637             setCellClass(this, cells[i]);
10638         }
10639         var extraDays = 0;
10640         for(; i < 42; i++) {
10641              textEls[i].innerHTML = (++extraDays);
10642              d.setDate(d.getDate()+1);
10643              cells[i].className = "x-date-nextday";
10644              setCellClass(this, cells[i]);
10645         }
10646
10647         this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10648
10649         if(!this.internalRender){
10650             var main = this.el.dom.firstChild;
10651             var w = main.offsetWidth;
10652             this.el.setWidth(w + this.el.getBorderWidth("lr"));
10653             Roo.fly(main).setWidth(w);
10654             this.internalRender = true;
10655             // opera does not respect the auto grow header center column
10656             // then, after it gets a width opera refuses to recalculate
10657             // without a second pass
10658             if(Roo.isOpera && !this.secondPass){
10659                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10660                 this.secondPass = true;
10661                 this.update.defer(10, this, [date]);
10662             }
10663         }
10664     }
10665 });/*
10666  * Based on:
10667  * Ext JS Library 1.1.1
10668  * Copyright(c) 2006-2007, Ext JS, LLC.
10669  *
10670  * Originally Released Under LGPL - original licence link has changed is not relivant.
10671  *
10672  * Fork - LGPL
10673  * <script type="text/javascript">
10674  */
10675 /**
10676  * @class Roo.TabPanel
10677  * @extends Roo.util.Observable
10678  * A lightweight tab container.
10679  * <br><br>
10680  * Usage:
10681  * <pre><code>
10682 // basic tabs 1, built from existing content
10683 var tabs = new Roo.TabPanel("tabs1");
10684 tabs.addTab("script", "View Script");
10685 tabs.addTab("markup", "View Markup");
10686 tabs.activate("script");
10687
10688 // more advanced tabs, built from javascript
10689 var jtabs = new Roo.TabPanel("jtabs");
10690 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10691
10692 // set up the UpdateManager
10693 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10694 var updater = tab2.getUpdateManager();
10695 updater.setDefaultUrl("ajax1.htm");
10696 tab2.on('activate', updater.refresh, updater, true);
10697
10698 // Use setUrl for Ajax loading
10699 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10700 tab3.setUrl("ajax2.htm", null, true);
10701
10702 // Disabled tab
10703 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10704 tab4.disable();
10705
10706 jtabs.activate("jtabs-1");
10707  * </code></pre>
10708  * @constructor
10709  * Create a new TabPanel.
10710  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10711  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10712  */
10713 Roo.TabPanel = function(container, config){
10714     /**
10715     * The container element for this TabPanel.
10716     * @type Roo.Element
10717     */
10718     this.el = Roo.get(container, true);
10719     if(config){
10720         if(typeof config == "boolean"){
10721             this.tabPosition = config ? "bottom" : "top";
10722         }else{
10723             Roo.apply(this, config);
10724         }
10725     }
10726     if(this.tabPosition == "bottom"){
10727         this.bodyEl = Roo.get(this.createBody(this.el.dom));
10728         this.el.addClass("x-tabs-bottom");
10729     }
10730     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10731     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10732     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10733     if(Roo.isIE){
10734         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10735     }
10736     if(this.tabPosition != "bottom"){
10737     /** The body element that contains {@link Roo.TabPanelItem} bodies.
10738      * @type Roo.Element
10739      */
10740       this.bodyEl = Roo.get(this.createBody(this.el.dom));
10741       this.el.addClass("x-tabs-top");
10742     }
10743     this.items = [];
10744
10745     this.bodyEl.setStyle("position", "relative");
10746
10747     this.active = null;
10748     this.activateDelegate = this.activate.createDelegate(this);
10749
10750     this.addEvents({
10751         /**
10752          * @event tabchange
10753          * Fires when the active tab changes
10754          * @param {Roo.TabPanel} this
10755          * @param {Roo.TabPanelItem} activePanel The new active tab
10756          */
10757         "tabchange": true,
10758         /**
10759          * @event beforetabchange
10760          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10761          * @param {Roo.TabPanel} this
10762          * @param {Object} e Set cancel to true on this object to cancel the tab change
10763          * @param {Roo.TabPanelItem} tab The tab being changed to
10764          */
10765         "beforetabchange" : true
10766     });
10767
10768     Roo.EventManager.onWindowResize(this.onResize, this);
10769     this.cpad = this.el.getPadding("lr");
10770     this.hiddenCount = 0;
10771
10772     Roo.TabPanel.superclass.constructor.call(this);
10773 };
10774
10775 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10776         /*
10777          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10778          */
10779     tabPosition : "top",
10780         /*
10781          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10782          */
10783     currentTabWidth : 0,
10784         /*
10785          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10786          */
10787     minTabWidth : 40,
10788         /*
10789          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10790          */
10791     maxTabWidth : 250,
10792         /*
10793          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10794          */
10795     preferredTabWidth : 175,
10796         /*
10797          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10798          */
10799     resizeTabs : false,
10800         /*
10801          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10802          */
10803     monitorResize : true,
10804
10805     /**
10806      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10807      * @param {String} id The id of the div to use <b>or create</b>
10808      * @param {String} text The text for the tab
10809      * @param {String} content (optional) Content to put in the TabPanelItem body
10810      * @param {Boolean} closable (optional) True to create a close icon on the tab
10811      * @return {Roo.TabPanelItem} The created TabPanelItem
10812      */
10813     addTab : function(id, text, content, closable){
10814         var item = new Roo.TabPanelItem(this, id, text, closable);
10815         this.addTabItem(item);
10816         if(content){
10817             item.setContent(content);
10818         }
10819         return item;
10820     },
10821
10822     /**
10823      * Returns the {@link Roo.TabPanelItem} with the specified id/index
10824      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10825      * @return {Roo.TabPanelItem}
10826      */
10827     getTab : function(id){
10828         return this.items[id];
10829     },
10830
10831     /**
10832      * Hides the {@link Roo.TabPanelItem} with the specified id/index
10833      * @param {String/Number} id The id or index of the TabPanelItem to hide.
10834      */
10835     hideTab : function(id){
10836         var t = this.items[id];
10837         if(!t.isHidden()){
10838            t.setHidden(true);
10839            this.hiddenCount++;
10840            this.autoSizeTabs();
10841         }
10842     },
10843
10844     /**
10845      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10846      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10847      */
10848     unhideTab : function(id){
10849         var t = this.items[id];
10850         if(t.isHidden()){
10851            t.setHidden(false);
10852            this.hiddenCount--;
10853            this.autoSizeTabs();
10854         }
10855     },
10856
10857     /**
10858      * Adds an existing {@link Roo.TabPanelItem}.
10859      * @param {Roo.TabPanelItem} item The TabPanelItem to add
10860      */
10861     addTabItem : function(item){
10862         this.items[item.id] = item;
10863         this.items.push(item);
10864         if(this.resizeTabs){
10865            item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10866            this.autoSizeTabs();
10867         }else{
10868             item.autoSize();
10869         }
10870     },
10871
10872     /**
10873      * Removes a {@link Roo.TabPanelItem}.
10874      * @param {String/Number} id The id or index of the TabPanelItem to remove.
10875      */
10876     removeTab : function(id){
10877         var items = this.items;
10878         var tab = items[id];
10879         if(!tab) { return; }
10880         var index = items.indexOf(tab);
10881         if(this.active == tab && items.length > 1){
10882             var newTab = this.getNextAvailable(index);
10883             if(newTab) {
10884                 newTab.activate();
10885             }
10886         }
10887         this.stripEl.dom.removeChild(tab.pnode.dom);
10888         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10889             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10890         }
10891         items.splice(index, 1);
10892         delete this.items[tab.id];
10893         tab.fireEvent("close", tab);
10894         tab.purgeListeners();
10895         this.autoSizeTabs();
10896     },
10897
10898     getNextAvailable : function(start){
10899         var items = this.items;
10900         var index = start;
10901         // look for a next tab that will slide over to
10902         // replace the one being removed
10903         while(index < items.length){
10904             var item = items[++index];
10905             if(item && !item.isHidden()){
10906                 return item;
10907             }
10908         }
10909         // if one isn't found select the previous tab (on the left)
10910         index = start;
10911         while(index >= 0){
10912             var item = items[--index];
10913             if(item && !item.isHidden()){
10914                 return item;
10915             }
10916         }
10917         return null;
10918     },
10919
10920     /**
10921      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10922      * @param {String/Number} id The id or index of the TabPanelItem to disable.
10923      */
10924     disableTab : function(id){
10925         var tab = this.items[id];
10926         if(tab && this.active != tab){
10927             tab.disable();
10928         }
10929     },
10930
10931     /**
10932      * Enables a {@link Roo.TabPanelItem} that is disabled.
10933      * @param {String/Number} id The id or index of the TabPanelItem to enable.
10934      */
10935     enableTab : function(id){
10936         var tab = this.items[id];
10937         tab.enable();
10938     },
10939
10940     /**
10941      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10942      * @param {String/Number} id The id or index of the TabPanelItem to activate.
10943      * @return {Roo.TabPanelItem} The TabPanelItem.
10944      */
10945     activate : function(id){
10946         var tab = this.items[id];
10947         if(!tab){
10948             return null;
10949         }
10950         if(tab == this.active || tab.disabled){
10951             return tab;
10952         }
10953         var e = {};
10954         this.fireEvent("beforetabchange", this, e, tab);
10955         if(e.cancel !== true && !tab.disabled){
10956             if(this.active){
10957                 this.active.hide();
10958             }
10959             this.active = this.items[id];
10960             this.active.show();
10961             this.fireEvent("tabchange", this, this.active);
10962         }
10963         return tab;
10964     },
10965
10966     /**
10967      * Gets the active {@link Roo.TabPanelItem}.
10968      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10969      */
10970     getActiveTab : function(){
10971         return this.active;
10972     },
10973
10974     /**
10975      * Updates the tab body element to fit the height of the container element
10976      * for overflow scrolling
10977      * @param {Number} targetHeight (optional) Override the starting height from the elements height
10978      */
10979     syncHeight : function(targetHeight){
10980         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10981         var bm = this.bodyEl.getMargins();
10982         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10983         this.bodyEl.setHeight(newHeight);
10984         return newHeight;
10985     },
10986
10987     onResize : function(){
10988         if(this.monitorResize){
10989             this.autoSizeTabs();
10990         }
10991     },
10992
10993     /**
10994      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10995      */
10996     beginUpdate : function(){
10997         this.updating = true;
10998     },
10999
11000     /**
11001      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11002      */
11003     endUpdate : function(){
11004         this.updating = false;
11005         this.autoSizeTabs();
11006     },
11007
11008     /**
11009      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11010      */
11011     autoSizeTabs : function(){
11012         var count = this.items.length;
11013         var vcount = count - this.hiddenCount;
11014         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11015         var w = Math.max(this.el.getWidth() - this.cpad, 10);
11016         var availWidth = Math.floor(w / vcount);
11017         var b = this.stripBody;
11018         if(b.getWidth() > w){
11019             var tabs = this.items;
11020             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11021             if(availWidth < this.minTabWidth){
11022                 /*if(!this.sleft){    // incomplete scrolling code
11023                     this.createScrollButtons();
11024                 }
11025                 this.showScroll();
11026                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11027             }
11028         }else{
11029             if(this.currentTabWidth < this.preferredTabWidth){
11030                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11031             }
11032         }
11033     },
11034
11035     /**
11036      * Returns the number of tabs in this TabPanel.
11037      * @return {Number}
11038      */
11039      getCount : function(){
11040          return this.items.length;
11041      },
11042
11043     /**
11044      * Resizes all the tabs to the passed width
11045      * @param {Number} The new width
11046      */
11047     setTabWidth : function(width){
11048         this.currentTabWidth = width;
11049         for(var i = 0, len = this.items.length; i < len; i++) {
11050                 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11051         }
11052     },
11053
11054     /**
11055      * Destroys this TabPanel
11056      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11057      */
11058     destroy : function(removeEl){
11059         Roo.EventManager.removeResizeListener(this.onResize, this);
11060         for(var i = 0, len = this.items.length; i < len; i++){
11061             this.items[i].purgeListeners();
11062         }
11063         if(removeEl === true){
11064             this.el.update("");
11065             this.el.remove();
11066         }
11067     }
11068 });
11069
11070 /**
11071  * @class Roo.TabPanelItem
11072  * @extends Roo.util.Observable
11073  * Represents an individual item (tab plus body) in a TabPanel.
11074  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11075  * @param {String} id The id of this TabPanelItem
11076  * @param {String} text The text for the tab of this TabPanelItem
11077  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11078  */
11079 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11080     /**
11081      * The {@link Roo.TabPanel} this TabPanelItem belongs to
11082      * @type Roo.TabPanel
11083      */
11084     this.tabPanel = tabPanel;
11085     /**
11086      * The id for this TabPanelItem
11087      * @type String
11088      */
11089     this.id = id;
11090     /** @private */
11091     this.disabled = false;
11092     /** @private */
11093     this.text = text;
11094     /** @private */
11095     this.loaded = false;
11096     this.closable = closable;
11097
11098     /**
11099      * The body element for this TabPanelItem.
11100      * @type Roo.Element
11101      */
11102     this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11103     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11104     this.bodyEl.setStyle("display", "block");
11105     this.bodyEl.setStyle("zoom", "1");
11106     this.hideAction();
11107
11108     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11109     /** @private */
11110     this.el = Roo.get(els.el, true);
11111     this.inner = Roo.get(els.inner, true);
11112     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11113     this.pnode = Roo.get(els.el.parentNode, true);
11114     this.el.on("mousedown", this.onTabMouseDown, this);
11115     this.el.on("click", this.onTabClick, this);
11116     /** @private */
11117     if(closable){
11118         var c = Roo.get(els.close, true);
11119         c.dom.title = this.closeText;
11120         c.addClassOnOver("close-over");
11121         c.on("click", this.closeClick, this);
11122      }
11123
11124     this.addEvents({
11125          /**
11126          * @event activate
11127          * Fires when this tab becomes the active tab.
11128          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11129          * @param {Roo.TabPanelItem} this
11130          */
11131         "activate": true,
11132         /**
11133          * @event beforeclose
11134          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11135          * @param {Roo.TabPanelItem} this
11136          * @param {Object} e Set cancel to true on this object to cancel the close.
11137          */
11138         "beforeclose": true,
11139         /**
11140          * @event close
11141          * Fires when this tab is closed.
11142          * @param {Roo.TabPanelItem} this
11143          */
11144          "close": true,
11145         /**
11146          * @event deactivate
11147          * Fires when this tab is no longer the active tab.
11148          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11149          * @param {Roo.TabPanelItem} this
11150          */
11151          "deactivate" : true
11152     });
11153     this.hidden = false;
11154
11155     Roo.TabPanelItem.superclass.constructor.call(this);
11156 };
11157
11158 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11159     purgeListeners : function(){
11160        Roo.util.Observable.prototype.purgeListeners.call(this);
11161        this.el.removeAllListeners();
11162     },
11163     /**
11164      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11165      */
11166     show : function(){
11167         this.pnode.addClass("on");
11168         this.showAction();
11169         if(Roo.isOpera){
11170             this.tabPanel.stripWrap.repaint();
11171         }
11172         this.fireEvent("activate", this.tabPanel, this);
11173     },
11174
11175     /**
11176      * Returns true if this tab is the active tab.
11177      * @return {Boolean}
11178      */
11179     isActive : function(){
11180         return this.tabPanel.getActiveTab() == this;
11181     },
11182
11183     /**
11184      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11185      */
11186     hide : function(){
11187         this.pnode.removeClass("on");
11188         this.hideAction();
11189         this.fireEvent("deactivate", this.tabPanel, this);
11190     },
11191
11192     hideAction : function(){
11193         this.bodyEl.hide();
11194         this.bodyEl.setStyle("position", "absolute");
11195         this.bodyEl.setLeft("-20000px");
11196         this.bodyEl.setTop("-20000px");
11197     },
11198
11199     showAction : function(){
11200         this.bodyEl.setStyle("position", "relative");
11201         this.bodyEl.setTop("");
11202         this.bodyEl.setLeft("");
11203         this.bodyEl.show();
11204     },
11205
11206     /**
11207      * Set the tooltip for the tab.
11208      * @param {String} tooltip The tab's tooltip
11209      */
11210     setTooltip : function(text){
11211         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11212             this.textEl.dom.qtip = text;
11213             this.textEl.dom.removeAttribute('title');
11214         }else{
11215             this.textEl.dom.title = text;
11216         }
11217     },
11218
11219     onTabClick : function(e){
11220         e.preventDefault();
11221         this.tabPanel.activate(this.id);
11222     },
11223
11224     onTabMouseDown : function(e){
11225         e.preventDefault();
11226         this.tabPanel.activate(this.id);
11227     },
11228
11229     getWidth : function(){
11230         return this.inner.getWidth();
11231     },
11232
11233     setWidth : function(width){
11234         var iwidth = width - this.pnode.getPadding("lr");
11235         this.inner.setWidth(iwidth);
11236         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11237         this.pnode.setWidth(width);
11238     },
11239
11240     /**
11241      * Show or hide the tab
11242      * @param {Boolean} hidden True to hide or false to show.
11243      */
11244     setHidden : function(hidden){
11245         this.hidden = hidden;
11246         this.pnode.setStyle("display", hidden ? "none" : "");
11247     },
11248
11249     /**
11250      * Returns true if this tab is "hidden"
11251      * @return {Boolean}
11252      */
11253     isHidden : function(){
11254         return this.hidden;
11255     },
11256
11257     /**
11258      * Returns the text for this tab
11259      * @return {String}
11260      */
11261     getText : function(){
11262         return this.text;
11263     },
11264
11265     autoSize : function(){
11266         //this.el.beginMeasure();
11267         this.textEl.setWidth(1);
11268         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11269         //this.el.endMeasure();
11270     },
11271
11272     /**
11273      * Sets the text for the tab (Note: this also sets the tooltip text)
11274      * @param {String} text The tab's text and tooltip
11275      */
11276     setText : function(text){
11277         this.text = text;
11278         this.textEl.update(text);
11279         this.setTooltip(text);
11280         if(!this.tabPanel.resizeTabs){
11281             this.autoSize();
11282         }
11283     },
11284     /**
11285      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11286      */
11287     activate : function(){
11288         this.tabPanel.activate(this.id);
11289     },
11290
11291     /**
11292      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11293      */
11294     disable : function(){
11295         if(this.tabPanel.active != this){
11296             this.disabled = true;
11297             this.pnode.addClass("disabled");
11298         }
11299     },
11300
11301     /**
11302      * Enables this TabPanelItem if it was previously disabled.
11303      */
11304     enable : function(){
11305         this.disabled = false;
11306         this.pnode.removeClass("disabled");
11307     },
11308
11309     /**
11310      * Sets the content for this TabPanelItem.
11311      * @param {String} content The content
11312      * @param {Boolean} loadScripts true to look for and load scripts
11313      */
11314     setContent : function(content, loadScripts){
11315         this.bodyEl.update(content, loadScripts);
11316     },
11317
11318     /**
11319      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11320      * @return {Roo.UpdateManager} The UpdateManager
11321      */
11322     getUpdateManager : function(){
11323         return this.bodyEl.getUpdateManager();
11324     },
11325
11326     /**
11327      * Set a URL to be used to load the content for this TabPanelItem.
11328      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11329      * @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)
11330      * @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)
11331      * @return {Roo.UpdateManager} The UpdateManager
11332      */
11333     setUrl : function(url, params, loadOnce){
11334         if(this.refreshDelegate){
11335             this.un('activate', this.refreshDelegate);
11336         }
11337         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11338         this.on("activate", this.refreshDelegate);
11339         return this.bodyEl.getUpdateManager();
11340     },
11341
11342     /** @private */
11343     _handleRefresh : function(url, params, loadOnce){
11344         if(!loadOnce || !this.loaded){
11345             var updater = this.bodyEl.getUpdateManager();
11346             updater.update(url, params, this._setLoaded.createDelegate(this));
11347         }
11348     },
11349
11350     /**
11351      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
11352      *   Will fail silently if the setUrl method has not been called.
11353      *   This does not activate the panel, just updates its content.
11354      */
11355     refresh : function(){
11356         if(this.refreshDelegate){
11357            this.loaded = false;
11358            this.refreshDelegate();
11359         }
11360     },
11361
11362     /** @private */
11363     _setLoaded : function(){
11364         this.loaded = true;
11365     },
11366
11367     /** @private */
11368     closeClick : function(e){
11369         var o = {};
11370         e.stopEvent();
11371         this.fireEvent("beforeclose", this, o);
11372         if(o.cancel !== true){
11373             this.tabPanel.removeTab(this.id);
11374         }
11375     },
11376     /**
11377      * The text displayed in the tooltip for the close icon.
11378      * @type String
11379      */
11380     closeText : "Close this tab"
11381 });
11382
11383 /** @private */
11384 Roo.TabPanel.prototype.createStrip = function(container){
11385     var strip = document.createElement("div");
11386     strip.className = "x-tabs-wrap";
11387     container.appendChild(strip);
11388     return strip;
11389 };
11390 /** @private */
11391 Roo.TabPanel.prototype.createStripList = function(strip){
11392     // div wrapper for retard IE
11393     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>';
11394     return strip.firstChild.firstChild.firstChild.firstChild;
11395 };
11396 /** @private */
11397 Roo.TabPanel.prototype.createBody = function(container){
11398     var body = document.createElement("div");
11399     Roo.id(body, "tab-body");
11400     Roo.fly(body).addClass("x-tabs-body");
11401     container.appendChild(body);
11402     return body;
11403 };
11404 /** @private */
11405 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11406     var body = Roo.getDom(id);
11407     if(!body){
11408         body = document.createElement("div");
11409         body.id = id;
11410     }
11411     Roo.fly(body).addClass("x-tabs-item-body");
11412     bodyEl.insertBefore(body, bodyEl.firstChild);
11413     return body;
11414 };
11415 /** @private */
11416 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11417     var td = document.createElement("td");
11418     stripEl.appendChild(td);
11419     if(closable){
11420         td.className = "x-tabs-closable";
11421         if(!this.closeTpl){
11422             this.closeTpl = new Roo.Template(
11423                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11424                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11425                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
11426             );
11427         }
11428         var el = this.closeTpl.overwrite(td, {"text": text});
11429         var close = el.getElementsByTagName("div")[0];
11430         var inner = el.getElementsByTagName("em")[0];
11431         return {"el": el, "close": close, "inner": inner};
11432     } else {
11433         if(!this.tabTpl){
11434             this.tabTpl = new Roo.Template(
11435                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11436                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11437             );
11438         }
11439         var el = this.tabTpl.overwrite(td, {"text": text});
11440         var inner = el.getElementsByTagName("em")[0];
11441         return {"el": el, "inner": inner};
11442     }
11443 };/*
11444  * Based on:
11445  * Ext JS Library 1.1.1
11446  * Copyright(c) 2006-2007, Ext JS, LLC.
11447  *
11448  * Originally Released Under LGPL - original licence link has changed is not relivant.
11449  *
11450  * Fork - LGPL
11451  * <script type="text/javascript">
11452  */
11453
11454 /**
11455  * @class Roo.Button
11456  * @extends Roo.util.Observable
11457  * Simple Button class
11458  * @cfg {String} text The button text
11459  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11460  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11461  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11462  * @cfg {Object} scope The scope of the handler
11463  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11464  * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11465  * @cfg {Boolean} hidden True to start hidden (defaults to false)
11466  * @cfg {Boolean} disabled True to start disabled (defaults to false)
11467  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11468  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11469    applies if enableToggle = true)
11470  * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11471  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11472   an {@link Roo.util.ClickRepeater} config object (defaults to false).
11473  * @constructor
11474  * Create a new button
11475  * @param {Object} config The config object
11476  */
11477 Roo.Button = function(renderTo, config)
11478 {
11479     if (!config) {
11480         config = renderTo;
11481         renderTo = config.renderTo || false;
11482     }
11483     
11484     Roo.apply(this, config);
11485     this.addEvents({
11486         /**
11487              * @event click
11488              * Fires when this button is clicked
11489              * @param {Button} this
11490              * @param {EventObject} e The click event
11491              */
11492             "click" : true,
11493         /**
11494              * @event toggle
11495              * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11496              * @param {Button} this
11497              * @param {Boolean} pressed
11498              */
11499             "toggle" : true,
11500         /**
11501              * @event mouseover
11502              * Fires when the mouse hovers over the button
11503              * @param {Button} this
11504              * @param {Event} e The event object
11505              */
11506         'mouseover' : true,
11507         /**
11508              * @event mouseout
11509              * Fires when the mouse exits the button
11510              * @param {Button} this
11511              * @param {Event} e The event object
11512              */
11513         'mouseout': true,
11514          /**
11515              * @event render
11516              * Fires when the button is rendered
11517              * @param {Button} this
11518              */
11519         'render': true
11520     });
11521     if(this.menu){
11522         this.menu = Roo.menu.MenuMgr.get(this.menu);
11523     }
11524     // register listeners first!!  - so render can be captured..
11525     Roo.util.Observable.call(this);
11526     if(renderTo){
11527         this.render(renderTo);
11528     }
11529     
11530   
11531 };
11532
11533 Roo.extend(Roo.Button, Roo.util.Observable, {
11534     /**
11535      * 
11536      */
11537     
11538     /**
11539      * Read-only. True if this button is hidden
11540      * @type Boolean
11541      */
11542     hidden : false,
11543     /**
11544      * Read-only. True if this button is disabled
11545      * @type Boolean
11546      */
11547     disabled : false,
11548     /**
11549      * Read-only. True if this button is pressed (only if enableToggle = true)
11550      * @type Boolean
11551      */
11552     pressed : false,
11553
11554     /**
11555      * @cfg {Number} tabIndex 
11556      * The DOM tabIndex for this button (defaults to undefined)
11557      */
11558     tabIndex : undefined,
11559
11560     /**
11561      * @cfg {Boolean} enableToggle
11562      * True to enable pressed/not pressed toggling (defaults to false)
11563      */
11564     enableToggle: false,
11565     /**
11566      * @cfg {Mixed} menu
11567      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11568      */
11569     menu : undefined,
11570     /**
11571      * @cfg {String} menuAlign
11572      * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11573      */
11574     menuAlign : "tl-bl?",
11575
11576     /**
11577      * @cfg {String} iconCls
11578      * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11579      */
11580     iconCls : undefined,
11581     /**
11582      * @cfg {String} type
11583      * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
11584      */
11585     type : 'button',
11586
11587     // private
11588     menuClassTarget: 'tr',
11589
11590     /**
11591      * @cfg {String} clickEvent
11592      * The type of event to map to the button's event handler (defaults to 'click')
11593      */
11594     clickEvent : 'click',
11595
11596     /**
11597      * @cfg {Boolean} handleMouseEvents
11598      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11599      */
11600     handleMouseEvents : true,
11601
11602     /**
11603      * @cfg {String} tooltipType
11604      * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11605      */
11606     tooltipType : 'qtip',
11607
11608     /**
11609      * @cfg {String} cls
11610      * A CSS class to apply to the button's main element.
11611      */
11612     
11613     /**
11614      * @cfg {Roo.Template} template (Optional)
11615      * An {@link Roo.Template} with which to create the Button's main element. This Template must
11616      * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11617      * require code modifications if required elements (e.g. a button) aren't present.
11618      */
11619
11620     // private
11621     render : function(renderTo){
11622         var btn;
11623         if(this.hideParent){
11624             this.parentEl = Roo.get(renderTo);
11625         }
11626         if(!this.dhconfig){
11627             if(!this.template){
11628                 if(!Roo.Button.buttonTemplate){
11629                     // hideous table template
11630                     Roo.Button.buttonTemplate = new Roo.Template(
11631                         '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11632                         '<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>',
11633                         "</tr></tbody></table>");
11634                 }
11635                 this.template = Roo.Button.buttonTemplate;
11636             }
11637             btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
11638             var btnEl = btn.child("button:first");
11639             btnEl.on('focus', this.onFocus, this);
11640             btnEl.on('blur', this.onBlur, this);
11641             if(this.cls){
11642                 btn.addClass(this.cls);
11643             }
11644             if(this.icon){
11645                 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11646             }
11647             if(this.iconCls){
11648                 btnEl.addClass(this.iconCls);
11649                 if(!this.cls){
11650                     btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11651                 }
11652             }
11653             if(this.tabIndex !== undefined){
11654                 btnEl.dom.tabIndex = this.tabIndex;
11655             }
11656             if(this.tooltip){
11657                 if(typeof this.tooltip == 'object'){
11658                     Roo.QuickTips.tips(Roo.apply({
11659                           target: btnEl.id
11660                     }, this.tooltip));
11661                 } else {
11662                     btnEl.dom[this.tooltipType] = this.tooltip;
11663                 }
11664             }
11665         }else{
11666             btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11667         }
11668         this.el = btn;
11669         if(this.id){
11670             this.el.dom.id = this.el.id = this.id;
11671         }
11672         if(this.menu){
11673             this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11674             this.menu.on("show", this.onMenuShow, this);
11675             this.menu.on("hide", this.onMenuHide, this);
11676         }
11677         btn.addClass("x-btn");
11678         if(Roo.isIE && !Roo.isIE7){
11679             this.autoWidth.defer(1, this);
11680         }else{
11681             this.autoWidth();
11682         }
11683         if(this.handleMouseEvents){
11684             btn.on("mouseover", this.onMouseOver, this);
11685             btn.on("mouseout", this.onMouseOut, this);
11686             btn.on("mousedown", this.onMouseDown, this);
11687         }
11688         btn.on(this.clickEvent, this.onClick, this);
11689         //btn.on("mouseup", this.onMouseUp, this);
11690         if(this.hidden){
11691             this.hide();
11692         }
11693         if(this.disabled){
11694             this.disable();
11695         }
11696         Roo.ButtonToggleMgr.register(this);
11697         if(this.pressed){
11698             this.el.addClass("x-btn-pressed");
11699         }
11700         if(this.repeat){
11701             var repeater = new Roo.util.ClickRepeater(btn,
11702                 typeof this.repeat == "object" ? this.repeat : {}
11703             );
11704             repeater.on("click", this.onClick,  this);
11705         }
11706         
11707         this.fireEvent('render', this);
11708         
11709     },
11710     /**
11711      * Returns the button's underlying element
11712      * @return {Roo.Element} The element
11713      */
11714     getEl : function(){
11715         return this.el;  
11716     },
11717     
11718     /**
11719      * Destroys this Button and removes any listeners.
11720      */
11721     destroy : function(){
11722         Roo.ButtonToggleMgr.unregister(this);
11723         this.el.removeAllListeners();
11724         this.purgeListeners();
11725         this.el.remove();
11726     },
11727
11728     // private
11729     autoWidth : function(){
11730         if(this.el){
11731             this.el.setWidth("auto");
11732             if(Roo.isIE7 && Roo.isStrict){
11733                 var ib = this.el.child('button');
11734                 if(ib && ib.getWidth() > 20){
11735                     ib.clip();
11736                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11737                 }
11738             }
11739             if(this.minWidth){
11740                 if(this.hidden){
11741                     this.el.beginMeasure();
11742                 }
11743                 if(this.el.getWidth() < this.minWidth){
11744                     this.el.setWidth(this.minWidth);
11745                 }
11746                 if(this.hidden){
11747                     this.el.endMeasure();
11748                 }
11749             }
11750         }
11751     },
11752
11753     /**
11754      * Assigns this button's click handler
11755      * @param {Function} handler The function to call when the button is clicked
11756      * @param {Object} scope (optional) Scope for the function passed in
11757      */
11758     setHandler : function(handler, scope){
11759         this.handler = handler;
11760         this.scope = scope;  
11761     },
11762     
11763     /**
11764      * Sets this button's text
11765      * @param {String} text The button text
11766      */
11767     setText : function(text){
11768         this.text = text;
11769         if(this.el){
11770             this.el.child("td.x-btn-center button.x-btn-text").update(text);
11771         }
11772         this.autoWidth();
11773     },
11774     
11775     /**
11776      * Gets the text for this button
11777      * @return {String} The button text
11778      */
11779     getText : function(){
11780         return this.text;  
11781     },
11782     
11783     /**
11784      * Show this button
11785      */
11786     show: function(){
11787         this.hidden = false;
11788         if(this.el){
11789             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11790         }
11791     },
11792     
11793     /**
11794      * Hide this button
11795      */
11796     hide: function(){
11797         this.hidden = true;
11798         if(this.el){
11799             this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11800         }
11801     },
11802     
11803     /**
11804      * Convenience function for boolean show/hide
11805      * @param {Boolean} visible True to show, false to hide
11806      */
11807     setVisible: function(visible){
11808         if(visible) {
11809             this.show();
11810         }else{
11811             this.hide();
11812         }
11813     },
11814     
11815     /**
11816      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11817      * @param {Boolean} state (optional) Force a particular state
11818      */
11819     toggle : function(state){
11820         state = state === undefined ? !this.pressed : state;
11821         if(state != this.pressed){
11822             if(state){
11823                 this.el.addClass("x-btn-pressed");
11824                 this.pressed = true;
11825                 this.fireEvent("toggle", this, true);
11826             }else{
11827                 this.el.removeClass("x-btn-pressed");
11828                 this.pressed = false;
11829                 this.fireEvent("toggle", this, false);
11830             }
11831             if(this.toggleHandler){
11832                 this.toggleHandler.call(this.scope || this, this, state);
11833             }
11834         }
11835     },
11836     
11837     /**
11838      * Focus the button
11839      */
11840     focus : function(){
11841         this.el.child('button:first').focus();
11842     },
11843     
11844     /**
11845      * Disable this button
11846      */
11847     disable : function(){
11848         if(this.el){
11849             this.el.addClass("x-btn-disabled");
11850         }
11851         this.disabled = true;
11852     },
11853     
11854     /**
11855      * Enable this button
11856      */
11857     enable : function(){
11858         if(this.el){
11859             this.el.removeClass("x-btn-disabled");
11860         }
11861         this.disabled = false;
11862     },
11863
11864     /**
11865      * Convenience function for boolean enable/disable
11866      * @param {Boolean} enabled True to enable, false to disable
11867      */
11868     setDisabled : function(v){
11869         this[v !== true ? "enable" : "disable"]();
11870     },
11871
11872     // private
11873     onClick : function(e){
11874         if(e){
11875             e.preventDefault();
11876         }
11877         if(e.button != 0){
11878             return;
11879         }
11880         if(!this.disabled){
11881             if(this.enableToggle){
11882                 this.toggle();
11883             }
11884             if(this.menu && !this.menu.isVisible()){
11885                 this.menu.show(this.el, this.menuAlign);
11886             }
11887             this.fireEvent("click", this, e);
11888             if(this.handler){
11889                 this.el.removeClass("x-btn-over");
11890                 this.handler.call(this.scope || this, this, e);
11891             }
11892         }
11893     },
11894     // private
11895     onMouseOver : function(e){
11896         if(!this.disabled){
11897             this.el.addClass("x-btn-over");
11898             this.fireEvent('mouseover', this, e);
11899         }
11900     },
11901     // private
11902     onMouseOut : function(e){
11903         if(!e.within(this.el,  true)){
11904             this.el.removeClass("x-btn-over");
11905             this.fireEvent('mouseout', this, e);
11906         }
11907     },
11908     // private
11909     onFocus : function(e){
11910         if(!this.disabled){
11911             this.el.addClass("x-btn-focus");
11912         }
11913     },
11914     // private
11915     onBlur : function(e){
11916         this.el.removeClass("x-btn-focus");
11917     },
11918     // private
11919     onMouseDown : function(e){
11920         if(!this.disabled && e.button == 0){
11921             this.el.addClass("x-btn-click");
11922             Roo.get(document).on('mouseup', this.onMouseUp, this);
11923         }
11924     },
11925     // private
11926     onMouseUp : function(e){
11927         if(e.button == 0){
11928             this.el.removeClass("x-btn-click");
11929             Roo.get(document).un('mouseup', this.onMouseUp, this);
11930         }
11931     },
11932     // private
11933     onMenuShow : function(e){
11934         this.el.addClass("x-btn-menu-active");
11935     },
11936     // private
11937     onMenuHide : function(e){
11938         this.el.removeClass("x-btn-menu-active");
11939     }   
11940 });
11941
11942 // Private utility class used by Button
11943 Roo.ButtonToggleMgr = function(){
11944    var groups = {};
11945    
11946    function toggleGroup(btn, state){
11947        if(state){
11948            var g = groups[btn.toggleGroup];
11949            for(var i = 0, l = g.length; i < l; i++){
11950                if(g[i] != btn){
11951                    g[i].toggle(false);
11952                }
11953            }
11954        }
11955    }
11956    
11957    return {
11958        register : function(btn){
11959            if(!btn.toggleGroup){
11960                return;
11961            }
11962            var g = groups[btn.toggleGroup];
11963            if(!g){
11964                g = groups[btn.toggleGroup] = [];
11965            }
11966            g.push(btn);
11967            btn.on("toggle", toggleGroup);
11968        },
11969        
11970        unregister : function(btn){
11971            if(!btn.toggleGroup){
11972                return;
11973            }
11974            var g = groups[btn.toggleGroup];
11975            if(g){
11976                g.remove(btn);
11977                btn.un("toggle", toggleGroup);
11978            }
11979        }
11980    };
11981 }();/*
11982  * Based on:
11983  * Ext JS Library 1.1.1
11984  * Copyright(c) 2006-2007, Ext JS, LLC.
11985  *
11986  * Originally Released Under LGPL - original licence link has changed is not relivant.
11987  *
11988  * Fork - LGPL
11989  * <script type="text/javascript">
11990  */
11991  
11992 /**
11993  * @class Roo.SplitButton
11994  * @extends Roo.Button
11995  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11996  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
11997  * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11998  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11999  * @cfg {String} arrowTooltip The title attribute of the arrow
12000  * @constructor
12001  * Create a new menu button
12002  * @param {String/HTMLElement/Element} renderTo The element to append the button to
12003  * @param {Object} config The config object
12004  */
12005 Roo.SplitButton = function(renderTo, config){
12006     Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12007     /**
12008      * @event arrowclick
12009      * Fires when this button's arrow is clicked
12010      * @param {SplitButton} this
12011      * @param {EventObject} e The click event
12012      */
12013     this.addEvents({"arrowclick":true});
12014 };
12015
12016 Roo.extend(Roo.SplitButton, Roo.Button, {
12017     render : function(renderTo){
12018         // this is one sweet looking template!
12019         var tpl = new Roo.Template(
12020             '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12021             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12022             '<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>',
12023             "</tbody></table></td><td>",
12024             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12025             '<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>',
12026             "</tbody></table></td></tr></table>"
12027         );
12028         var btn = tpl.append(renderTo, [this.text, this.type], true);
12029         var btnEl = btn.child("button");
12030         if(this.cls){
12031             btn.addClass(this.cls);
12032         }
12033         if(this.icon){
12034             btnEl.setStyle('background-image', 'url(' +this.icon +')');
12035         }
12036         if(this.iconCls){
12037             btnEl.addClass(this.iconCls);
12038             if(!this.cls){
12039                 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12040             }
12041         }
12042         this.el = btn;
12043         if(this.handleMouseEvents){
12044             btn.on("mouseover", this.onMouseOver, this);
12045             btn.on("mouseout", this.onMouseOut, this);
12046             btn.on("mousedown", this.onMouseDown, this);
12047             btn.on("mouseup", this.onMouseUp, this);
12048         }
12049         btn.on(this.clickEvent, this.onClick, this);
12050         if(this.tooltip){
12051             if(typeof this.tooltip == 'object'){
12052                 Roo.QuickTips.tips(Roo.apply({
12053                       target: btnEl.id
12054                 }, this.tooltip));
12055             } else {
12056                 btnEl.dom[this.tooltipType] = this.tooltip;
12057             }
12058         }
12059         if(this.arrowTooltip){
12060             btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12061         }
12062         if(this.hidden){
12063             this.hide();
12064         }
12065         if(this.disabled){
12066             this.disable();
12067         }
12068         if(this.pressed){
12069             this.el.addClass("x-btn-pressed");
12070         }
12071         if(Roo.isIE && !Roo.isIE7){
12072             this.autoWidth.defer(1, this);
12073         }else{
12074             this.autoWidth();
12075         }
12076         if(this.menu){
12077             this.menu.on("show", this.onMenuShow, this);
12078             this.menu.on("hide", this.onMenuHide, this);
12079         }
12080         this.fireEvent('render', this);
12081     },
12082
12083     // private
12084     autoWidth : function(){
12085         if(this.el){
12086             var tbl = this.el.child("table:first");
12087             var tbl2 = this.el.child("table:last");
12088             this.el.setWidth("auto");
12089             tbl.setWidth("auto");
12090             if(Roo.isIE7 && Roo.isStrict){
12091                 var ib = this.el.child('button:first');
12092                 if(ib && ib.getWidth() > 20){
12093                     ib.clip();
12094                     ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12095                 }
12096             }
12097             if(this.minWidth){
12098                 if(this.hidden){
12099                     this.el.beginMeasure();
12100                 }
12101                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12102                     tbl.setWidth(this.minWidth-tbl2.getWidth());
12103                 }
12104                 if(this.hidden){
12105                     this.el.endMeasure();
12106                 }
12107             }
12108             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12109         } 
12110     },
12111     /**
12112      * Sets this button's click handler
12113      * @param {Function} handler The function to call when the button is clicked
12114      * @param {Object} scope (optional) Scope for the function passed above
12115      */
12116     setHandler : function(handler, scope){
12117         this.handler = handler;
12118         this.scope = scope;  
12119     },
12120     
12121     /**
12122      * Sets this button's arrow click handler
12123      * @param {Function} handler The function to call when the arrow is clicked
12124      * @param {Object} scope (optional) Scope for the function passed above
12125      */
12126     setArrowHandler : function(handler, scope){
12127         this.arrowHandler = handler;
12128         this.scope = scope;  
12129     },
12130     
12131     /**
12132      * Focus the button
12133      */
12134     focus : function(){
12135         if(this.el){
12136             this.el.child("button:first").focus();
12137         }
12138     },
12139
12140     // private
12141     onClick : function(e){
12142         e.preventDefault();
12143         if(!this.disabled){
12144             if(e.getTarget(".x-btn-menu-arrow-wrap")){
12145                 if(this.menu && !this.menu.isVisible()){
12146                     this.menu.show(this.el, this.menuAlign);
12147                 }
12148                 this.fireEvent("arrowclick", this, e);
12149                 if(this.arrowHandler){
12150                     this.arrowHandler.call(this.scope || this, this, e);
12151                 }
12152             }else{
12153                 this.fireEvent("click", this, e);
12154                 if(this.handler){
12155                     this.handler.call(this.scope || this, this, e);
12156                 }
12157             }
12158         }
12159     },
12160     // private
12161     onMouseDown : function(e){
12162         if(!this.disabled){
12163             Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12164         }
12165     },
12166     // private
12167     onMouseUp : function(e){
12168         Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12169     }   
12170 });
12171
12172
12173 // backwards compat
12174 Roo.MenuButton = Roo.SplitButton;