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|String} valid true/false or string (add/sub/ok/nodrop)
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 typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4024             this.valid ? this.dropAllowed : this.dropNotAllowed
4025         );
4026     },
4027
4028     /**
4029      * @hide
4030      */
4031     notifyOver : function(dd, e, data){
4032         this.valid = true;
4033         this.fireEvent('over', this, dd, e, data);
4034         return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4035             this.valid ? this.dropAllowed : this.dropNotAllowed
4036         );
4037     },
4038
4039     /**
4040      * @hide
4041      */
4042     notifyOut : function(dd, e, data){
4043         this.fireEvent('out', this, dd, e, data);
4044         if(this.overClass){
4045             this.el.removeClass(this.overClass);
4046         }
4047     },
4048
4049     /**
4050      * @hide
4051      */
4052     notifyDrop : function(dd, e, data){
4053         this.success = false;
4054         this.fireEvent('drop', this, dd, e, data);
4055         return this.success;
4056     }
4057 });/*
4058  * Based on:
4059  * Ext JS Library 1.1.1
4060  * Copyright(c) 2006-2007, Ext JS, LLC.
4061  *
4062  * Originally Released Under LGPL - original licence link has changed is not relivant.
4063  *
4064  * Fork - LGPL
4065  * <script type="text/javascript">
4066  */
4067
4068
4069 /**
4070  * @class Roo.dd.DragZone
4071  * @extends Roo.dd.DragSource
4072  * This class provides a container DD instance that proxies for multiple child node sources.<br />
4073  * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4074  * @constructor
4075  * @param {String/HTMLElement/Element} el The container element
4076  * @param {Object} config
4077  */
4078 Roo.dd.DragZone = function(el, config){
4079     Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4080     if(this.containerScroll){
4081         Roo.dd.ScrollManager.register(this.el);
4082     }
4083 };
4084
4085 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4086     /**
4087      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4088      * for auto scrolling during drag operations.
4089      */
4090     /**
4091      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4092      * method after a failed drop (defaults to "c3daf9" - light blue)
4093      */
4094
4095     /**
4096      * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4097      * for a valid target to drag based on the mouse down. Override this method
4098      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4099      * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4100      * @param {EventObject} e The mouse down event
4101      * @return {Object} The dragData
4102      */
4103     getDragData : function(e){
4104         return Roo.dd.Registry.getHandleFromEvent(e);
4105     },
4106     
4107     /**
4108      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4109      * this.dragData.ddel
4110      * @param {Number} x The x position of the click on the dragged object
4111      * @param {Number} y The y position of the click on the dragged object
4112      * @return {Boolean} true to continue the drag, false to cancel
4113      */
4114     onInitDrag : function(x, y){
4115         this.proxy.update(this.dragData.ddel.cloneNode(true));
4116         this.onStartDrag(x, y);
4117         return true;
4118     },
4119     
4120     /**
4121      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
4122      */
4123     afterRepair : function(){
4124         if(Roo.enableFx){
4125             Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4126         }
4127         this.dragging = false;
4128     },
4129
4130     /**
4131      * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4132      * the XY of this.dragData.ddel
4133      * @param {EventObject} e The mouse up event
4134      * @return {Array} The xy location (e.g. [100, 200])
4135      */
4136     getRepairXY : function(e){
4137         return Roo.Element.fly(this.dragData.ddel).getXY();  
4138     }
4139 });/*
4140  * Based on:
4141  * Ext JS Library 1.1.1
4142  * Copyright(c) 2006-2007, Ext JS, LLC.
4143  *
4144  * Originally Released Under LGPL - original licence link has changed is not relivant.
4145  *
4146  * Fork - LGPL
4147  * <script type="text/javascript">
4148  */
4149 /**
4150  * @class Roo.dd.DropZone
4151  * @extends Roo.dd.DropTarget
4152  * This class provides a container DD instance that proxies for multiple child node targets.<br />
4153  * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4154  * @constructor
4155  * @param {String/HTMLElement/Element} el The container element
4156  * @param {Object} config
4157  */
4158 Roo.dd.DropZone = function(el, config){
4159     Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4160 };
4161
4162 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4163     /**
4164      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
4165      * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4166      * provide your own custom lookup.
4167      * @param {Event} e The event
4168      * @return {Object} data The custom data
4169      */
4170     getTargetFromEvent : function(e){
4171         return Roo.dd.Registry.getTargetFromEvent(e);
4172     },
4173
4174     /**
4175      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4176      * that it has registered.  This method has no default implementation and should be overridden to provide
4177      * node-specific processing if necessary.
4178      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
4179      * {@link #getTargetFromEvent} for this node)
4180      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4181      * @param {Event} e The event
4182      * @param {Object} data An object containing arbitrary data supplied by the drag source
4183      */
4184     onNodeEnter : function(n, dd, e, data){
4185         
4186     },
4187
4188     /**
4189      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4190      * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
4191      * overridden to provide the proper feedback.
4192      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4193      * {@link #getTargetFromEvent} for this node)
4194      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4195      * @param {Event} e The event
4196      * @param {Object} data An object containing arbitrary data supplied by the drag source
4197      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4198      * underlying {@link Roo.dd.StatusProxy} can be updated
4199      */
4200     onNodeOver : function(n, dd, e, data){
4201         return this.dropAllowed;
4202     },
4203
4204     /**
4205      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4206      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
4207      * node-specific processing if necessary.
4208      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4209      * {@link #getTargetFromEvent} for this node)
4210      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4211      * @param {Event} e The event
4212      * @param {Object} data An object containing arbitrary data supplied by the drag source
4213      */
4214     onNodeOut : function(n, dd, e, data){
4215         
4216     },
4217
4218     /**
4219      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4220      * the drop node.  The default implementation returns false, so it should be overridden to provide the
4221      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4222      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4223      * {@link #getTargetFromEvent} for this node)
4224      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4225      * @param {Event} e The event
4226      * @param {Object} data An object containing arbitrary data supplied by the drag source
4227      * @return {Boolean} True if the drop was valid, else false
4228      */
4229     onNodeDrop : function(n, dd, e, data){
4230         return false;
4231     },
4232
4233     /**
4234      * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4235      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
4236      * it should be overridden to provide the proper feedback if necessary.
4237      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4238      * @param {Event} e The event
4239      * @param {Object} data An object containing arbitrary data supplied by the drag source
4240      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4241      * underlying {@link Roo.dd.StatusProxy} can be updated
4242      */
4243     onContainerOver : function(dd, e, data){
4244         return this.dropNotAllowed;
4245     },
4246
4247     /**
4248      * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4249      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
4250      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4251      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
4252      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4253      * @param {Event} e The event
4254      * @param {Object} data An object containing arbitrary data supplied by the drag source
4255      * @return {Boolean} True if the drop was valid, else false
4256      */
4257     onContainerDrop : function(dd, e, data){
4258         return false;
4259     },
4260
4261     /**
4262      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4263      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
4264      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4265      * you should override this method and provide a custom implementation.
4266      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4267      * @param {Event} e The event
4268      * @param {Object} data An object containing arbitrary data supplied by the drag source
4269      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4270      * underlying {@link Roo.dd.StatusProxy} can be updated
4271      */
4272     notifyEnter : function(dd, e, data){
4273         return this.dropNotAllowed;
4274     },
4275
4276     /**
4277      * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4278      * This method will be called on every mouse movement while the drag source is over the drop zone.
4279      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4280      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4281      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4282      * registered node, it will call {@link #onContainerOver}.
4283      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4284      * @param {Event} e The event
4285      * @param {Object} data An object containing arbitrary data supplied by the drag source
4286      * @return {String} status The CSS class that communicates the drop status back to the source so that the
4287      * underlying {@link Roo.dd.StatusProxy} can be updated
4288      */
4289     notifyOver : function(dd, e, data){
4290         var n = this.getTargetFromEvent(e);
4291         if(!n){ // not over valid drop target
4292             if(this.lastOverNode){
4293                 this.onNodeOut(this.lastOverNode, dd, e, data);
4294                 this.lastOverNode = null;
4295             }
4296             return this.onContainerOver(dd, e, data);
4297         }
4298         if(this.lastOverNode != n){
4299             if(this.lastOverNode){
4300                 this.onNodeOut(this.lastOverNode, dd, e, data);
4301             }
4302             this.onNodeEnter(n, dd, e, data);
4303             this.lastOverNode = n;
4304         }
4305         return this.onNodeOver(n, dd, e, data);
4306     },
4307
4308     /**
4309      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4310      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
4311      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4312      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4313      * @param {Event} e The event
4314      * @param {Object} data An object containing arbitrary data supplied by the drag zone
4315      */
4316     notifyOut : function(dd, e, data){
4317         if(this.lastOverNode){
4318             this.onNodeOut(this.lastOverNode, dd, e, data);
4319             this.lastOverNode = null;
4320         }
4321     },
4322
4323     /**
4324      * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4325      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
4326      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4327      * otherwise it will call {@link #onContainerDrop}.
4328      * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4329      * @param {Event} e The event
4330      * @param {Object} data An object containing arbitrary data supplied by the drag source
4331      * @return {Boolean} True if the drop was valid, else false
4332      */
4333     notifyDrop : function(dd, e, data){
4334         if(this.lastOverNode){
4335             this.onNodeOut(this.lastOverNode, dd, e, data);
4336             this.lastOverNode = null;
4337         }
4338         var n = this.getTargetFromEvent(e);
4339         return n ?
4340             this.onNodeDrop(n, dd, e, data) :
4341             this.onContainerDrop(dd, e, data);
4342     },
4343
4344     // private
4345     triggerCacheRefresh : function(){
4346         Roo.dd.DDM.refreshCache(this.groups);
4347     }  
4348 });/*
4349  * Based on:
4350  * Ext JS Library 1.1.1
4351  * Copyright(c) 2006-2007, Ext JS, LLC.
4352  *
4353  * Originally Released Under LGPL - original licence link has changed is not relivant.
4354  *
4355  * Fork - LGPL
4356  * <script type="text/javascript">
4357  */
4358
4359
4360 /**
4361  * @class Roo.data.SortTypes
4362  * @singleton
4363  * Defines the default sorting (casting?) comparison functions used when sorting data.
4364  */
4365 Roo.data.SortTypes = {
4366     /**
4367      * Default sort that does nothing
4368      * @param {Mixed} s The value being converted
4369      * @return {Mixed} The comparison value
4370      */
4371     none : function(s){
4372         return s;
4373     },
4374     
4375     /**
4376      * The regular expression used to strip tags
4377      * @type {RegExp}
4378      * @property
4379      */
4380     stripTagsRE : /<\/?[^>]+>/gi,
4381     
4382     /**
4383      * Strips all HTML tags to sort on text only
4384      * @param {Mixed} s The value being converted
4385      * @return {String} The comparison value
4386      */
4387     asText : function(s){
4388         return String(s).replace(this.stripTagsRE, "");
4389     },
4390     
4391     /**
4392      * Strips all HTML tags to sort on text only - Case insensitive
4393      * @param {Mixed} s The value being converted
4394      * @return {String} The comparison value
4395      */
4396     asUCText : function(s){
4397         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4398     },
4399     
4400     /**
4401      * Case insensitive string
4402      * @param {Mixed} s The value being converted
4403      * @return {String} The comparison value
4404      */
4405     asUCString : function(s) {
4406         return String(s).toUpperCase();
4407     },
4408     
4409     /**
4410      * Date sorting
4411      * @param {Mixed} s The value being converted
4412      * @return {Number} The comparison value
4413      */
4414     asDate : function(s) {
4415         if(!s){
4416             return 0;
4417         }
4418         if(s instanceof Date){
4419             return s.getTime();
4420         }
4421         return Date.parse(String(s));
4422     },
4423     
4424     /**
4425      * Float sorting
4426      * @param {Mixed} s The value being converted
4427      * @return {Float} The comparison value
4428      */
4429     asFloat : function(s) {
4430         var val = parseFloat(String(s).replace(/,/g, ""));
4431         if(isNaN(val)) val = 0;
4432         return val;
4433     },
4434     
4435     /**
4436      * Integer sorting
4437      * @param {Mixed} s The value being converted
4438      * @return {Number} The comparison value
4439      */
4440     asInt : function(s) {
4441         var val = parseInt(String(s).replace(/,/g, ""));
4442         if(isNaN(val)) val = 0;
4443         return val;
4444     }
4445 };/*
4446  * Based on:
4447  * Ext JS Library 1.1.1
4448  * Copyright(c) 2006-2007, Ext JS, LLC.
4449  *
4450  * Originally Released Under LGPL - original licence link has changed is not relivant.
4451  *
4452  * Fork - LGPL
4453  * <script type="text/javascript">
4454  */
4455
4456 /**
4457 * @class Roo.data.Record
4458  * Instances of this class encapsulate both record <em>definition</em> information, and record
4459  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4460  * to access Records cached in an {@link Roo.data.Store} object.<br>
4461  * <p>
4462  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4463  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4464  * objects.<br>
4465  * <p>
4466  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4467  * @constructor
4468  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4469  * {@link #create}. The parameters are the same.
4470  * @param {Array} data An associative Array of data values keyed by the field name.
4471  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4472  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4473  * not specified an integer id is generated.
4474  */
4475 Roo.data.Record = function(data, id){
4476     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4477     this.data = data;
4478 };
4479
4480 /**
4481  * Generate a constructor for a specific record layout.
4482  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4483  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4484  * Each field definition object may contain the following properties: <ul>
4485  * <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,
4486  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4487  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4488  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4489  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4490  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4491  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4492  * this may be omitted.</p></li>
4493  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4494  * <ul><li>auto (Default, implies no conversion)</li>
4495  * <li>string</li>
4496  * <li>int</li>
4497  * <li>float</li>
4498  * <li>boolean</li>
4499  * <li>date</li></ul></p></li>
4500  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4501  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4502  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4503  * by the Reader into an object that will be stored in the Record. It is passed the
4504  * following parameters:<ul>
4505  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4506  * </ul></p></li>
4507  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4508  * </ul>
4509  * <br>usage:<br><pre><code>
4510 var TopicRecord = Roo.data.Record.create(
4511     {name: 'title', mapping: 'topic_title'},
4512     {name: 'author', mapping: 'username'},
4513     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4514     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4515     {name: 'lastPoster', mapping: 'user2'},
4516     {name: 'excerpt', mapping: 'post_text'}
4517 );
4518
4519 var myNewRecord = new TopicRecord({
4520     title: 'Do my job please',
4521     author: 'noobie',
4522     totalPosts: 1,
4523     lastPost: new Date(),
4524     lastPoster: 'Animal',
4525     excerpt: 'No way dude!'
4526 });
4527 myStore.add(myNewRecord);
4528 </code></pre>
4529  * @method create
4530  * @static
4531  */
4532 Roo.data.Record.create = function(o){
4533     var f = function(){
4534         f.superclass.constructor.apply(this, arguments);
4535     };
4536     Roo.extend(f, Roo.data.Record);
4537     var p = f.prototype;
4538     p.fields = new Roo.util.MixedCollection(false, function(field){
4539         return field.name;
4540     });
4541     for(var i = 0, len = o.length; i < len; i++){
4542         p.fields.add(new Roo.data.Field(o[i]));
4543     }
4544     f.getField = function(name){
4545         return p.fields.get(name);  
4546     };
4547     return f;
4548 };
4549
4550 Roo.data.Record.AUTO_ID = 1000;
4551 Roo.data.Record.EDIT = 'edit';
4552 Roo.data.Record.REJECT = 'reject';
4553 Roo.data.Record.COMMIT = 'commit';
4554
4555 Roo.data.Record.prototype = {
4556     /**
4557      * Readonly flag - true if this record has been modified.
4558      * @type Boolean
4559      */
4560     dirty : false,
4561     editing : false,
4562     error: null,
4563     modified: null,
4564
4565     // private
4566     join : function(store){
4567         this.store = store;
4568     },
4569
4570     /**
4571      * Set the named field to the specified value.
4572      * @param {String} name The name of the field to set.
4573      * @param {Object} value The value to set the field to.
4574      */
4575     set : function(name, value){
4576         if(this.data[name] == value){
4577             return;
4578         }
4579         this.dirty = true;
4580         if(!this.modified){
4581             this.modified = {};
4582         }
4583         if(typeof this.modified[name] == 'undefined'){
4584             this.modified[name] = this.data[name];
4585         }
4586         this.data[name] = value;
4587         if(!this.editing){
4588             this.store.afterEdit(this);
4589         }       
4590     },
4591
4592     /**
4593      * Get the value of the named field.
4594      * @param {String} name The name of the field to get the value of.
4595      * @return {Object} The value of the field.
4596      */
4597     get : function(name){
4598         return this.data[name]; 
4599     },
4600
4601     // private
4602     beginEdit : function(){
4603         this.editing = true;
4604         this.modified = {}; 
4605     },
4606
4607     // private
4608     cancelEdit : function(){
4609         this.editing = false;
4610         delete this.modified;
4611     },
4612
4613     // private
4614     endEdit : function(){
4615         this.editing = false;
4616         if(this.dirty && this.store){
4617             this.store.afterEdit(this);
4618         }
4619     },
4620
4621     /**
4622      * Usually called by the {@link Roo.data.Store} which owns the Record.
4623      * Rejects all changes made to the Record since either creation, or the last commit operation.
4624      * Modified fields are reverted to their original values.
4625      * <p>
4626      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4627      * of reject operations.
4628      */
4629     reject : function(){
4630         var m = this.modified;
4631         for(var n in m){
4632             if(typeof m[n] != "function"){
4633                 this.data[n] = m[n];
4634             }
4635         }
4636         this.dirty = false;
4637         delete this.modified;
4638         this.editing = false;
4639         if(this.store){
4640             this.store.afterReject(this);
4641         }
4642     },
4643
4644     /**
4645      * Usually called by the {@link Roo.data.Store} which owns the Record.
4646      * Commits all changes made to the Record since either creation, or the last commit operation.
4647      * <p>
4648      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4649      * of commit operations.
4650      */
4651     commit : function(){
4652         this.dirty = false;
4653         delete this.modified;
4654         this.editing = false;
4655         if(this.store){
4656             this.store.afterCommit(this);
4657         }
4658     },
4659
4660     // private
4661     hasError : function(){
4662         return this.error != null;
4663     },
4664
4665     // private
4666     clearError : function(){
4667         this.error = null;
4668     },
4669
4670     /**
4671      * Creates a copy of this record.
4672      * @param {String} id (optional) A new record id if you don't want to use this record's id
4673      * @return {Record}
4674      */
4675     copy : function(newId) {
4676         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4677     }
4678 };/*
4679  * Based on:
4680  * Ext JS Library 1.1.1
4681  * Copyright(c) 2006-2007, Ext JS, LLC.
4682  *
4683  * Originally Released Under LGPL - original licence link has changed is not relivant.
4684  *
4685  * Fork - LGPL
4686  * <script type="text/javascript">
4687  */
4688
4689
4690
4691 /**
4692  * @class Roo.data.Store
4693  * @extends Roo.util.Observable
4694  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4695  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4696  * <p>
4697  * 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
4698  * has no knowledge of the format of the data returned by the Proxy.<br>
4699  * <p>
4700  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4701  * instances from the data object. These records are cached and made available through accessor functions.
4702  * @constructor
4703  * Creates a new Store.
4704  * @param {Object} config A config object containing the objects needed for the Store to access data,
4705  * and read the data into Records.
4706  */
4707 Roo.data.Store = function(config){
4708     this.data = new Roo.util.MixedCollection(false);
4709     this.data.getKey = function(o){
4710         return o.id;
4711     };
4712     this.baseParams = {};
4713     // private
4714     this.paramNames = {
4715         "start" : "start",
4716         "limit" : "limit",
4717         "sort" : "sort",
4718         "dir" : "dir"
4719     };
4720
4721     if(config && config.data){
4722         this.inlineData = config.data;
4723         delete config.data;
4724     }
4725
4726     Roo.apply(this, config);
4727     
4728     if(this.reader){ // reader passed
4729         this.reader = Roo.factory(this.reader, Roo.data);
4730         this.reader.xmodule = this.xmodule || false;
4731         if(!this.recordType){
4732             this.recordType = this.reader.recordType;
4733         }
4734         if(this.reader.onMetaChange){
4735             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4736         }
4737     }
4738
4739     if(this.recordType){
4740         this.fields = this.recordType.prototype.fields;
4741     }
4742     this.modified = [];
4743
4744     this.addEvents({
4745         /**
4746          * @event datachanged
4747          * Fires when the data cache has changed, and a widget which is using this Store
4748          * as a Record cache should refresh its view.
4749          * @param {Store} this
4750          */
4751         datachanged : true,
4752         /**
4753          * @event metachange
4754          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4755          * @param {Store} this
4756          * @param {Object} meta The JSON metadata
4757          */
4758         metachange : true,
4759         /**
4760          * @event add
4761          * Fires when Records have been added to the Store
4762          * @param {Store} this
4763          * @param {Roo.data.Record[]} records The array of Records added
4764          * @param {Number} index The index at which the record(s) were added
4765          */
4766         add : true,
4767         /**
4768          * @event remove
4769          * Fires when a Record has been removed from the Store
4770          * @param {Store} this
4771          * @param {Roo.data.Record} record The Record that was removed
4772          * @param {Number} index The index at which the record was removed
4773          */
4774         remove : true,
4775         /**
4776          * @event update
4777          * Fires when a Record has been updated
4778          * @param {Store} this
4779          * @param {Roo.data.Record} record The Record that was updated
4780          * @param {String} operation The update operation being performed.  Value may be one of:
4781          * <pre><code>
4782  Roo.data.Record.EDIT
4783  Roo.data.Record.REJECT
4784  Roo.data.Record.COMMIT
4785          * </code></pre>
4786          */
4787         update : true,
4788         /**
4789          * @event clear
4790          * Fires when the data cache has been cleared.
4791          * @param {Store} this
4792          */
4793         clear : true,
4794         /**
4795          * @event beforeload
4796          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4797          * the load action will be canceled.
4798          * @param {Store} this
4799          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4800          */
4801         beforeload : true,
4802         /**
4803          * @event load
4804          * Fires after a new set of Records has been loaded.
4805          * @param {Store} this
4806          * @param {Roo.data.Record[]} records The Records that were loaded
4807          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4808          */
4809         load : true,
4810         /**
4811          * @event loadexception
4812          * Fires if an exception occurs in the Proxy during loading.
4813          * Called with the signature of the Proxy's "loadexception" event.
4814          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4815          * 
4816          * @param {Proxy} 
4817          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4818          * @param {Object} load options 
4819          * @param {Object} jsonData from your request (normally this contains the Exception)
4820          */
4821         loadexception : true
4822     });
4823     
4824     if(this.proxy){
4825         this.proxy = Roo.factory(this.proxy, Roo.data);
4826         this.proxy.xmodule = this.xmodule || false;
4827         this.relayEvents(this.proxy,  ["loadexception"]);
4828     }
4829     this.sortToggle = {};
4830
4831     Roo.data.Store.superclass.constructor.call(this);
4832
4833     if(this.inlineData){
4834         this.loadData(this.inlineData);
4835         delete this.inlineData;
4836     }
4837 };
4838 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4839      /**
4840     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4841     * without a remote query - used by combo/forms at present.
4842     */
4843     
4844     /**
4845     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4846     */
4847     /**
4848     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4849     */
4850     /**
4851     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4852     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4853     */
4854     /**
4855     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4856     * on any HTTP request
4857     */
4858     /**
4859     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4860     */
4861     /**
4862     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4863     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4864     */
4865     remoteSort : false,
4866
4867     /**
4868     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4869      * loaded or when a record is removed. (defaults to false).
4870     */
4871     pruneModifiedRecords : false,
4872
4873     // private
4874     lastOptions : null,
4875
4876     /**
4877      * Add Records to the Store and fires the add event.
4878      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4879      */
4880     add : function(records){
4881         records = [].concat(records);
4882         for(var i = 0, len = records.length; i < len; i++){
4883             records[i].join(this);
4884         }
4885         var index = this.data.length;
4886         this.data.addAll(records);
4887         this.fireEvent("add", this, records, index);
4888     },
4889
4890     /**
4891      * Remove a Record from the Store and fires the remove event.
4892      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4893      */
4894     remove : function(record){
4895         var index = this.data.indexOf(record);
4896         this.data.removeAt(index);
4897         if(this.pruneModifiedRecords){
4898             this.modified.remove(record);
4899         }
4900         this.fireEvent("remove", this, record, index);
4901     },
4902
4903     /**
4904      * Remove all Records from the Store and fires the clear event.
4905      */
4906     removeAll : function(){
4907         this.data.clear();
4908         if(this.pruneModifiedRecords){
4909             this.modified = [];
4910         }
4911         this.fireEvent("clear", this);
4912     },
4913
4914     /**
4915      * Inserts Records to the Store at the given index and fires the add event.
4916      * @param {Number} index The start index at which to insert the passed Records.
4917      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4918      */
4919     insert : function(index, records){
4920         records = [].concat(records);
4921         for(var i = 0, len = records.length; i < len; i++){
4922             this.data.insert(index, records[i]);
4923             records[i].join(this);
4924         }
4925         this.fireEvent("add", this, records, index);
4926     },
4927
4928     /**
4929      * Get the index within the cache of the passed Record.
4930      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4931      * @return {Number} The index of the passed Record. Returns -1 if not found.
4932      */
4933     indexOf : function(record){
4934         return this.data.indexOf(record);
4935     },
4936
4937     /**
4938      * Get the index within the cache of the Record with the passed id.
4939      * @param {String} id The id of the Record to find.
4940      * @return {Number} The index of the Record. Returns -1 if not found.
4941      */
4942     indexOfId : function(id){
4943         return this.data.indexOfKey(id);
4944     },
4945
4946     /**
4947      * Get the Record with the specified id.
4948      * @param {String} id The id of the Record to find.
4949      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4950      */
4951     getById : function(id){
4952         return this.data.key(id);
4953     },
4954
4955     /**
4956      * Get the Record at the specified index.
4957      * @param {Number} index The index of the Record to find.
4958      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4959      */
4960     getAt : function(index){
4961         return this.data.itemAt(index);
4962     },
4963
4964     /**
4965      * Returns a range of Records between specified indices.
4966      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4967      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4968      * @return {Roo.data.Record[]} An array of Records
4969      */
4970     getRange : function(start, end){
4971         return this.data.getRange(start, end);
4972     },
4973
4974     // private
4975     storeOptions : function(o){
4976         o = Roo.apply({}, o);
4977         delete o.callback;
4978         delete o.scope;
4979         this.lastOptions = o;
4980     },
4981
4982     /**
4983      * Loads the Record cache from the configured Proxy using the configured Reader.
4984      * <p>
4985      * If using remote paging, then the first load call must specify the <em>start</em>
4986      * and <em>limit</em> properties in the options.params property to establish the initial
4987      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4988      * <p>
4989      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4990      * and this call will return before the new data has been loaded. Perform any post-processing
4991      * in a callback function, or in a "load" event handler.</strong>
4992      * <p>
4993      * @param {Object} options An object containing properties which control loading options:<ul>
4994      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4995      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4996      * passed the following arguments:<ul>
4997      * <li>r : Roo.data.Record[]</li>
4998      * <li>options: Options object from the load call</li>
4999      * <li>success: Boolean success indicator</li></ul></li>
5000      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5001      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5002      * </ul>
5003      */
5004     load : function(options){
5005         options = options || {};
5006         if(this.fireEvent("beforeload", this, options) !== false){
5007             this.storeOptions(options);
5008             var p = Roo.apply(options.params || {}, this.baseParams);
5009             // if meta was not loaded from remote source.. try requesting it.
5010             if (!this.reader.metaFromRemote) {
5011                 p._requestMeta = 1;
5012             }
5013             if(this.sortInfo && this.remoteSort){
5014                 var pn = this.paramNames;
5015                 p[pn["sort"]] = this.sortInfo.field;
5016                 p[pn["dir"]] = this.sortInfo.direction;
5017             }
5018             this.proxy.load(p, this.reader, this.loadRecords, this, options);
5019         }
5020     },
5021
5022     /**
5023      * Reloads the Record cache from the configured Proxy using the configured Reader and
5024      * the options from the last load operation performed.
5025      * @param {Object} options (optional) An object containing properties which may override the options
5026      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5027      * the most recently used options are reused).
5028      */
5029     reload : function(options){
5030         this.load(Roo.applyIf(options||{}, this.lastOptions));
5031     },
5032
5033     // private
5034     // Called as a callback by the Reader during a load operation.
5035     loadRecords : function(o, options, success){
5036         if(!o || success === false){
5037             if(success !== false){
5038                 this.fireEvent("load", this, [], options);
5039             }
5040             if(options.callback){
5041                 options.callback.call(options.scope || this, [], options, false);
5042             }
5043             return;
5044         }
5045         // if data returned failure - throw an exception.
5046         if (o.success === false) {
5047             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5048             return;
5049         }
5050         var r = o.records, t = o.totalRecords || r.length;
5051         if(!options || options.add !== true){
5052             if(this.pruneModifiedRecords){
5053                 this.modified = [];
5054             }
5055             for(var i = 0, len = r.length; i < len; i++){
5056                 r[i].join(this);
5057             }
5058             if(this.snapshot){
5059                 this.data = this.snapshot;
5060                 delete this.snapshot;
5061             }
5062             this.data.clear();
5063             this.data.addAll(r);
5064             this.totalLength = t;
5065             this.applySort();
5066             this.fireEvent("datachanged", this);
5067         }else{
5068             this.totalLength = Math.max(t, this.data.length+r.length);
5069             this.add(r);
5070         }
5071         this.fireEvent("load", this, r, options);
5072         if(options.callback){
5073             options.callback.call(options.scope || this, r, options, true);
5074         }
5075     },
5076
5077     /**
5078      * Loads data from a passed data block. A Reader which understands the format of the data
5079      * must have been configured in the constructor.
5080      * @param {Object} data The data block from which to read the Records.  The format of the data expected
5081      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5082      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5083      */
5084     loadData : function(o, append){
5085         var r = this.reader.readRecords(o);
5086         this.loadRecords(r, {add: append}, true);
5087     },
5088
5089     /**
5090      * Gets the number of cached records.
5091      * <p>
5092      * <em>If using paging, this may not be the total size of the dataset. If the data object
5093      * used by the Reader contains the dataset size, then the getTotalCount() function returns
5094      * the data set size</em>
5095      */
5096     getCount : function(){
5097         return this.data.length || 0;
5098     },
5099
5100     /**
5101      * Gets the total number of records in the dataset as returned by the server.
5102      * <p>
5103      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5104      * the dataset size</em>
5105      */
5106     getTotalCount : function(){
5107         return this.totalLength || 0;
5108     },
5109
5110     /**
5111      * Returns the sort state of the Store as an object with two properties:
5112      * <pre><code>
5113  field {String} The name of the field by which the Records are sorted
5114  direction {String} The sort order, "ASC" or "DESC"
5115      * </code></pre>
5116      */
5117     getSortState : function(){
5118         return this.sortInfo;
5119     },
5120
5121     // private
5122     applySort : function(){
5123         if(this.sortInfo && !this.remoteSort){
5124             var s = this.sortInfo, f = s.field;
5125             var st = this.fields.get(f).sortType;
5126             var fn = function(r1, r2){
5127                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5128                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5129             };
5130             this.data.sort(s.direction, fn);
5131             if(this.snapshot && this.snapshot != this.data){
5132                 this.snapshot.sort(s.direction, fn);
5133             }
5134         }
5135     },
5136
5137     /**
5138      * Sets the default sort column and order to be used by the next load operation.
5139      * @param {String} fieldName The name of the field to sort by.
5140      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5141      */
5142     setDefaultSort : function(field, dir){
5143         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5144     },
5145
5146     /**
5147      * Sort the Records.
5148      * If remote sorting is used, the sort is performed on the server, and the cache is
5149      * reloaded. If local sorting is used, the cache is sorted internally.
5150      * @param {String} fieldName The name of the field to sort by.
5151      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5152      */
5153     sort : function(fieldName, dir){
5154         var f = this.fields.get(fieldName);
5155         if(!dir){
5156             if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5157                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5158             }else{
5159                 dir = f.sortDir;
5160             }
5161         }
5162         this.sortToggle[f.name] = dir;
5163         this.sortInfo = {field: f.name, direction: dir};
5164         if(!this.remoteSort){
5165             this.applySort();
5166             this.fireEvent("datachanged", this);
5167         }else{
5168             this.load(this.lastOptions);
5169         }
5170     },
5171
5172     /**
5173      * Calls the specified function for each of the Records in the cache.
5174      * @param {Function} fn The function to call. The Record is passed as the first parameter.
5175      * Returning <em>false</em> aborts and exits the iteration.
5176      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5177      */
5178     each : function(fn, scope){
5179         this.data.each(fn, scope);
5180     },
5181
5182     /**
5183      * Gets all records modified since the last commit.  Modified records are persisted across load operations
5184      * (e.g., during paging).
5185      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5186      */
5187     getModifiedRecords : function(){
5188         return this.modified;
5189     },
5190
5191     // private
5192     createFilterFn : function(property, value, anyMatch){
5193         if(!value.exec){ // not a regex
5194             value = String(value);
5195             if(value.length == 0){
5196                 return false;
5197             }
5198             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5199         }
5200         return function(r){
5201             return value.test(r.data[property]);
5202         };
5203     },
5204
5205     /**
5206      * Sums the value of <i>property</i> for each record between start and end and returns the result.
5207      * @param {String} property A field on your records
5208      * @param {Number} start The record index to start at (defaults to 0)
5209      * @param {Number} end The last record index to include (defaults to length - 1)
5210      * @return {Number} The sum
5211      */
5212     sum : function(property, start, end){
5213         var rs = this.data.items, v = 0;
5214         start = start || 0;
5215         end = (end || end === 0) ? end : rs.length-1;
5216
5217         for(var i = start; i <= end; i++){
5218             v += (rs[i].data[property] || 0);
5219         }
5220         return v;
5221     },
5222
5223     /**
5224      * Filter the records by a specified property.
5225      * @param {String} field A field on your records
5226      * @param {String/RegExp} value Either a string that the field
5227      * should start with or a RegExp to test against the field
5228      * @param {Boolean} anyMatch True to match any part not just the beginning
5229      */
5230     filter : function(property, value, anyMatch){
5231         var fn = this.createFilterFn(property, value, anyMatch);
5232         return fn ? this.filterBy(fn) : this.clearFilter();
5233     },
5234
5235     /**
5236      * Filter by a function. The specified function will be called with each
5237      * record in this data source. If the function returns true the record is included,
5238      * otherwise it is filtered.
5239      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5240      * @param {Object} scope (optional) The scope of the function (defaults to this)
5241      */
5242     filterBy : function(fn, scope){
5243         this.snapshot = this.snapshot || this.data;
5244         this.data = this.queryBy(fn, scope||this);
5245         this.fireEvent("datachanged", this);
5246     },
5247
5248     /**
5249      * Query the records by a specified property.
5250      * @param {String} field A field on your records
5251      * @param {String/RegExp} value Either a string that the field
5252      * should start with or a RegExp to test against the field
5253      * @param {Boolean} anyMatch True to match any part not just the beginning
5254      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5255      */
5256     query : function(property, value, anyMatch){
5257         var fn = this.createFilterFn(property, value, anyMatch);
5258         return fn ? this.queryBy(fn) : this.data.clone();
5259     },
5260
5261     /**
5262      * Query by a function. The specified function will be called with each
5263      * record in this data source. If the function returns true the record is included
5264      * in the results.
5265      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5266      * @param {Object} scope (optional) The scope of the function (defaults to this)
5267       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5268      **/
5269     queryBy : function(fn, scope){
5270         var data = this.snapshot || this.data;
5271         return data.filterBy(fn, scope||this);
5272     },
5273
5274     /**
5275      * Collects unique values for a particular dataIndex from this store.
5276      * @param {String} dataIndex The property to collect
5277      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5278      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5279      * @return {Array} An array of the unique values
5280      **/
5281     collect : function(dataIndex, allowNull, bypassFilter){
5282         var d = (bypassFilter === true && this.snapshot) ?
5283                 this.snapshot.items : this.data.items;
5284         var v, sv, r = [], l = {};
5285         for(var i = 0, len = d.length; i < len; i++){
5286             v = d[i].data[dataIndex];
5287             sv = String(v);
5288             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5289                 l[sv] = true;
5290                 r[r.length] = v;
5291             }
5292         }
5293         return r;
5294     },
5295
5296     /**
5297      * Revert to a view of the Record cache with no filtering applied.
5298      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5299      */
5300     clearFilter : function(suppressEvent){
5301         if(this.snapshot && this.snapshot != this.data){
5302             this.data = this.snapshot;
5303             delete this.snapshot;
5304             if(suppressEvent !== true){
5305                 this.fireEvent("datachanged", this);
5306             }
5307         }
5308     },
5309
5310     // private
5311     afterEdit : function(record){
5312         if(this.modified.indexOf(record) == -1){
5313             this.modified.push(record);
5314         }
5315         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5316     },
5317
5318     // private
5319     afterReject : function(record){
5320         this.modified.remove(record);
5321         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5322     },
5323
5324     // private
5325     afterCommit : function(record){
5326         this.modified.remove(record);
5327         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5328     },
5329
5330     /**
5331      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5332      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5333      */
5334     commitChanges : function(){
5335         var m = this.modified.slice(0);
5336         this.modified = [];
5337         for(var i = 0, len = m.length; i < len; i++){
5338             m[i].commit();
5339         }
5340     },
5341
5342     /**
5343      * Cancel outstanding changes on all changed records.
5344      */
5345     rejectChanges : function(){
5346         var m = this.modified.slice(0);
5347         this.modified = [];
5348         for(var i = 0, len = m.length; i < len; i++){
5349             m[i].reject();
5350         }
5351     },
5352
5353     onMetaChange : function(meta, rtype, o){
5354         this.recordType = rtype;
5355         this.fields = rtype.prototype.fields;
5356         delete this.snapshot;
5357         this.sortInfo = meta.sortInfo || this.sortInfo;
5358         this.modified = [];
5359         this.fireEvent('metachange', this, this.reader.meta);
5360     }
5361 });/*
5362  * Based on:
5363  * Ext JS Library 1.1.1
5364  * Copyright(c) 2006-2007, Ext JS, LLC.
5365  *
5366  * Originally Released Under LGPL - original licence link has changed is not relivant.
5367  *
5368  * Fork - LGPL
5369  * <script type="text/javascript">
5370  */
5371
5372 /**
5373  * @class Roo.data.SimpleStore
5374  * @extends Roo.data.Store
5375  * Small helper class to make creating Stores from Array data easier.
5376  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5377  * @cfg {Array} fields An array of field definition objects, or field name strings.
5378  * @cfg {Array} data The multi-dimensional array of data
5379  * @constructor
5380  * @param {Object} config
5381  */
5382 Roo.data.SimpleStore = function(config){
5383     Roo.data.SimpleStore.superclass.constructor.call(this, {
5384         isLocal : true,
5385         reader: new Roo.data.ArrayReader({
5386                 id: config.id
5387             },
5388             Roo.data.Record.create(config.fields)
5389         ),
5390         proxy : new Roo.data.MemoryProxy(config.data)
5391     });
5392     this.load();
5393 };
5394 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5395  * Based on:
5396  * Ext JS Library 1.1.1
5397  * Copyright(c) 2006-2007, Ext JS, LLC.
5398  *
5399  * Originally Released Under LGPL - original licence link has changed is not relivant.
5400  *
5401  * Fork - LGPL
5402  * <script type="text/javascript">
5403  */
5404
5405 /**
5406 /**
5407  * @extends Roo.data.Store
5408  * @class Roo.data.JsonStore
5409  * Small helper class to make creating Stores for JSON data easier. <br/>
5410 <pre><code>
5411 var store = new Roo.data.JsonStore({
5412     url: 'get-images.php',
5413     root: 'images',
5414     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5415 });
5416 </code></pre>
5417  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5418  * JsonReader and HttpProxy (unless inline data is provided).</b>
5419  * @cfg {Array} fields An array of field definition objects, or field name strings.
5420  * @constructor
5421  * @param {Object} config
5422  */
5423 Roo.data.JsonStore = function(c){
5424     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5425         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5426         reader: new Roo.data.JsonReader(c, c.fields)
5427     }));
5428 };
5429 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5430  * Based on:
5431  * Ext JS Library 1.1.1
5432  * Copyright(c) 2006-2007, Ext JS, LLC.
5433  *
5434  * Originally Released Under LGPL - original licence link has changed is not relivant.
5435  *
5436  * Fork - LGPL
5437  * <script type="text/javascript">
5438  */
5439
5440  
5441 Roo.data.Field = function(config){
5442     if(typeof config == "string"){
5443         config = {name: config};
5444     }
5445     Roo.apply(this, config);
5446     
5447     if(!this.type){
5448         this.type = "auto";
5449     }
5450     
5451     var st = Roo.data.SortTypes;
5452     // named sortTypes are supported, here we look them up
5453     if(typeof this.sortType == "string"){
5454         this.sortType = st[this.sortType];
5455     }
5456     
5457     // set default sortType for strings and dates
5458     if(!this.sortType){
5459         switch(this.type){
5460             case "string":
5461                 this.sortType = st.asUCString;
5462                 break;
5463             case "date":
5464                 this.sortType = st.asDate;
5465                 break;
5466             default:
5467                 this.sortType = st.none;
5468         }
5469     }
5470
5471     // define once
5472     var stripRe = /[\$,%]/g;
5473
5474     // prebuilt conversion function for this field, instead of
5475     // switching every time we're reading a value
5476     if(!this.convert){
5477         var cv, dateFormat = this.dateFormat;
5478         switch(this.type){
5479             case "":
5480             case "auto":
5481             case undefined:
5482                 cv = function(v){ return v; };
5483                 break;
5484             case "string":
5485                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5486                 break;
5487             case "int":
5488                 cv = function(v){
5489                     return v !== undefined && v !== null && v !== '' ?
5490                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5491                     };
5492                 break;
5493             case "float":
5494                 cv = function(v){
5495                     return v !== undefined && v !== null && v !== '' ?
5496                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5497                     };
5498                 break;
5499             case "bool":
5500             case "boolean":
5501                 cv = function(v){ return v === true || v === "true" || v == 1; };
5502                 break;
5503             case "date":
5504                 cv = function(v){
5505                     if(!v){
5506                         return '';
5507                     }
5508                     if(v instanceof Date){
5509                         return v;
5510                     }
5511                     if(dateFormat){
5512                         if(dateFormat == "timestamp"){
5513                             return new Date(v*1000);
5514                         }
5515                         return Date.parseDate(v, dateFormat);
5516                     }
5517                     var parsed = Date.parse(v);
5518                     return parsed ? new Date(parsed) : null;
5519                 };
5520              break;
5521             
5522         }
5523         this.convert = cv;
5524     }
5525 };
5526
5527 Roo.data.Field.prototype = {
5528     dateFormat: null,
5529     defaultValue: "",
5530     mapping: null,
5531     sortType : null,
5532     sortDir : "ASC"
5533 };/*
5534  * Based on:
5535  * Ext JS Library 1.1.1
5536  * Copyright(c) 2006-2007, Ext JS, LLC.
5537  *
5538  * Originally Released Under LGPL - original licence link has changed is not relivant.
5539  *
5540  * Fork - LGPL
5541  * <script type="text/javascript">
5542  */
5543  
5544 // Base class for reading structured data from a data source.  This class is intended to be
5545 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5546
5547 /**
5548  * @class Roo.data.DataReader
5549  * Base class for reading structured data from a data source.  This class is intended to be
5550  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5551  */
5552
5553 Roo.data.DataReader = function(meta, recordType){
5554     
5555     this.meta = meta;
5556     
5557     this.recordType = recordType instanceof Array ? 
5558         Roo.data.Record.create(recordType) : recordType;
5559 };
5560
5561 Roo.data.DataReader.prototype = {
5562      /**
5563      * Create an empty record
5564      * @param {Object} data (optional) - overlay some values
5565      * @return {Roo.data.Record} record created.
5566      */
5567     newRow :  function(d) {
5568         var da =  {};
5569         this.recordType.prototype.fields.each(function(c) {
5570             switch( c.type) {
5571                 case 'int' : da[c.name] = 0; break;
5572                 case 'date' : da[c.name] = new Date(); break;
5573                 case 'float' : da[c.name] = 0.0; break;
5574                 case 'boolean' : da[c.name] = false; break;
5575                 default : da[c.name] = ""; break;
5576             }
5577             
5578         });
5579         return new this.recordType(Roo.apply(da, d));
5580     }
5581     
5582 };/*
5583  * Based on:
5584  * Ext JS Library 1.1.1
5585  * Copyright(c) 2006-2007, Ext JS, LLC.
5586  *
5587  * Originally Released Under LGPL - original licence link has changed is not relivant.
5588  *
5589  * Fork - LGPL
5590  * <script type="text/javascript">
5591  */
5592
5593 /**
5594  * @class Roo.data.DataProxy
5595  * @extends Roo.data.Observable
5596  * This class is an abstract base class for implementations which provide retrieval of
5597  * unformatted data objects.<br>
5598  * <p>
5599  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5600  * (of the appropriate type which knows how to parse the data object) to provide a block of
5601  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5602  * <p>
5603  * Custom implementations must implement the load method as described in
5604  * {@link Roo.data.HttpProxy#load}.
5605  */
5606 Roo.data.DataProxy = function(){
5607     this.addEvents({
5608         /**
5609          * @event beforeload
5610          * Fires before a network request is made to retrieve a data object.
5611          * @param {Object} This DataProxy object.
5612          * @param {Object} params The params parameter to the load function.
5613          */
5614         beforeload : true,
5615         /**
5616          * @event load
5617          * Fires before the load method's callback is called.
5618          * @param {Object} This DataProxy object.
5619          * @param {Object} o The data object.
5620          * @param {Object} arg The callback argument object passed to the load function.
5621          */
5622         load : true,
5623         /**
5624          * @event loadexception
5625          * Fires if an Exception occurs during data retrieval.
5626          * @param {Object} This DataProxy object.
5627          * @param {Object} o The data object.
5628          * @param {Object} arg The callback argument object passed to the load function.
5629          * @param {Object} e The Exception.
5630          */
5631         loadexception : true
5632     });
5633     Roo.data.DataProxy.superclass.constructor.call(this);
5634 };
5635
5636 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5637
5638     /**
5639      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5640      */
5641 /*
5642  * Based on:
5643  * Ext JS Library 1.1.1
5644  * Copyright(c) 2006-2007, Ext JS, LLC.
5645  *
5646  * Originally Released Under LGPL - original licence link has changed is not relivant.
5647  *
5648  * Fork - LGPL
5649  * <script type="text/javascript">
5650  */
5651 /**
5652  * @class Roo.data.MemoryProxy
5653  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5654  * to the Reader when its load method is called.
5655  * @constructor
5656  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5657  */
5658 Roo.data.MemoryProxy = function(data){
5659     if (data.data) {
5660         data = data.data;
5661     }
5662     Roo.data.MemoryProxy.superclass.constructor.call(this);
5663     this.data = data;
5664 };
5665
5666 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5667     /**
5668      * Load data from the requested source (in this case an in-memory
5669      * data object passed to the constructor), read the data object into
5670      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5671      * process that block using the passed callback.
5672      * @param {Object} params This parameter is not used by the MemoryProxy class.
5673      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5674      * object into a block of Roo.data.Records.
5675      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5676      * The function must be passed <ul>
5677      * <li>The Record block object</li>
5678      * <li>The "arg" argument from the load function</li>
5679      * <li>A boolean success indicator</li>
5680      * </ul>
5681      * @param {Object} scope The scope in which to call the callback
5682      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5683      */
5684     load : function(params, reader, callback, scope, arg){
5685         params = params || {};
5686         var result;
5687         try {
5688             result = reader.readRecords(this.data);
5689         }catch(e){
5690             this.fireEvent("loadexception", this, arg, null, e);
5691             callback.call(scope, null, arg, false);
5692             return;
5693         }
5694         callback.call(scope, result, arg, true);
5695     },
5696     
5697     // private
5698     update : function(params, records){
5699         
5700     }
5701 });/*
5702  * Based on:
5703  * Ext JS Library 1.1.1
5704  * Copyright(c) 2006-2007, Ext JS, LLC.
5705  *
5706  * Originally Released Under LGPL - original licence link has changed is not relivant.
5707  *
5708  * Fork - LGPL
5709  * <script type="text/javascript">
5710  */
5711 /**
5712  * @class Roo.data.HttpProxy
5713  * @extends Roo.data.DataProxy
5714  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5715  * configured to reference a certain URL.<br><br>
5716  * <p>
5717  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5718  * from which the running page was served.<br><br>
5719  * <p>
5720  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5721  * <p>
5722  * Be aware that to enable the browser to parse an XML document, the server must set
5723  * the Content-Type header in the HTTP response to "text/xml".
5724  * @constructor
5725  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5726  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5727  * will be used to make the request.
5728  */
5729 Roo.data.HttpProxy = function(conn){
5730     Roo.data.HttpProxy.superclass.constructor.call(this);
5731     // is conn a conn config or a real conn?
5732     this.conn = conn;
5733     this.useAjax = !conn || !conn.events;
5734   
5735 };
5736
5737 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5738     // thse are take from connection...
5739     
5740     /**
5741      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5742      */
5743     /**
5744      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5745      * extra parameters to each request made by this object. (defaults to undefined)
5746      */
5747     /**
5748      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5749      *  to each request made by this object. (defaults to undefined)
5750      */
5751     /**
5752      * @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)
5753      */
5754     /**
5755      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5756      */
5757      /**
5758      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5759      * @type Boolean
5760      */
5761   
5762
5763     /**
5764      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5765      * @type Boolean
5766      */
5767     /**
5768      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5769      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5770      * a finer-grained basis than the DataProxy events.
5771      */
5772     getConnection : function(){
5773         return this.useAjax ? Roo.Ajax : this.conn;
5774     },
5775
5776     /**
5777      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5778      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5779      * process that block using the passed callback.
5780      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5781      * for the request to the remote server.
5782      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5783      * object into a block of Roo.data.Records.
5784      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5785      * The function must be passed <ul>
5786      * <li>The Record block object</li>
5787      * <li>The "arg" argument from the load function</li>
5788      * <li>A boolean success indicator</li>
5789      * </ul>
5790      * @param {Object} scope The scope in which to call the callback
5791      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5792      */
5793     load : function(params, reader, callback, scope, arg){
5794         if(this.fireEvent("beforeload", this, params) !== false){
5795             var  o = {
5796                 params : params || {},
5797                 request: {
5798                     callback : callback,
5799                     scope : scope,
5800                     arg : arg
5801                 },
5802                 reader: reader,
5803                 callback : this.loadResponse,
5804                 scope: this
5805             };
5806             if(this.useAjax){
5807                 Roo.applyIf(o, this.conn);
5808                 if(this.activeRequest){
5809                     Roo.Ajax.abort(this.activeRequest);
5810                 }
5811                 this.activeRequest = Roo.Ajax.request(o);
5812             }else{
5813                 this.conn.request(o);
5814             }
5815         }else{
5816             callback.call(scope||this, null, arg, false);
5817         }
5818     },
5819
5820     // private
5821     loadResponse : function(o, success, response){
5822         delete this.activeRequest;
5823         if(!success){
5824             this.fireEvent("loadexception", this, o, response);
5825             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5826             return;
5827         }
5828         var result;
5829         try {
5830             result = o.reader.read(response);
5831         }catch(e){
5832             this.fireEvent("loadexception", this, o, response, e);
5833             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5834             return;
5835         }
5836         
5837         this.fireEvent("load", this, o, o.request.arg);
5838         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5839     },
5840
5841     // private
5842     update : function(dataSet){
5843
5844     },
5845
5846     // private
5847     updateResponse : function(dataSet){
5848
5849     }
5850 });/*
5851  * Based on:
5852  * Ext JS Library 1.1.1
5853  * Copyright(c) 2006-2007, Ext JS, LLC.
5854  *
5855  * Originally Released Under LGPL - original licence link has changed is not relivant.
5856  *
5857  * Fork - LGPL
5858  * <script type="text/javascript">
5859  */
5860
5861 /**
5862  * @class Roo.data.ScriptTagProxy
5863  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5864  * other than the originating domain of the running page.<br><br>
5865  * <p>
5866  * <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
5867  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5868  * <p>
5869  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5870  * source code that is used as the source inside a &lt;script> tag.<br><br>
5871  * <p>
5872  * In order for the browser to process the returned data, the server must wrap the data object
5873  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5874  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5875  * depending on whether the callback name was passed:
5876  * <p>
5877  * <pre><code>
5878 boolean scriptTag = false;
5879 String cb = request.getParameter("callback");
5880 if (cb != null) {
5881     scriptTag = true;
5882     response.setContentType("text/javascript");
5883 } else {
5884     response.setContentType("application/x-json");
5885 }
5886 Writer out = response.getWriter();
5887 if (scriptTag) {
5888     out.write(cb + "(");
5889 }
5890 out.print(dataBlock.toJsonString());
5891 if (scriptTag) {
5892     out.write(");");
5893 }
5894 </pre></code>
5895  *
5896  * @constructor
5897  * @param {Object} config A configuration object.
5898  */
5899 Roo.data.ScriptTagProxy = function(config){
5900     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5901     Roo.apply(this, config);
5902     this.head = document.getElementsByTagName("head")[0];
5903 };
5904
5905 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5906
5907 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5908     /**
5909      * @cfg {String} url The URL from which to request the data object.
5910      */
5911     /**
5912      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5913      */
5914     timeout : 30000,
5915     /**
5916      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5917      * the server the name of the callback function set up by the load call to process the returned data object.
5918      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5919      * javascript output which calls this named function passing the data object as its only parameter.
5920      */
5921     callbackParam : "callback",
5922     /**
5923      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5924      * name to the request.
5925      */
5926     nocache : true,
5927
5928     /**
5929      * Load data from the configured URL, read the data object into
5930      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5931      * process that block using the passed callback.
5932      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5933      * for the request to the remote server.
5934      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5935      * object into a block of Roo.data.Records.
5936      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5937      * The function must be passed <ul>
5938      * <li>The Record block object</li>
5939      * <li>The "arg" argument from the load function</li>
5940      * <li>A boolean success indicator</li>
5941      * </ul>
5942      * @param {Object} scope The scope in which to call the callback
5943      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5944      */
5945     load : function(params, reader, callback, scope, arg){
5946         if(this.fireEvent("beforeload", this, params) !== false){
5947
5948             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5949
5950             var url = this.url;
5951             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5952             if(this.nocache){
5953                 url += "&_dc=" + (new Date().getTime());
5954             }
5955             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5956             var trans = {
5957                 id : transId,
5958                 cb : "stcCallback"+transId,
5959                 scriptId : "stcScript"+transId,
5960                 params : params,
5961                 arg : arg,
5962                 url : url,
5963                 callback : callback,
5964                 scope : scope,
5965                 reader : reader
5966             };
5967             var conn = this;
5968
5969             window[trans.cb] = function(o){
5970                 conn.handleResponse(o, trans);
5971             };
5972
5973             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5974
5975             if(this.autoAbort !== false){
5976                 this.abort();
5977             }
5978
5979             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5980
5981             var script = document.createElement("script");
5982             script.setAttribute("src", url);
5983             script.setAttribute("type", "text/javascript");
5984             script.setAttribute("id", trans.scriptId);
5985             this.head.appendChild(script);
5986
5987             this.trans = trans;
5988         }else{
5989             callback.call(scope||this, null, arg, false);
5990         }
5991     },
5992
5993     // private
5994     isLoading : function(){
5995         return this.trans ? true : false;
5996     },
5997
5998     /**
5999      * Abort the current server request.
6000      */
6001     abort : function(){
6002         if(this.isLoading()){
6003             this.destroyTrans(this.trans);
6004         }
6005     },
6006
6007     // private
6008     destroyTrans : function(trans, isLoaded){
6009         this.head.removeChild(document.getElementById(trans.scriptId));
6010         clearTimeout(trans.timeoutId);
6011         if(isLoaded){
6012             window[trans.cb] = undefined;
6013             try{
6014                 delete window[trans.cb];
6015             }catch(e){}
6016         }else{
6017             // if hasn't been loaded, wait for load to remove it to prevent script error
6018             window[trans.cb] = function(){
6019                 window[trans.cb] = undefined;
6020                 try{
6021                     delete window[trans.cb];
6022                 }catch(e){}
6023             };
6024         }
6025     },
6026
6027     // private
6028     handleResponse : function(o, trans){
6029         this.trans = false;
6030         this.destroyTrans(trans, true);
6031         var result;
6032         try {
6033             result = trans.reader.readRecords(o);
6034         }catch(e){
6035             this.fireEvent("loadexception", this, o, trans.arg, e);
6036             trans.callback.call(trans.scope||window, null, trans.arg, false);
6037             return;
6038         }
6039         this.fireEvent("load", this, o, trans.arg);
6040         trans.callback.call(trans.scope||window, result, trans.arg, true);
6041     },
6042
6043     // private
6044     handleFailure : function(trans){
6045         this.trans = false;
6046         this.destroyTrans(trans, false);
6047         this.fireEvent("loadexception", this, null, trans.arg);
6048         trans.callback.call(trans.scope||window, null, trans.arg, false);
6049     }
6050 });/*
6051  * Based on:
6052  * Ext JS Library 1.1.1
6053  * Copyright(c) 2006-2007, Ext JS, LLC.
6054  *
6055  * Originally Released Under LGPL - original licence link has changed is not relivant.
6056  *
6057  * Fork - LGPL
6058  * <script type="text/javascript">
6059  */
6060
6061 /**
6062  * @class Roo.data.JsonReader
6063  * @extends Roo.data.DataReader
6064  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6065  * based on mappings in a provided Roo.data.Record constructor.
6066  * 
6067  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6068  * in the reply previously. 
6069  * 
6070  * <p>
6071  * Example code:
6072  * <pre><code>
6073 var RecordDef = Roo.data.Record.create([
6074     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6075     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6076 ]);
6077 var myReader = new Roo.data.JsonReader({
6078     totalProperty: "results",    // The property which contains the total dataset size (optional)
6079     root: "rows",                // The property which contains an Array of row objects
6080     id: "id"                     // The property within each row object that provides an ID for the record (optional)
6081 }, RecordDef);
6082 </code></pre>
6083  * <p>
6084  * This would consume a JSON file like this:
6085  * <pre><code>
6086 { 'results': 2, 'rows': [
6087     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6088     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6089 }
6090 </code></pre>
6091  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6092  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6093  * paged from the remote server.
6094  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6095  * @cfg {String} root name of the property which contains the Array of row objects.
6096  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6097  * @constructor
6098  * Create a new JsonReader
6099  * @param {Object} meta Metadata configuration options
6100  * @param {Object} recordType Either an Array of field definition objects,
6101  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6102  */
6103 Roo.data.JsonReader = function(meta, recordType){
6104     
6105     meta = meta || {};
6106     // set some defaults:
6107     Roo.applyIf(meta, {
6108         totalProperty: 'total',
6109         successProperty : 'success',
6110         root : 'data',
6111         id : 'id'
6112     });
6113     
6114     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6115 };
6116 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6117     
6118     /**
6119      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
6120      * Used by Store query builder to append _requestMeta to params.
6121      * 
6122      */
6123     metaFromRemote : false,
6124     /**
6125      * This method is only used by a DataProxy which has retrieved data from a remote server.
6126      * @param {Object} response The XHR object which contains the JSON data in its responseText.
6127      * @return {Object} data A data block which is used by an Roo.data.Store object as
6128      * a cache of Roo.data.Records.
6129      */
6130     read : function(response){
6131         var json = response.responseText;
6132        
6133         var o = /* eval:var:o */ eval("("+json+")");
6134         if(!o) {
6135             throw {message: "JsonReader.read: Json object not found"};
6136         }
6137         
6138         if(o.metaData){
6139             
6140             delete this.ef;
6141             this.metaFromRemote = true;
6142             this.meta = o.metaData;
6143             this.recordType = Roo.data.Record.create(o.metaData.fields);
6144             this.onMetaChange(this.meta, this.recordType, o);
6145         }
6146         return this.readRecords(o);
6147     },
6148
6149     // private function a store will implement
6150     onMetaChange : function(meta, recordType, o){
6151
6152     },
6153
6154     /**
6155          * @ignore
6156          */
6157     simpleAccess: function(obj, subsc) {
6158         return obj[subsc];
6159     },
6160
6161         /**
6162          * @ignore
6163          */
6164     getJsonAccessor: function(){
6165         var re = /[\[\.]/;
6166         return function(expr) {
6167             try {
6168                 return(re.test(expr))
6169                     ? new Function("obj", "return obj." + expr)
6170                     : function(obj){
6171                         return obj[expr];
6172                     };
6173             } catch(e){}
6174             return Roo.emptyFn;
6175         };
6176     }(),
6177
6178     /**
6179      * Create a data block containing Roo.data.Records from an XML document.
6180      * @param {Object} o An object which contains an Array of row objects in the property specified
6181      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6182      * which contains the total size of the dataset.
6183      * @return {Object} data A data block which is used by an Roo.data.Store object as
6184      * a cache of Roo.data.Records.
6185      */
6186     readRecords : function(o){
6187         /**
6188          * After any data loads, the raw JSON data is available for further custom processing.
6189          * @type Object
6190          */
6191         this.jsonData = o;
6192         var s = this.meta, Record = this.recordType,
6193             f = Record.prototype.fields, fi = f.items, fl = f.length;
6194
6195 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
6196         if (!this.ef) {
6197             if(s.totalProperty) {
6198                     this.getTotal = this.getJsonAccessor(s.totalProperty);
6199                 }
6200                 if(s.successProperty) {
6201                     this.getSuccess = this.getJsonAccessor(s.successProperty);
6202                 }
6203                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6204                 if (s.id) {
6205                         var g = this.getJsonAccessor(s.id);
6206                         this.getId = function(rec) {
6207                                 var r = g(rec);
6208                                 return (r === undefined || r === "") ? null : r;
6209                         };
6210                 } else {
6211                         this.getId = function(){return null;};
6212                 }
6213             this.ef = [];
6214             for(var jj = 0; jj < fl; jj++){
6215                 f = fi[jj];
6216                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6217                 this.ef[jj] = this.getJsonAccessor(map);
6218             }
6219         }
6220
6221         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6222         if(s.totalProperty){
6223             var vt = parseInt(this.getTotal(o), 10);
6224             if(!isNaN(vt)){
6225                 totalRecords = vt;
6226             }
6227         }
6228         if(s.successProperty){
6229             var vs = this.getSuccess(o);
6230             if(vs === false || vs === 'false'){
6231                 success = false;
6232             }
6233         }
6234         var records = [];
6235             for(var i = 0; i < c; i++){
6236                     var n = root[i];
6237                 var values = {};
6238                 var id = this.getId(n);
6239                 for(var j = 0; j < fl; j++){
6240                     f = fi[j];
6241                 var v = this.ef[j](n);
6242                 if (!f.convert) {
6243                     Roo.log('missing convert for ' + f.name);
6244                     Roo.log(f);
6245                     continue;
6246                 }
6247                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6248                 }
6249                 var record = new Record(values, id);
6250                 record.json = n;
6251                 records[i] = record;
6252             }
6253             return {
6254                 success : success,
6255                 records : records,
6256                 totalRecords : totalRecords
6257             };
6258     }
6259 });/*
6260  * Based on:
6261  * Ext JS Library 1.1.1
6262  * Copyright(c) 2006-2007, Ext JS, LLC.
6263  *
6264  * Originally Released Under LGPL - original licence link has changed is not relivant.
6265  *
6266  * Fork - LGPL
6267  * <script type="text/javascript">
6268  */
6269
6270 /**
6271  * @class Roo.data.XmlReader
6272  * @extends Roo.data.DataReader
6273  * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6274  * based on mappings in a provided Roo.data.Record constructor.<br><br>
6275  * <p>
6276  * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6277  * header in the HTTP response must be set to "text/xml".</em>
6278  * <p>
6279  * Example code:
6280  * <pre><code>
6281 var RecordDef = Roo.data.Record.create([
6282    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
6283    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
6284 ]);
6285 var myReader = new Roo.data.XmlReader({
6286    totalRecords: "results", // The element which contains the total dataset size (optional)
6287    record: "row",           // The repeated element which contains row information
6288    id: "id"                 // The element within the row that provides an ID for the record (optional)
6289 }, RecordDef);
6290 </code></pre>
6291  * <p>
6292  * This would consume an XML file like this:
6293  * <pre><code>
6294 &lt;?xml?>
6295 &lt;dataset>
6296  &lt;results>2&lt;/results>
6297  &lt;row>
6298    &lt;id>1&lt;/id>
6299    &lt;name>Bill&lt;/name>
6300    &lt;occupation>Gardener&lt;/occupation>
6301  &lt;/row>
6302  &lt;row>
6303    &lt;id>2&lt;/id>
6304    &lt;name>Ben&lt;/name>
6305    &lt;occupation>Horticulturalist&lt;/occupation>
6306  &lt;/row>
6307 &lt;/dataset>
6308 </code></pre>
6309  * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6310  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6311  * paged from the remote server.
6312  * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6313  * @cfg {String} success The DomQuery path to the success attribute used by forms.
6314  * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6315  * a record identifier value.
6316  * @constructor
6317  * Create a new XmlReader
6318  * @param {Object} meta Metadata configuration options
6319  * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
6320  * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6321  * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
6322  */
6323 Roo.data.XmlReader = function(meta, recordType){
6324     meta = meta || {};
6325     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6326 };
6327 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6328     /**
6329      * This method is only used by a DataProxy which has retrieved data from a remote server.
6330          * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
6331          * to contain a method called 'responseXML' that returns an XML document object.
6332      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6333      * a cache of Roo.data.Records.
6334      */
6335     read : function(response){
6336         var doc = response.responseXML;
6337         if(!doc) {
6338             throw {message: "XmlReader.read: XML Document not available"};
6339         }
6340         return this.readRecords(doc);
6341     },
6342
6343     /**
6344      * Create a data block containing Roo.data.Records from an XML document.
6345          * @param {Object} doc A parsed XML document.
6346      * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6347      * a cache of Roo.data.Records.
6348      */
6349     readRecords : function(doc){
6350         /**
6351          * After any data loads/reads, the raw XML Document is available for further custom processing.
6352          * @type XMLDocument
6353          */
6354         this.xmlData = doc;
6355         var root = doc.documentElement || doc;
6356         var q = Roo.DomQuery;
6357         var recordType = this.recordType, fields = recordType.prototype.fields;
6358         var sid = this.meta.id;
6359         var totalRecords = 0, success = true;
6360         if(this.meta.totalRecords){
6361             totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6362         }
6363         
6364         if(this.meta.success){
6365             var sv = q.selectValue(this.meta.success, root, true);
6366             success = sv !== false && sv !== 'false';
6367         }
6368         var records = [];
6369         var ns = q.select(this.meta.record, root);
6370         for(var i = 0, len = ns.length; i < len; i++) {
6371                 var n = ns[i];
6372                 var values = {};
6373                 var id = sid ? q.selectValue(sid, n) : undefined;
6374                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6375                     var f = fields.items[j];
6376                 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6377                     v = f.convert(v);
6378                     values[f.name] = v;
6379                 }
6380                 var record = new recordType(values, id);
6381                 record.node = n;
6382                 records[records.length] = record;
6383             }
6384
6385             return {
6386                 success : success,
6387                 records : records,
6388                 totalRecords : totalRecords || records.length
6389             };
6390     }
6391 });/*
6392  * Based on:
6393  * Ext JS Library 1.1.1
6394  * Copyright(c) 2006-2007, Ext JS, LLC.
6395  *
6396  * Originally Released Under LGPL - original licence link has changed is not relivant.
6397  *
6398  * Fork - LGPL
6399  * <script type="text/javascript">
6400  */
6401
6402 /**
6403  * @class Roo.data.ArrayReader
6404  * @extends Roo.data.DataReader
6405  * Data reader class to create an Array of Roo.data.Record objects from an Array.
6406  * Each element of that Array represents a row of data fields. The
6407  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6408  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6409  * <p>
6410  * Example code:.
6411  * <pre><code>
6412 var RecordDef = Roo.data.Record.create([
6413     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
6414     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
6415 ]);
6416 var myReader = new Roo.data.ArrayReader({
6417     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
6418 }, RecordDef);
6419 </code></pre>
6420  * <p>
6421  * This would consume an Array like this:
6422  * <pre><code>
6423 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6424   </code></pre>
6425  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6426  * @constructor
6427  * Create a new JsonReader
6428  * @param {Object} meta Metadata configuration options.
6429  * @param {Object} recordType Either an Array of field definition objects
6430  * as specified to {@link Roo.data.Record#create},
6431  * or an {@link Roo.data.Record} object
6432  * created using {@link Roo.data.Record#create}.
6433  */
6434 Roo.data.ArrayReader = function(meta, recordType){
6435     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6436 };
6437
6438 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6439     /**
6440      * Create a data block containing Roo.data.Records from an XML document.
6441      * @param {Object} o An Array of row objects which represents the dataset.
6442      * @return {Object} data A data block which is used by an Roo.data.Store object as
6443      * a cache of Roo.data.Records.
6444      */
6445     readRecords : function(o){
6446         var sid = this.meta ? this.meta.id : null;
6447         var recordType = this.recordType, fields = recordType.prototype.fields;
6448         var records = [];
6449         var root = o;
6450             for(var i = 0; i < root.length; i++){
6451                     var n = root[i];
6452                 var values = {};
6453                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6454                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6455                 var f = fields.items[j];
6456                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6457                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6458                 v = f.convert(v);
6459                 values[f.name] = v;
6460             }
6461                 var record = new recordType(values, id);
6462                 record.json = n;
6463                 records[records.length] = record;
6464             }
6465             return {
6466                 records : records,
6467                 totalRecords : records.length
6468             };
6469     }
6470 });/*
6471  * Based on:
6472  * Ext JS Library 1.1.1
6473  * Copyright(c) 2006-2007, Ext JS, LLC.
6474  *
6475  * Originally Released Under LGPL - original licence link has changed is not relivant.
6476  *
6477  * Fork - LGPL
6478  * <script type="text/javascript">
6479  */
6480
6481
6482 /**
6483  * @class Roo.data.Tree
6484  * @extends Roo.util.Observable
6485  * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6486  * in the tree have most standard DOM functionality.
6487  * @constructor
6488  * @param {Node} root (optional) The root node
6489  */
6490 Roo.data.Tree = function(root){
6491    this.nodeHash = {};
6492    /**
6493     * The root node for this tree
6494     * @type Node
6495     */
6496    this.root = null;
6497    if(root){
6498        this.setRootNode(root);
6499    }
6500    this.addEvents({
6501        /**
6502         * @event append
6503         * Fires when a new child node is appended to a node in this tree.
6504         * @param {Tree} tree The owner tree
6505         * @param {Node} parent The parent node
6506         * @param {Node} node The newly appended node
6507         * @param {Number} index The index of the newly appended node
6508         */
6509        "append" : true,
6510        /**
6511         * @event remove
6512         * Fires when a child node is removed from a node in this tree.
6513         * @param {Tree} tree The owner tree
6514         * @param {Node} parent The parent node
6515         * @param {Node} node The child node removed
6516         */
6517        "remove" : true,
6518        /**
6519         * @event move
6520         * Fires when a node is moved to a new location in the tree
6521         * @param {Tree} tree The owner tree
6522         * @param {Node} node The node moved
6523         * @param {Node} oldParent The old parent of this node
6524         * @param {Node} newParent The new parent of this node
6525         * @param {Number} index The index it was moved to
6526         */
6527        "move" : true,
6528        /**
6529         * @event insert
6530         * Fires when a new child node is inserted in a node in this tree.
6531         * @param {Tree} tree The owner tree
6532         * @param {Node} parent The parent node
6533         * @param {Node} node The child node inserted
6534         * @param {Node} refNode The child node the node was inserted before
6535         */
6536        "insert" : true,
6537        /**
6538         * @event beforeappend
6539         * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6540         * @param {Tree} tree The owner tree
6541         * @param {Node} parent The parent node
6542         * @param {Node} node The child node to be appended
6543         */
6544        "beforeappend" : true,
6545        /**
6546         * @event beforeremove
6547         * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6548         * @param {Tree} tree The owner tree
6549         * @param {Node} parent The parent node
6550         * @param {Node} node The child node to be removed
6551         */
6552        "beforeremove" : true,
6553        /**
6554         * @event beforemove
6555         * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6556         * @param {Tree} tree The owner tree
6557         * @param {Node} node The node being moved
6558         * @param {Node} oldParent The parent of the node
6559         * @param {Node} newParent The new parent the node is moving to
6560         * @param {Number} index The index it is being moved to
6561         */
6562        "beforemove" : true,
6563        /**
6564         * @event beforeinsert
6565         * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6566         * @param {Tree} tree The owner tree
6567         * @param {Node} parent The parent node
6568         * @param {Node} node The child node to be inserted
6569         * @param {Node} refNode The child node the node is being inserted before
6570         */
6571        "beforeinsert" : true
6572    });
6573
6574     Roo.data.Tree.superclass.constructor.call(this);
6575 };
6576
6577 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6578     pathSeparator: "/",
6579
6580     proxyNodeEvent : function(){
6581         return this.fireEvent.apply(this, arguments);
6582     },
6583
6584     /**
6585      * Returns the root node for this tree.
6586      * @return {Node}
6587      */
6588     getRootNode : function(){
6589         return this.root;
6590     },
6591
6592     /**
6593      * Sets the root node for this tree.
6594      * @param {Node} node
6595      * @return {Node}
6596      */
6597     setRootNode : function(node){
6598         this.root = node;
6599         node.ownerTree = this;
6600         node.isRoot = true;
6601         this.registerNode(node);
6602         return node;
6603     },
6604
6605     /**
6606      * Gets a node in this tree by its id.
6607      * @param {String} id
6608      * @return {Node}
6609      */
6610     getNodeById : function(id){
6611         return this.nodeHash[id];
6612     },
6613
6614     registerNode : function(node){
6615         this.nodeHash[node.id] = node;
6616     },
6617
6618     unregisterNode : function(node){
6619         delete this.nodeHash[node.id];
6620     },
6621
6622     toString : function(){
6623         return "[Tree"+(this.id?" "+this.id:"")+"]";
6624     }
6625 });
6626
6627 /**
6628  * @class Roo.data.Node
6629  * @extends Roo.util.Observable
6630  * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6631  * @cfg {String} id The id for this node. If one is not specified, one is generated.
6632  * @constructor
6633  * @param {Object} attributes The attributes/config for the node
6634  */
6635 Roo.data.Node = function(attributes){
6636     /**
6637      * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6638      * @type {Object}
6639      */
6640     this.attributes = attributes || {};
6641     this.leaf = this.attributes.leaf;
6642     /**
6643      * The node id. @type String
6644      */
6645     this.id = this.attributes.id;
6646     if(!this.id){
6647         this.id = Roo.id(null, "ynode-");
6648         this.attributes.id = this.id;
6649     }
6650     /**
6651      * All child nodes of this node. @type Array
6652      */
6653     this.childNodes = [];
6654     if(!this.childNodes.indexOf){ // indexOf is a must
6655         this.childNodes.indexOf = function(o){
6656             for(var i = 0, len = this.length; i < len; i++){
6657                 if(this[i] == o) {
6658                     return i;
6659                 }
6660             }
6661             return -1;
6662         };
6663     }
6664     /**
6665      * The parent node for this node. @type Node
6666      */
6667     this.parentNode = null;
6668     /**
6669      * The first direct child node of this node, or null if this node has no child nodes. @type Node
6670      */
6671     this.firstChild = null;
6672     /**
6673      * The last direct child node of this node, or null if this node has no child nodes. @type Node
6674      */
6675     this.lastChild = null;
6676     /**
6677      * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6678      */
6679     this.previousSibling = null;
6680     /**
6681      * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6682      */
6683     this.nextSibling = null;
6684
6685     this.addEvents({
6686        /**
6687         * @event append
6688         * Fires when a new child node is appended
6689         * @param {Tree} tree The owner tree
6690         * @param {Node} this This node
6691         * @param {Node} node The newly appended node
6692         * @param {Number} index The index of the newly appended node
6693         */
6694        "append" : true,
6695        /**
6696         * @event remove
6697         * Fires when a child node is removed
6698         * @param {Tree} tree The owner tree
6699         * @param {Node} this This node
6700         * @param {Node} node The removed node
6701         */
6702        "remove" : true,
6703        /**
6704         * @event move
6705         * Fires when this node is moved to a new location in the tree
6706         * @param {Tree} tree The owner tree
6707         * @param {Node} this This node
6708         * @param {Node} oldParent The old parent of this node
6709         * @param {Node} newParent The new parent of this node
6710         * @param {Number} index The index it was moved to
6711         */
6712        "move" : true,
6713        /**
6714         * @event insert
6715         * Fires when a new child node is inserted.
6716         * @param {Tree} tree The owner tree
6717         * @param {Node} this This node
6718         * @param {Node} node The child node inserted
6719         * @param {Node} refNode The child node the node was inserted before
6720         */
6721        "insert" : true,
6722        /**
6723         * @event beforeappend
6724         * Fires before a new child is appended, return false to cancel the append.
6725         * @param {Tree} tree The owner tree
6726         * @param {Node} this This node
6727         * @param {Node} node The child node to be appended
6728         */
6729        "beforeappend" : true,
6730        /**
6731         * @event beforeremove
6732         * Fires before a child is removed, return false to cancel the remove.
6733         * @param {Tree} tree The owner tree
6734         * @param {Node} this This node
6735         * @param {Node} node The child node to be removed
6736         */
6737        "beforeremove" : true,
6738        /**
6739         * @event beforemove
6740         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6741         * @param {Tree} tree The owner tree
6742         * @param {Node} this This node
6743         * @param {Node} oldParent The parent of this node
6744         * @param {Node} newParent The new parent this node is moving to
6745         * @param {Number} index The index it is being moved to
6746         */
6747        "beforemove" : true,
6748        /**
6749         * @event beforeinsert
6750         * Fires before a new child is inserted, return false to cancel the insert.
6751         * @param {Tree} tree The owner tree
6752         * @param {Node} this This node
6753         * @param {Node} node The child node to be inserted
6754         * @param {Node} refNode The child node the node is being inserted before
6755         */
6756        "beforeinsert" : true
6757    });
6758     this.listeners = this.attributes.listeners;
6759     Roo.data.Node.superclass.constructor.call(this);
6760 };
6761
6762 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6763     fireEvent : function(evtName){
6764         // first do standard event for this node
6765         if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6766             return false;
6767         }
6768         // then bubble it up to the tree if the event wasn't cancelled
6769         var ot = this.getOwnerTree();
6770         if(ot){
6771             if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6772                 return false;
6773             }
6774         }
6775         return true;
6776     },
6777
6778     /**
6779      * Returns true if this node is a leaf
6780      * @return {Boolean}
6781      */
6782     isLeaf : function(){
6783         return this.leaf === true;
6784     },
6785
6786     // private
6787     setFirstChild : function(node){
6788         this.firstChild = node;
6789     },
6790
6791     //private
6792     setLastChild : function(node){
6793         this.lastChild = node;
6794     },
6795
6796
6797     /**
6798      * Returns true if this node is the last child of its parent
6799      * @return {Boolean}
6800      */
6801     isLast : function(){
6802        return (!this.parentNode ? true : this.parentNode.lastChild == this);
6803     },
6804
6805     /**
6806      * Returns true if this node is the first child of its parent
6807      * @return {Boolean}
6808      */
6809     isFirst : function(){
6810        return (!this.parentNode ? true : this.parentNode.firstChild == this);
6811     },
6812
6813     hasChildNodes : function(){
6814         return !this.isLeaf() && this.childNodes.length > 0;
6815     },
6816
6817     /**
6818      * Insert node(s) as the last child node of this node.
6819      * @param {Node/Array} node The node or Array of nodes to append
6820      * @return {Node} The appended node if single append, or null if an array was passed
6821      */
6822     appendChild : function(node){
6823         var multi = false;
6824         if(node instanceof Array){
6825             multi = node;
6826         }else if(arguments.length > 1){
6827             multi = arguments;
6828         }
6829         // if passed an array or multiple args do them one by one
6830         if(multi){
6831             for(var i = 0, len = multi.length; i < len; i++) {
6832                 this.appendChild(multi[i]);
6833             }
6834         }else{
6835             if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6836                 return false;
6837             }
6838             var index = this.childNodes.length;
6839             var oldParent = node.parentNode;
6840             // it's a move, make sure we move it cleanly
6841             if(oldParent){
6842                 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6843                     return false;
6844                 }
6845                 oldParent.removeChild(node);
6846             }
6847             index = this.childNodes.length;
6848             if(index == 0){
6849                 this.setFirstChild(node);
6850             }
6851             this.childNodes.push(node);
6852             node.parentNode = this;
6853             var ps = this.childNodes[index-1];
6854             if(ps){
6855                 node.previousSibling = ps;
6856                 ps.nextSibling = node;
6857             }else{
6858                 node.previousSibling = null;
6859             }
6860             node.nextSibling = null;
6861             this.setLastChild(node);
6862             node.setOwnerTree(this.getOwnerTree());
6863             this.fireEvent("append", this.ownerTree, this, node, index);
6864             if(oldParent){
6865                 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6866             }
6867             return node;
6868         }
6869     },
6870
6871     /**
6872      * Removes a child node from this node.
6873      * @param {Node} node The node to remove
6874      * @return {Node} The removed node
6875      */
6876     removeChild : function(node){
6877         var index = this.childNodes.indexOf(node);
6878         if(index == -1){
6879             return false;
6880         }
6881         if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6882             return false;
6883         }
6884
6885         // remove it from childNodes collection
6886         this.childNodes.splice(index, 1);
6887
6888         // update siblings
6889         if(node.previousSibling){
6890             node.previousSibling.nextSibling = node.nextSibling;
6891         }
6892         if(node.nextSibling){
6893             node.nextSibling.previousSibling = node.previousSibling;
6894         }
6895
6896         // update child refs
6897         if(this.firstChild == node){
6898             this.setFirstChild(node.nextSibling);
6899         }
6900         if(this.lastChild == node){
6901             this.setLastChild(node.previousSibling);
6902         }
6903
6904         node.setOwnerTree(null);
6905         // clear any references from the node
6906         node.parentNode = null;
6907         node.previousSibling = null;
6908         node.nextSibling = null;
6909         this.fireEvent("remove", this.ownerTree, this, node);
6910         return node;
6911     },
6912
6913     /**
6914      * Inserts the first node before the second node in this nodes childNodes collection.
6915      * @param {Node} node The node to insert
6916      * @param {Node} refNode The node to insert before (if null the node is appended)
6917      * @return {Node} The inserted node
6918      */
6919     insertBefore : function(node, refNode){
6920         if(!refNode){ // like standard Dom, refNode can be null for append
6921             return this.appendChild(node);
6922         }
6923         // nothing to do
6924         if(node == refNode){
6925             return false;
6926         }
6927
6928         if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6929             return false;
6930         }
6931         var index = this.childNodes.indexOf(refNode);
6932         var oldParent = node.parentNode;
6933         var refIndex = index;
6934
6935         // when moving internally, indexes will change after remove
6936         if(oldParent == this && this.childNodes.indexOf(node) < index){
6937             refIndex--;
6938         }
6939
6940         // it's a move, make sure we move it cleanly
6941         if(oldParent){
6942             if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6943                 return false;
6944             }
6945             oldParent.removeChild(node);
6946         }
6947         if(refIndex == 0){
6948             this.setFirstChild(node);
6949         }
6950         this.childNodes.splice(refIndex, 0, node);
6951         node.parentNode = this;
6952         var ps = this.childNodes[refIndex-1];
6953         if(ps){
6954             node.previousSibling = ps;
6955             ps.nextSibling = node;
6956         }else{
6957             node.previousSibling = null;
6958         }
6959         node.nextSibling = refNode;
6960         refNode.previousSibling = node;
6961         node.setOwnerTree(this.getOwnerTree());
6962         this.fireEvent("insert", this.ownerTree, this, node, refNode);
6963         if(oldParent){
6964             node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6965         }
6966         return node;
6967     },
6968
6969     /**
6970      * Returns the child node at the specified index.
6971      * @param {Number} index
6972      * @return {Node}
6973      */
6974     item : function(index){
6975         return this.childNodes[index];
6976     },
6977
6978     /**
6979      * Replaces one child node in this node with another.
6980      * @param {Node} newChild The replacement node
6981      * @param {Node} oldChild The node to replace
6982      * @return {Node} The replaced node
6983      */
6984     replaceChild : function(newChild, oldChild){
6985         this.insertBefore(newChild, oldChild);
6986         this.removeChild(oldChild);
6987         return oldChild;
6988     },
6989
6990     /**
6991      * Returns the index of a child node
6992      * @param {Node} node
6993      * @return {Number} The index of the node or -1 if it was not found
6994      */
6995     indexOf : function(child){
6996         return this.childNodes.indexOf(child);
6997     },
6998
6999     /**
7000      * Returns the tree this node is in.
7001      * @return {Tree}
7002      */
7003     getOwnerTree : function(){
7004         // if it doesn't have one, look for one
7005         if(!this.ownerTree){
7006             var p = this;
7007             while(p){
7008                 if(p.ownerTree){
7009                     this.ownerTree = p.ownerTree;
7010                     break;
7011                 }
7012                 p = p.parentNode;
7013             }
7014         }
7015         return this.ownerTree;
7016     },
7017
7018     /**
7019      * Returns depth of this node (the root node has a depth of 0)
7020      * @return {Number}
7021      */
7022     getDepth : function(){
7023         var depth = 0;
7024         var p = this;
7025         while(p.parentNode){
7026             ++depth;
7027             p = p.parentNode;
7028         }
7029         return depth;
7030     },
7031
7032     // private
7033     setOwnerTree : function(tree){
7034         // if it's move, we need to update everyone
7035         if(tree != this.ownerTree){
7036             if(this.ownerTree){
7037                 this.ownerTree.unregisterNode(this);
7038             }
7039             this.ownerTree = tree;
7040             var cs = this.childNodes;
7041             for(var i = 0, len = cs.length; i < len; i++) {
7042                 cs[i].setOwnerTree(tree);
7043             }
7044             if(tree){
7045                 tree.registerNode(this);
7046             }
7047         }
7048     },
7049
7050     /**
7051      * Returns the path for this node. The path can be used to expand or select this node programmatically.
7052      * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7053      * @return {String} The path
7054      */
7055     getPath : function(attr){
7056         attr = attr || "id";
7057         var p = this.parentNode;
7058         var b = [this.attributes[attr]];
7059         while(p){
7060             b.unshift(p.attributes[attr]);
7061             p = p.parentNode;
7062         }
7063         var sep = this.getOwnerTree().pathSeparator;
7064         return sep + b.join(sep);
7065     },
7066
7067     /**
7068      * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7069      * function call will be the scope provided or the current node. The arguments to the function
7070      * will be the args provided or the current node. If the function returns false at any point,
7071      * the bubble is stopped.
7072      * @param {Function} fn The function to call
7073      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7074      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7075      */
7076     bubble : function(fn, scope, args){
7077         var p = this;
7078         while(p){
7079             if(fn.call(scope || p, args || p) === false){
7080                 break;
7081             }
7082             p = p.parentNode;
7083         }
7084     },
7085
7086     /**
7087      * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7088      * function call will be the scope provided or the current node. The arguments to the function
7089      * will be the args provided or the current node. If the function returns false at any point,
7090      * the cascade is stopped on that branch.
7091      * @param {Function} fn The function to call
7092      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7093      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7094      */
7095     cascade : function(fn, scope, args){
7096         if(fn.call(scope || this, args || this) !== false){
7097             var cs = this.childNodes;
7098             for(var i = 0, len = cs.length; i < len; i++) {
7099                 cs[i].cascade(fn, scope, args);
7100             }
7101         }
7102     },
7103
7104     /**
7105      * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7106      * function call will be the scope provided or the current node. The arguments to the function
7107      * will be the args provided or the current node. If the function returns false at any point,
7108      * the iteration stops.
7109      * @param {Function} fn The function to call
7110      * @param {Object} scope (optional) The scope of the function (defaults to current node)
7111      * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7112      */
7113     eachChild : function(fn, scope, args){
7114         var cs = this.childNodes;
7115         for(var i = 0, len = cs.length; i < len; i++) {
7116                 if(fn.call(scope || this, args || cs[i]) === false){
7117                     break;
7118                 }
7119         }
7120     },
7121
7122     /**
7123      * Finds the first child that has the attribute with the specified value.
7124      * @param {String} attribute The attribute name
7125      * @param {Mixed} value The value to search for
7126      * @return {Node} The found child or null if none was found
7127      */
7128     findChild : function(attribute, value){
7129         var cs = this.childNodes;
7130         for(var i = 0, len = cs.length; i < len; i++) {
7131                 if(cs[i].attributes[attribute] == value){
7132                     return cs[i];
7133                 }
7134         }
7135         return null;
7136     },
7137
7138     /**
7139      * Finds the first child by a custom function. The child matches if the function passed
7140      * returns true.
7141      * @param {Function} fn
7142      * @param {Object} scope (optional)
7143      * @return {Node} The found child or null if none was found
7144      */
7145     findChildBy : function(fn, scope){
7146         var cs = this.childNodes;
7147         for(var i = 0, len = cs.length; i < len; i++) {
7148                 if(fn.call(scope||cs[i], cs[i]) === true){
7149                     return cs[i];
7150                 }
7151         }
7152         return null;
7153     },
7154
7155     /**
7156      * Sorts this nodes children using the supplied sort function
7157      * @param {Function} fn
7158      * @param {Object} scope (optional)
7159      */
7160     sort : function(fn, scope){
7161         var cs = this.childNodes;
7162         var len = cs.length;
7163         if(len > 0){
7164             var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7165             cs.sort(sortFn);
7166             for(var i = 0; i < len; i++){
7167                 var n = cs[i];
7168                 n.previousSibling = cs[i-1];
7169                 n.nextSibling = cs[i+1];
7170                 if(i == 0){
7171                     this.setFirstChild(n);
7172                 }
7173                 if(i == len-1){
7174                     this.setLastChild(n);
7175                 }
7176             }
7177         }
7178     },
7179
7180     /**
7181      * Returns true if this node is an ancestor (at any point) of the passed node.
7182      * @param {Node} node
7183      * @return {Boolean}
7184      */
7185     contains : function(node){
7186         return node.isAncestor(this);
7187     },
7188
7189     /**
7190      * Returns true if the passed node is an ancestor (at any point) of this node.
7191      * @param {Node} node
7192      * @return {Boolean}
7193      */
7194     isAncestor : function(node){
7195         var p = this.parentNode;
7196         while(p){
7197             if(p == node){
7198                 return true;
7199             }
7200             p = p.parentNode;
7201         }
7202         return false;
7203     },
7204
7205     toString : function(){
7206         return "[Node"+(this.id?" "+this.id:"")+"]";
7207     }
7208 });/*
7209  * Based on:
7210  * Ext JS Library 1.1.1
7211  * Copyright(c) 2006-2007, Ext JS, LLC.
7212  *
7213  * Originally Released Under LGPL - original licence link has changed is not relivant.
7214  *
7215  * Fork - LGPL
7216  * <script type="text/javascript">
7217  */
7218  
7219
7220 /**
7221  * @class Roo.ComponentMgr
7222  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7223  * @singleton
7224  */
7225 Roo.ComponentMgr = function(){
7226     var all = new Roo.util.MixedCollection();
7227
7228     return {
7229         /**
7230          * Registers a component.
7231          * @param {Roo.Component} c The component
7232          */
7233         register : function(c){
7234             all.add(c);
7235         },
7236
7237         /**
7238          * Unregisters a component.
7239          * @param {Roo.Component} c The component
7240          */
7241         unregister : function(c){
7242             all.remove(c);
7243         },
7244
7245         /**
7246          * Returns a component by id
7247          * @param {String} id The component id
7248          */
7249         get : function(id){
7250             return all.get(id);
7251         },
7252
7253         /**
7254          * Registers a function that will be called when a specified component is added to ComponentMgr
7255          * @param {String} id The component id
7256          * @param {Funtction} fn The callback function
7257          * @param {Object} scope The scope of the callback
7258          */
7259         onAvailable : function(id, fn, scope){
7260             all.on("add", function(index, o){
7261                 if(o.id == id){
7262                     fn.call(scope || o, o);
7263                     all.un("add", fn, scope);
7264                 }
7265             });
7266         }
7267     };
7268 }();/*
7269  * Based on:
7270  * Ext JS Library 1.1.1
7271  * Copyright(c) 2006-2007, Ext JS, LLC.
7272  *
7273  * Originally Released Under LGPL - original licence link has changed is not relivant.
7274  *
7275  * Fork - LGPL
7276  * <script type="text/javascript">
7277  */
7278  
7279 /**
7280  * @class Roo.Component
7281  * @extends Roo.util.Observable
7282  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
7283  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
7284  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7285  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7286  * All visual components (widgets) that require rendering into a layout should subclass Component.
7287  * @constructor
7288  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
7289  * 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
7290  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
7291  */
7292 Roo.Component = function(config){
7293     config = config || {};
7294     if(config.tagName || config.dom || typeof config == "string"){ // element object
7295         config = {el: config, id: config.id || config};
7296     }
7297     this.initialConfig = config;
7298
7299     Roo.apply(this, config);
7300     this.addEvents({
7301         /**
7302          * @event disable
7303          * Fires after the component is disabled.
7304              * @param {Roo.Component} this
7305              */
7306         disable : true,
7307         /**
7308          * @event enable
7309          * Fires after the component is enabled.
7310              * @param {Roo.Component} this
7311              */
7312         enable : true,
7313         /**
7314          * @event beforeshow
7315          * Fires before the component is shown.  Return false to stop the show.
7316              * @param {Roo.Component} this
7317              */
7318         beforeshow : true,
7319         /**
7320          * @event show
7321          * Fires after the component is shown.
7322              * @param {Roo.Component} this
7323              */
7324         show : true,
7325         /**
7326          * @event beforehide
7327          * Fires before the component is hidden. Return false to stop the hide.
7328              * @param {Roo.Component} this
7329              */
7330         beforehide : true,
7331         /**
7332          * @event hide
7333          * Fires after the component is hidden.
7334              * @param {Roo.Component} this
7335              */
7336         hide : true,
7337         /**
7338          * @event beforerender
7339          * Fires before the component is rendered. Return false to stop the render.
7340              * @param {Roo.Component} this
7341              */
7342         beforerender : true,
7343         /**
7344          * @event render
7345          * Fires after the component is rendered.
7346              * @param {Roo.Component} this
7347              */
7348         render : true,
7349         /**
7350          * @event beforedestroy
7351          * Fires before the component is destroyed. Return false to stop the destroy.
7352              * @param {Roo.Component} this
7353              */
7354         beforedestroy : true,
7355         /**
7356          * @event destroy
7357          * Fires after the component is destroyed.
7358              * @param {Roo.Component} this
7359              */
7360         destroy : true
7361     });
7362     if(!this.id){
7363         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7364     }
7365     Roo.ComponentMgr.register(this);
7366     Roo.Component.superclass.constructor.call(this);
7367     this.initComponent();
7368     if(this.renderTo){ // not supported by all components yet. use at your own risk!
7369         this.render(this.renderTo);
7370         delete this.renderTo;
7371     }
7372 };
7373
7374 // private
7375 Roo.Component.AUTO_ID = 1000;
7376
7377 Roo.extend(Roo.Component, Roo.util.Observable, {
7378     /**
7379      * @property {Boolean} hidden
7380      * true if this component is hidden. Read-only.
7381      */
7382     hidden : false,
7383     /**
7384      * true if this component is disabled. Read-only.
7385      */
7386     disabled : false,
7387     /**
7388      * true if this component has been rendered. Read-only.
7389      */
7390     rendered : false,
7391     
7392     /** @cfg {String} disableClass
7393      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7394      */
7395     disabledClass : "x-item-disabled",
7396         /** @cfg {Boolean} allowDomMove
7397          * Whether the component can move the Dom node when rendering (defaults to true).
7398          */
7399     allowDomMove : true,
7400     /** @cfg {String} hideMode
7401      * How this component should hidden. Supported values are
7402      * "visibility" (css visibility), "offsets" (negative offset position) and
7403      * "display" (css display) - defaults to "display".
7404      */
7405     hideMode: 'display',
7406
7407     // private
7408     ctype : "Roo.Component",
7409
7410     /** @cfg {String} actionMode 
7411      * which property holds the element that used for  hide() / show() / disable() / enable()
7412      * default is 'el' 
7413      */
7414     actionMode : "el",
7415
7416     // private
7417     getActionEl : function(){
7418         return this[this.actionMode];
7419     },
7420
7421     initComponent : Roo.emptyFn,
7422     /**
7423      * If this is a lazy rendering component, render it to its container element.
7424      * @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.
7425      */
7426     render : function(container, position){
7427         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7428             if(!container && this.el){
7429                 this.el = Roo.get(this.el);
7430                 container = this.el.dom.parentNode;
7431                 this.allowDomMove = false;
7432             }
7433             this.container = Roo.get(container);
7434             this.rendered = true;
7435             if(position !== undefined){
7436                 if(typeof position == 'number'){
7437                     position = this.container.dom.childNodes[position];
7438                 }else{
7439                     position = Roo.getDom(position);
7440                 }
7441             }
7442             this.onRender(this.container, position || null);
7443             if(this.cls){
7444                 this.el.addClass(this.cls);
7445                 delete this.cls;
7446             }
7447             if(this.style){
7448                 this.el.applyStyles(this.style);
7449                 delete this.style;
7450             }
7451             this.fireEvent("render", this);
7452             this.afterRender(this.container);
7453             if(this.hidden){
7454                 this.hide();
7455             }
7456             if(this.disabled){
7457                 this.disable();
7458             }
7459         }
7460         return this;
7461     },
7462
7463     // private
7464     // default function is not really useful
7465     onRender : function(ct, position){
7466         if(this.el){
7467             this.el = Roo.get(this.el);
7468             if(this.allowDomMove !== false){
7469                 ct.dom.insertBefore(this.el.dom, position);
7470             }
7471         }
7472     },
7473
7474     // private
7475     getAutoCreate : function(){
7476         var cfg = typeof this.autoCreate == "object" ?
7477                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7478         if(this.id && !cfg.id){
7479             cfg.id = this.id;
7480         }
7481         return cfg;
7482     },
7483
7484     // private
7485     afterRender : Roo.emptyFn,
7486
7487     /**
7488      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7489      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7490      */
7491     destroy : function(){
7492         if(this.fireEvent("beforedestroy", this) !== false){
7493             this.purgeListeners();
7494             this.beforeDestroy();
7495             if(this.rendered){
7496                 this.el.removeAllListeners();
7497                 this.el.remove();
7498                 if(this.actionMode == "container"){
7499                     this.container.remove();
7500                 }
7501             }
7502             this.onDestroy();
7503             Roo.ComponentMgr.unregister(this);
7504             this.fireEvent("destroy", this);
7505         }
7506     },
7507
7508         // private
7509     beforeDestroy : function(){
7510
7511     },
7512
7513         // private
7514         onDestroy : function(){
7515
7516     },
7517
7518     /**
7519      * Returns the underlying {@link Roo.Element}.
7520      * @return {Roo.Element} The element
7521      */
7522     getEl : function(){
7523         return this.el;
7524     },
7525
7526     /**
7527      * Returns the id of this component.
7528      * @return {String}
7529      */
7530     getId : function(){
7531         return this.id;
7532     },
7533
7534     /**
7535      * Try to focus this component.
7536      * @param {Boolean} selectText True to also select the text in this component (if applicable)
7537      * @return {Roo.Component} this
7538      */
7539     focus : function(selectText){
7540         if(this.rendered){
7541             this.el.focus();
7542             if(selectText === true){
7543                 this.el.dom.select();
7544             }
7545         }
7546         return this;
7547     },
7548
7549     // private
7550     blur : function(){
7551         if(this.rendered){
7552             this.el.blur();
7553         }
7554         return this;
7555     },
7556
7557     /**
7558      * Disable this component.
7559      * @return {Roo.Component} this
7560      */
7561     disable : function(){
7562         if(this.rendered){
7563             this.onDisable();
7564         }
7565         this.disabled = true;
7566         this.fireEvent("disable", this);
7567         return this;
7568     },
7569
7570         // private
7571     onDisable : function(){
7572         this.getActionEl().addClass(this.disabledClass);
7573         this.el.dom.disabled = true;
7574     },
7575
7576     /**
7577      * Enable this component.
7578      * @return {Roo.Component} this
7579      */
7580     enable : function(){
7581         if(this.rendered){
7582             this.onEnable();
7583         }
7584         this.disabled = false;
7585         this.fireEvent("enable", this);
7586         return this;
7587     },
7588
7589         // private
7590     onEnable : function(){
7591         this.getActionEl().removeClass(this.disabledClass);
7592         this.el.dom.disabled = false;
7593     },
7594
7595     /**
7596      * Convenience function for setting disabled/enabled by boolean.
7597      * @param {Boolean} disabled
7598      */
7599     setDisabled : function(disabled){
7600         this[disabled ? "disable" : "enable"]();
7601     },
7602
7603     /**
7604      * Show this component.
7605      * @return {Roo.Component} this
7606      */
7607     show: function(){
7608         if(this.fireEvent("beforeshow", this) !== false){
7609             this.hidden = false;
7610             if(this.rendered){
7611                 this.onShow();
7612             }
7613             this.fireEvent("show", this);
7614         }
7615         return this;
7616     },
7617
7618     // private
7619     onShow : function(){
7620         var ae = this.getActionEl();
7621         if(this.hideMode == 'visibility'){
7622             ae.dom.style.visibility = "visible";
7623         }else if(this.hideMode == 'offsets'){
7624             ae.removeClass('x-hidden');
7625         }else{
7626             ae.dom.style.display = "";
7627         }
7628     },
7629
7630     /**
7631      * Hide this component.
7632      * @return {Roo.Component} this
7633      */
7634     hide: function(){
7635         if(this.fireEvent("beforehide", this) !== false){
7636             this.hidden = true;
7637             if(this.rendered){
7638                 this.onHide();
7639             }
7640             this.fireEvent("hide", this);
7641         }
7642         return this;
7643     },
7644
7645     // private
7646     onHide : function(){
7647         var ae = this.getActionEl();
7648         if(this.hideMode == 'visibility'){
7649             ae.dom.style.visibility = "hidden";
7650         }else if(this.hideMode == 'offsets'){
7651             ae.addClass('x-hidden');
7652         }else{
7653             ae.dom.style.display = "none";
7654         }
7655     },
7656
7657     /**
7658      * Convenience function to hide or show this component by boolean.
7659      * @param {Boolean} visible True to show, false to hide
7660      * @return {Roo.Component} this
7661      */
7662     setVisible: function(visible){
7663         if(visible) {
7664             this.show();
7665         }else{
7666             this.hide();
7667         }
7668         return this;
7669     },
7670
7671     /**
7672      * Returns true if this component is visible.
7673      */
7674     isVisible : function(){
7675         return this.getActionEl().isVisible();
7676     },
7677
7678     cloneConfig : function(overrides){
7679         overrides = overrides || {};
7680         var id = overrides.id || Roo.id();
7681         var cfg = Roo.applyIf(overrides, this.initialConfig);
7682         cfg.id = id; // prevent dup id
7683         return new this.constructor(cfg);
7684     }
7685 });/*
7686  * Based on:
7687  * Ext JS Library 1.1.1
7688  * Copyright(c) 2006-2007, Ext JS, LLC.
7689  *
7690  * Originally Released Under LGPL - original licence link has changed is not relivant.
7691  *
7692  * Fork - LGPL
7693  * <script type="text/javascript">
7694  */
7695  (function(){ 
7696 /**
7697  * @class Roo.Layer
7698  * @extends Roo.Element
7699  * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7700  * automatic maintaining of shadow/shim positions.
7701  * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7702  * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7703  * you can pass a string with a CSS class name. False turns off the shadow.
7704  * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7705  * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7706  * @cfg {String} cls CSS class to add to the element
7707  * @cfg {Number} zindex Starting z-index (defaults to 11000)
7708  * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7709  * @constructor
7710  * @param {Object} config An object with config options.
7711  * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7712  */
7713
7714 Roo.Layer = function(config, existingEl){
7715     config = config || {};
7716     var dh = Roo.DomHelper;
7717     var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7718     if(existingEl){
7719         this.dom = Roo.getDom(existingEl);
7720     }
7721     if(!this.dom){
7722         var o = config.dh || {tag: "div", cls: "x-layer"};
7723         this.dom = dh.append(pel, o);
7724     }
7725     if(config.cls){
7726         this.addClass(config.cls);
7727     }
7728     this.constrain = config.constrain !== false;
7729     this.visibilityMode = Roo.Element.VISIBILITY;
7730     if(config.id){
7731         this.id = this.dom.id = config.id;
7732     }else{
7733         this.id = Roo.id(this.dom);
7734     }
7735     this.zindex = config.zindex || this.getZIndex();
7736     this.position("absolute", this.zindex);
7737     if(config.shadow){
7738         this.shadowOffset = config.shadowOffset || 4;
7739         this.shadow = new Roo.Shadow({
7740             offset : this.shadowOffset,
7741             mode : config.shadow
7742         });
7743     }else{
7744         this.shadowOffset = 0;
7745     }
7746     this.useShim = config.shim !== false && Roo.useShims;
7747     this.useDisplay = config.useDisplay;
7748     this.hide();
7749 };
7750
7751 var supr = Roo.Element.prototype;
7752
7753 // shims are shared among layer to keep from having 100 iframes
7754 var shims = [];
7755
7756 Roo.extend(Roo.Layer, Roo.Element, {
7757
7758     getZIndex : function(){
7759         return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7760     },
7761
7762     getShim : function(){
7763         if(!this.useShim){
7764             return null;
7765         }
7766         if(this.shim){
7767             return this.shim;
7768         }
7769         var shim = shims.shift();
7770         if(!shim){
7771             shim = this.createShim();
7772             shim.enableDisplayMode('block');
7773             shim.dom.style.display = 'none';
7774             shim.dom.style.visibility = 'visible';
7775         }
7776         var pn = this.dom.parentNode;
7777         if(shim.dom.parentNode != pn){
7778             pn.insertBefore(shim.dom, this.dom);
7779         }
7780         shim.setStyle('z-index', this.getZIndex()-2);
7781         this.shim = shim;
7782         return shim;
7783     },
7784
7785     hideShim : function(){
7786         if(this.shim){
7787             this.shim.setDisplayed(false);
7788             shims.push(this.shim);
7789             delete this.shim;
7790         }
7791     },
7792
7793     disableShadow : function(){
7794         if(this.shadow){
7795             this.shadowDisabled = true;
7796             this.shadow.hide();
7797             this.lastShadowOffset = this.shadowOffset;
7798             this.shadowOffset = 0;
7799         }
7800     },
7801
7802     enableShadow : function(show){
7803         if(this.shadow){
7804             this.shadowDisabled = false;
7805             this.shadowOffset = this.lastShadowOffset;
7806             delete this.lastShadowOffset;
7807             if(show){
7808                 this.sync(true);
7809             }
7810         }
7811     },
7812
7813     // private
7814     // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7815     // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7816     sync : function(doShow){
7817         var sw = this.shadow;
7818         if(!this.updating && this.isVisible() && (sw || this.useShim)){
7819             var sh = this.getShim();
7820
7821             var w = this.getWidth(),
7822                 h = this.getHeight();
7823
7824             var l = this.getLeft(true),
7825                 t = this.getTop(true);
7826
7827             if(sw && !this.shadowDisabled){
7828                 if(doShow && !sw.isVisible()){
7829                     sw.show(this);
7830                 }else{
7831                     sw.realign(l, t, w, h);
7832                 }
7833                 if(sh){
7834                     if(doShow){
7835                        sh.show();
7836                     }
7837                     // fit the shim behind the shadow, so it is shimmed too
7838                     var a = sw.adjusts, s = sh.dom.style;
7839                     s.left = (Math.min(l, l+a.l))+"px";
7840                     s.top = (Math.min(t, t+a.t))+"px";
7841                     s.width = (w+a.w)+"px";
7842                     s.height = (h+a.h)+"px";
7843                 }
7844             }else if(sh){
7845                 if(doShow){
7846                    sh.show();
7847                 }
7848                 sh.setSize(w, h);
7849                 sh.setLeftTop(l, t);
7850             }
7851             
7852         }
7853     },
7854
7855     // private
7856     destroy : function(){
7857         this.hideShim();
7858         if(this.shadow){
7859             this.shadow.hide();
7860         }
7861         this.removeAllListeners();
7862         var pn = this.dom.parentNode;
7863         if(pn){
7864             pn.removeChild(this.dom);
7865         }
7866         Roo.Element.uncache(this.id);
7867     },
7868
7869     remove : function(){
7870         this.destroy();
7871     },
7872
7873     // private
7874     beginUpdate : function(){
7875         this.updating = true;
7876     },
7877
7878     // private
7879     endUpdate : function(){
7880         this.updating = false;
7881         this.sync(true);
7882     },
7883
7884     // private
7885     hideUnders : function(negOffset){
7886         if(this.shadow){
7887             this.shadow.hide();
7888         }
7889         this.hideShim();
7890     },
7891
7892     // private
7893     constrainXY : function(){
7894         if(this.constrain){
7895             var vw = Roo.lib.Dom.getViewWidth(),
7896                 vh = Roo.lib.Dom.getViewHeight();
7897             var s = Roo.get(document).getScroll();
7898
7899             var xy = this.getXY();
7900             var x = xy[0], y = xy[1];   
7901             var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7902             // only move it if it needs it
7903             var moved = false;
7904             // first validate right/bottom
7905             if((x + w) > vw+s.left){
7906                 x = vw - w - this.shadowOffset;
7907                 moved = true;
7908             }
7909             if((y + h) > vh+s.top){
7910                 y = vh - h - this.shadowOffset;
7911                 moved = true;
7912             }
7913             // then make sure top/left isn't negative
7914             if(x < s.left){
7915                 x = s.left;
7916                 moved = true;
7917             }
7918             if(y < s.top){
7919                 y = s.top;
7920                 moved = true;
7921             }
7922             if(moved){
7923                 if(this.avoidY){
7924                     var ay = this.avoidY;
7925                     if(y <= ay && (y+h) >= ay){
7926                         y = ay-h-5;   
7927                     }
7928                 }
7929                 xy = [x, y];
7930                 this.storeXY(xy);
7931                 supr.setXY.call(this, xy);
7932                 this.sync();
7933             }
7934         }
7935     },
7936
7937     isVisible : function(){
7938         return this.visible;    
7939     },
7940
7941     // private
7942     showAction : function(){
7943         this.visible = true; // track visibility to prevent getStyle calls
7944         if(this.useDisplay === true){
7945             this.setDisplayed("");
7946         }else if(this.lastXY){
7947             supr.setXY.call(this, this.lastXY);
7948         }else if(this.lastLT){
7949             supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7950         }
7951     },
7952
7953     // private
7954     hideAction : function(){
7955         this.visible = false;
7956         if(this.useDisplay === true){
7957             this.setDisplayed(false);
7958         }else{
7959             this.setLeftTop(-10000,-10000);
7960         }
7961     },
7962
7963     // overridden Element method
7964     setVisible : function(v, a, d, c, e){
7965         if(v){
7966             this.showAction();
7967         }
7968         if(a && v){
7969             var cb = function(){
7970                 this.sync(true);
7971                 if(c){
7972                     c();
7973                 }
7974             }.createDelegate(this);
7975             supr.setVisible.call(this, true, true, d, cb, e);
7976         }else{
7977             if(!v){
7978                 this.hideUnders(true);
7979             }
7980             var cb = c;
7981             if(a){
7982                 cb = function(){
7983                     this.hideAction();
7984                     if(c){
7985                         c();
7986                     }
7987                 }.createDelegate(this);
7988             }
7989             supr.setVisible.call(this, v, a, d, cb, e);
7990             if(v){
7991                 this.sync(true);
7992             }else if(!a){
7993                 this.hideAction();
7994             }
7995         }
7996     },
7997
7998     storeXY : function(xy){
7999         delete this.lastLT;
8000         this.lastXY = xy;
8001     },
8002
8003     storeLeftTop : function(left, top){
8004         delete this.lastXY;
8005         this.lastLT = [left, top];
8006     },
8007
8008     // private
8009     beforeFx : function(){
8010         this.beforeAction();
8011         return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8012     },
8013
8014     // private
8015     afterFx : function(){
8016         Roo.Layer.superclass.afterFx.apply(this, arguments);
8017         this.sync(this.isVisible());
8018     },
8019
8020     // private
8021     beforeAction : function(){
8022         if(!this.updating && this.shadow){
8023             this.shadow.hide();
8024         }
8025     },
8026
8027     // overridden Element method
8028     setLeft : function(left){
8029         this.storeLeftTop(left, this.getTop(true));
8030         supr.setLeft.apply(this, arguments);
8031         this.sync();
8032     },
8033
8034     setTop : function(top){
8035         this.storeLeftTop(this.getLeft(true), top);
8036         supr.setTop.apply(this, arguments);
8037         this.sync();
8038     },
8039
8040     setLeftTop : function(left, top){
8041         this.storeLeftTop(left, top);
8042         supr.setLeftTop.apply(this, arguments);
8043         this.sync();
8044     },
8045
8046     setXY : function(xy, a, d, c, e){
8047         this.fixDisplay();
8048         this.beforeAction();
8049         this.storeXY(xy);
8050         var cb = this.createCB(c);
8051         supr.setXY.call(this, xy, a, d, cb, e);
8052         if(!a){
8053             cb();
8054         }
8055     },
8056
8057     // private
8058     createCB : function(c){
8059         var el = this;
8060         return function(){
8061             el.constrainXY();
8062             el.sync(true);
8063             if(c){
8064                 c();
8065             }
8066         };
8067     },
8068
8069     // overridden Element method
8070     setX : function(x, a, d, c, e){
8071         this.setXY([x, this.getY()], a, d, c, e);
8072     },
8073
8074     // overridden Element method
8075     setY : function(y, a, d, c, e){
8076         this.setXY([this.getX(), y], a, d, c, e);
8077     },
8078
8079     // overridden Element method
8080     setSize : function(w, h, a, d, c, e){
8081         this.beforeAction();
8082         var cb = this.createCB(c);
8083         supr.setSize.call(this, w, h, a, d, cb, e);
8084         if(!a){
8085             cb();
8086         }
8087     },
8088
8089     // overridden Element method
8090     setWidth : function(w, a, d, c, e){
8091         this.beforeAction();
8092         var cb = this.createCB(c);
8093         supr.setWidth.call(this, w, a, d, cb, e);
8094         if(!a){
8095             cb();
8096         }
8097     },
8098
8099     // overridden Element method
8100     setHeight : function(h, a, d, c, e){
8101         this.beforeAction();
8102         var cb = this.createCB(c);
8103         supr.setHeight.call(this, h, a, d, cb, e);
8104         if(!a){
8105             cb();
8106         }
8107     },
8108
8109     // overridden Element method
8110     setBounds : function(x, y, w, h, a, d, c, e){
8111         this.beforeAction();
8112         var cb = this.createCB(c);
8113         if(!a){
8114             this.storeXY([x, y]);
8115             supr.setXY.call(this, [x, y]);
8116             supr.setSize.call(this, w, h, a, d, cb, e);
8117             cb();
8118         }else{
8119             supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8120         }
8121         return this;
8122     },
8123     
8124     /**
8125      * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8126      * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8127      * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8128      * @param {Number} zindex The new z-index to set
8129      * @return {this} The Layer
8130      */
8131     setZIndex : function(zindex){
8132         this.zindex = zindex;
8133         this.setStyle("z-index", zindex + 2);
8134         if(this.shadow){
8135             this.shadow.setZIndex(zindex + 1);
8136         }
8137         if(this.shim){
8138             this.shim.setStyle("z-index", zindex);
8139         }
8140     }
8141 });
8142 })();/*
8143  * Based on:
8144  * Ext JS Library 1.1.1
8145  * Copyright(c) 2006-2007, Ext JS, LLC.
8146  *
8147  * Originally Released Under LGPL - original licence link has changed is not relivant.
8148  *
8149  * Fork - LGPL
8150  * <script type="text/javascript">
8151  */
8152
8153
8154 /**
8155  * @class Roo.Shadow
8156  * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
8157  * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
8158  * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8159  * @constructor
8160  * Create a new Shadow
8161  * @param {Object} config The config object
8162  */
8163 Roo.Shadow = function(config){
8164     Roo.apply(this, config);
8165     if(typeof this.mode != "string"){
8166         this.mode = this.defaultMode;
8167     }
8168     var o = this.offset, a = {h: 0};
8169     var rad = Math.floor(this.offset/2);
8170     switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8171         case "drop":
8172             a.w = 0;
8173             a.l = a.t = o;
8174             a.t -= 1;
8175             if(Roo.isIE){
8176                 a.l -= this.offset + rad;
8177                 a.t -= this.offset + rad;
8178                 a.w -= rad;
8179                 a.h -= rad;
8180                 a.t += 1;
8181             }
8182         break;
8183         case "sides":
8184             a.w = (o*2);
8185             a.l = -o;
8186             a.t = o-1;
8187             if(Roo.isIE){
8188                 a.l -= (this.offset - rad);
8189                 a.t -= this.offset + rad;
8190                 a.l += 1;
8191                 a.w -= (this.offset - rad)*2;
8192                 a.w -= rad + 1;
8193                 a.h -= 1;
8194             }
8195         break;
8196         case "frame":
8197             a.w = a.h = (o*2);
8198             a.l = a.t = -o;
8199             a.t += 1;
8200             a.h -= 2;
8201             if(Roo.isIE){
8202                 a.l -= (this.offset - rad);
8203                 a.t -= (this.offset - rad);
8204                 a.l += 1;
8205                 a.w -= (this.offset + rad + 1);
8206                 a.h -= (this.offset + rad);
8207                 a.h += 1;
8208             }
8209         break;
8210     };
8211
8212     this.adjusts = a;
8213 };
8214
8215 Roo.Shadow.prototype = {
8216     /**
8217      * @cfg {String} mode
8218      * The shadow display mode.  Supports the following options:<br />
8219      * sides: Shadow displays on both sides and bottom only<br />
8220      * frame: Shadow displays equally on all four sides<br />
8221      * drop: Traditional bottom-right drop shadow (default)
8222      */
8223     /**
8224      * @cfg {String} offset
8225      * The number of pixels to offset the shadow from the element (defaults to 4)
8226      */
8227     offset: 4,
8228
8229     // private
8230     defaultMode: "drop",
8231
8232     /**
8233      * Displays the shadow under the target element
8234      * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8235      */
8236     show : function(target){
8237         target = Roo.get(target);
8238         if(!this.el){
8239             this.el = Roo.Shadow.Pool.pull();
8240             if(this.el.dom.nextSibling != target.dom){
8241                 this.el.insertBefore(target);
8242             }
8243         }
8244         this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8245         if(Roo.isIE){
8246             this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8247         }
8248         this.realign(
8249             target.getLeft(true),
8250             target.getTop(true),
8251             target.getWidth(),
8252             target.getHeight()
8253         );
8254         this.el.dom.style.display = "block";
8255     },
8256
8257     /**
8258      * Returns true if the shadow is visible, else false
8259      */
8260     isVisible : function(){
8261         return this.el ? true : false;  
8262     },
8263
8264     /**
8265      * Direct alignment when values are already available. Show must be called at least once before
8266      * calling this method to ensure it is initialized.
8267      * @param {Number} left The target element left position
8268      * @param {Number} top The target element top position
8269      * @param {Number} width The target element width
8270      * @param {Number} height The target element height
8271      */
8272     realign : function(l, t, w, h){
8273         if(!this.el){
8274             return;
8275         }
8276         var a = this.adjusts, d = this.el.dom, s = d.style;
8277         var iea = 0;
8278         s.left = (l+a.l)+"px";
8279         s.top = (t+a.t)+"px";
8280         var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8281  
8282         if(s.width != sws || s.height != shs){
8283             s.width = sws;
8284             s.height = shs;
8285             if(!Roo.isIE){
8286                 var cn = d.childNodes;
8287                 var sww = Math.max(0, (sw-12))+"px";
8288                 cn[0].childNodes[1].style.width = sww;
8289                 cn[1].childNodes[1].style.width = sww;
8290                 cn[2].childNodes[1].style.width = sww;
8291                 cn[1].style.height = Math.max(0, (sh-12))+"px";
8292             }
8293         }
8294     },
8295
8296     /**
8297      * Hides this shadow
8298      */
8299     hide : function(){
8300         if(this.el){
8301             this.el.dom.style.display = "none";
8302             Roo.Shadow.Pool.push(this.el);
8303             delete this.el;
8304         }
8305     },
8306
8307     /**
8308      * Adjust the z-index of this shadow
8309      * @param {Number} zindex The new z-index
8310      */
8311     setZIndex : function(z){
8312         this.zIndex = z;
8313         if(this.el){
8314             this.el.setStyle("z-index", z);
8315         }
8316     }
8317 };
8318
8319 // Private utility class that manages the internal Shadow cache
8320 Roo.Shadow.Pool = function(){
8321     var p = [];
8322     var markup = Roo.isIE ?
8323                  '<div class="x-ie-shadow"></div>' :
8324                  '<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>';
8325     return {
8326         pull : function(){
8327             var sh = p.shift();
8328             if(!sh){
8329                 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8330                 sh.autoBoxAdjust = false;
8331             }
8332             return sh;
8333         },
8334
8335         push : function(sh){
8336             p.push(sh);
8337         }
8338     };
8339 }();/*
8340  * Based on:
8341  * Ext JS Library 1.1.1
8342  * Copyright(c) 2006-2007, Ext JS, LLC.
8343  *
8344  * Originally Released Under LGPL - original licence link has changed is not relivant.
8345  *
8346  * Fork - LGPL
8347  * <script type="text/javascript">
8348  */
8349
8350 /**
8351  * @class Roo.BoxComponent
8352  * @extends Roo.Component
8353  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
8354  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
8355  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8356  * layout containers.
8357  * @constructor
8358  * @param {Roo.Element/String/Object} config The configuration options.
8359  */
8360 Roo.BoxComponent = function(config){
8361     Roo.Component.call(this, config);
8362     this.addEvents({
8363         /**
8364          * @event resize
8365          * Fires after the component is resized.
8366              * @param {Roo.Component} this
8367              * @param {Number} adjWidth The box-adjusted width that was set
8368              * @param {Number} adjHeight The box-adjusted height that was set
8369              * @param {Number} rawWidth The width that was originally specified
8370              * @param {Number} rawHeight The height that was originally specified
8371              */
8372         resize : true,
8373         /**
8374          * @event move
8375          * Fires after the component is moved.
8376              * @param {Roo.Component} this
8377              * @param {Number} x The new x position
8378              * @param {Number} y The new y position
8379              */
8380         move : true
8381     });
8382 };
8383
8384 Roo.extend(Roo.BoxComponent, Roo.Component, {
8385     // private, set in afterRender to signify that the component has been rendered
8386     boxReady : false,
8387     // private, used to defer height settings to subclasses
8388     deferHeight: false,
8389     /** @cfg {Number} width
8390      * width (optional) size of component
8391      */
8392      /** @cfg {Number} height
8393      * height (optional) size of component
8394      */
8395      
8396     /**
8397      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
8398      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8399      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8400      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8401      * @return {Roo.BoxComponent} this
8402      */
8403     setSize : function(w, h){
8404         // support for standard size objects
8405         if(typeof w == 'object'){
8406             h = w.height;
8407             w = w.width;
8408         }
8409         // not rendered
8410         if(!this.boxReady){
8411             this.width = w;
8412             this.height = h;
8413             return this;
8414         }
8415
8416         // prevent recalcs when not needed
8417         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8418             return this;
8419         }
8420         this.lastSize = {width: w, height: h};
8421
8422         var adj = this.adjustSize(w, h);
8423         var aw = adj.width, ah = adj.height;
8424         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8425             var rz = this.getResizeEl();
8426             if(!this.deferHeight && aw !== undefined && ah !== undefined){
8427                 rz.setSize(aw, ah);
8428             }else if(!this.deferHeight && ah !== undefined){
8429                 rz.setHeight(ah);
8430             }else if(aw !== undefined){
8431                 rz.setWidth(aw);
8432             }
8433             this.onResize(aw, ah, w, h);
8434             this.fireEvent('resize', this, aw, ah, w, h);
8435         }
8436         return this;
8437     },
8438
8439     /**
8440      * Gets the current size of the component's underlying element.
8441      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8442      */
8443     getSize : function(){
8444         return this.el.getSize();
8445     },
8446
8447     /**
8448      * Gets the current XY position of the component's underlying element.
8449      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8450      * @return {Array} The XY position of the element (e.g., [100, 200])
8451      */
8452     getPosition : function(local){
8453         if(local === true){
8454             return [this.el.getLeft(true), this.el.getTop(true)];
8455         }
8456         return this.xy || this.el.getXY();
8457     },
8458
8459     /**
8460      * Gets the current box measurements of the component's underlying element.
8461      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8462      * @returns {Object} box An object in the format {x, y, width, height}
8463      */
8464     getBox : function(local){
8465         var s = this.el.getSize();
8466         if(local){
8467             s.x = this.el.getLeft(true);
8468             s.y = this.el.getTop(true);
8469         }else{
8470             var xy = this.xy || this.el.getXY();
8471             s.x = xy[0];
8472             s.y = xy[1];
8473         }
8474         return s;
8475     },
8476
8477     /**
8478      * Sets the current box measurements of the component's underlying element.
8479      * @param {Object} box An object in the format {x, y, width, height}
8480      * @returns {Roo.BoxComponent} this
8481      */
8482     updateBox : function(box){
8483         this.setSize(box.width, box.height);
8484         this.setPagePosition(box.x, box.y);
8485         return this;
8486     },
8487
8488     // protected
8489     getResizeEl : function(){
8490         return this.resizeEl || this.el;
8491     },
8492
8493     // protected
8494     getPositionEl : function(){
8495         return this.positionEl || this.el;
8496     },
8497
8498     /**
8499      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
8500      * This method fires the move event.
8501      * @param {Number} left The new left
8502      * @param {Number} top The new top
8503      * @returns {Roo.BoxComponent} this
8504      */
8505     setPosition : function(x, y){
8506         this.x = x;
8507         this.y = y;
8508         if(!this.boxReady){
8509             return this;
8510         }
8511         var adj = this.adjustPosition(x, y);
8512         var ax = adj.x, ay = adj.y;
8513
8514         var el = this.getPositionEl();
8515         if(ax !== undefined || ay !== undefined){
8516             if(ax !== undefined && ay !== undefined){
8517                 el.setLeftTop(ax, ay);
8518             }else if(ax !== undefined){
8519                 el.setLeft(ax);
8520             }else if(ay !== undefined){
8521                 el.setTop(ay);
8522             }
8523             this.onPosition(ax, ay);
8524             this.fireEvent('move', this, ax, ay);
8525         }
8526         return this;
8527     },
8528
8529     /**
8530      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
8531      * This method fires the move event.
8532      * @param {Number} x The new x position
8533      * @param {Number} y The new y position
8534      * @returns {Roo.BoxComponent} this
8535      */
8536     setPagePosition : function(x, y){
8537         this.pageX = x;
8538         this.pageY = y;
8539         if(!this.boxReady){
8540             return;
8541         }
8542         if(x === undefined || y === undefined){ // cannot translate undefined points
8543             return;
8544         }
8545         var p = this.el.translatePoints(x, y);
8546         this.setPosition(p.left, p.top);
8547         return this;
8548     },
8549
8550     // private
8551     onRender : function(ct, position){
8552         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8553         if(this.resizeEl){
8554             this.resizeEl = Roo.get(this.resizeEl);
8555         }
8556         if(this.positionEl){
8557             this.positionEl = Roo.get(this.positionEl);
8558         }
8559     },
8560
8561     // private
8562     afterRender : function(){
8563         Roo.BoxComponent.superclass.afterRender.call(this);
8564         this.boxReady = true;
8565         this.setSize(this.width, this.height);
8566         if(this.x || this.y){
8567             this.setPosition(this.x, this.y);
8568         }
8569         if(this.pageX || this.pageY){
8570             this.setPagePosition(this.pageX, this.pageY);
8571         }
8572     },
8573
8574     /**
8575      * Force the component's size to recalculate based on the underlying element's current height and width.
8576      * @returns {Roo.BoxComponent} this
8577      */
8578     syncSize : function(){
8579         delete this.lastSize;
8580         this.setSize(this.el.getWidth(), this.el.getHeight());
8581         return this;
8582     },
8583
8584     /**
8585      * Called after the component is resized, this method is empty by default but can be implemented by any
8586      * subclass that needs to perform custom logic after a resize occurs.
8587      * @param {Number} adjWidth The box-adjusted width that was set
8588      * @param {Number} adjHeight The box-adjusted height that was set
8589      * @param {Number} rawWidth The width that was originally specified
8590      * @param {Number} rawHeight The height that was originally specified
8591      */
8592     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8593
8594     },
8595
8596     /**
8597      * Called after the component is moved, this method is empty by default but can be implemented by any
8598      * subclass that needs to perform custom logic after a move occurs.
8599      * @param {Number} x The new x position
8600      * @param {Number} y The new y position
8601      */
8602     onPosition : function(x, y){
8603
8604     },
8605
8606     // private
8607     adjustSize : function(w, h){
8608         if(this.autoWidth){
8609             w = 'auto';
8610         }
8611         if(this.autoHeight){
8612             h = 'auto';
8613         }
8614         return {width : w, height: h};
8615     },
8616
8617     // private
8618     adjustPosition : function(x, y){
8619         return {x : x, y: y};
8620     }
8621 });/*
8622  * Based on:
8623  * Ext JS Library 1.1.1
8624  * Copyright(c) 2006-2007, Ext JS, LLC.
8625  *
8626  * Originally Released Under LGPL - original licence link has changed is not relivant.
8627  *
8628  * Fork - LGPL
8629  * <script type="text/javascript">
8630  */
8631
8632
8633 /**
8634  * @class Roo.SplitBar
8635  * @extends Roo.util.Observable
8636  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8637  * <br><br>
8638  * Usage:
8639  * <pre><code>
8640 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8641                    Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8642 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8643 split.minSize = 100;
8644 split.maxSize = 600;
8645 split.animate = true;
8646 split.on('moved', splitterMoved);
8647 </code></pre>
8648  * @constructor
8649  * Create a new SplitBar
8650  * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
8651  * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
8652  * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8653  * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
8654                         Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8655                         position of the SplitBar).
8656  */
8657 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8658     
8659     /** @private */
8660     this.el = Roo.get(dragElement, true);
8661     this.el.dom.unselectable = "on";
8662     /** @private */
8663     this.resizingEl = Roo.get(resizingElement, true);
8664
8665     /**
8666      * @private
8667      * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8668      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8669      * @type Number
8670      */
8671     this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8672     
8673     /**
8674      * The minimum size of the resizing element. (Defaults to 0)
8675      * @type Number
8676      */
8677     this.minSize = 0;
8678     
8679     /**
8680      * The maximum size of the resizing element. (Defaults to 2000)
8681      * @type Number
8682      */
8683     this.maxSize = 2000;
8684     
8685     /**
8686      * Whether to animate the transition to the new size
8687      * @type Boolean
8688      */
8689     this.animate = false;
8690     
8691     /**
8692      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8693      * @type Boolean
8694      */
8695     this.useShim = false;
8696     
8697     /** @private */
8698     this.shim = null;
8699     
8700     if(!existingProxy){
8701         /** @private */
8702         this.proxy = Roo.SplitBar.createProxy(this.orientation);
8703     }else{
8704         this.proxy = Roo.get(existingProxy).dom;
8705     }
8706     /** @private */
8707     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8708     
8709     /** @private */
8710     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8711     
8712     /** @private */
8713     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8714     
8715     /** @private */
8716     this.dragSpecs = {};
8717     
8718     /**
8719      * @private The adapter to use to positon and resize elements
8720      */
8721     this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8722     this.adapter.init(this);
8723     
8724     if(this.orientation == Roo.SplitBar.HORIZONTAL){
8725         /** @private */
8726         this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8727         this.el.addClass("x-splitbar-h");
8728     }else{
8729         /** @private */
8730         this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8731         this.el.addClass("x-splitbar-v");
8732     }
8733     
8734     this.addEvents({
8735         /**
8736          * @event resize
8737          * Fires when the splitter is moved (alias for {@link #event-moved})
8738          * @param {Roo.SplitBar} this
8739          * @param {Number} newSize the new width or height
8740          */
8741         "resize" : true,
8742         /**
8743          * @event moved
8744          * Fires when the splitter is moved
8745          * @param {Roo.SplitBar} this
8746          * @param {Number} newSize the new width or height
8747          */
8748         "moved" : true,
8749         /**
8750          * @event beforeresize
8751          * Fires before the splitter is dragged
8752          * @param {Roo.SplitBar} this
8753          */
8754         "beforeresize" : true,
8755
8756         "beforeapply" : true
8757     });
8758
8759     Roo.util.Observable.call(this);
8760 };
8761
8762 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8763     onStartProxyDrag : function(x, y){
8764         this.fireEvent("beforeresize", this);
8765         if(!this.overlay){
8766             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
8767             o.unselectable();
8768             o.enableDisplayMode("block");
8769             // all splitbars share the same overlay
8770             Roo.SplitBar.prototype.overlay = o;
8771         }
8772         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8773         this.overlay.show();
8774         Roo.get(this.proxy).setDisplayed("block");
8775         var size = this.adapter.getElementSize(this);
8776         this.activeMinSize = this.getMinimumSize();;
8777         this.activeMaxSize = this.getMaximumSize();;
8778         var c1 = size - this.activeMinSize;
8779         var c2 = Math.max(this.activeMaxSize - size, 0);
8780         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8781             this.dd.resetConstraints();
8782             this.dd.setXConstraint(
8783                 this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
8784                 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8785             );
8786             this.dd.setYConstraint(0, 0);
8787         }else{
8788             this.dd.resetConstraints();
8789             this.dd.setXConstraint(0, 0);
8790             this.dd.setYConstraint(
8791                 this.placement == Roo.SplitBar.TOP ? c1 : c2, 
8792                 this.placement == Roo.SplitBar.TOP ? c2 : c1
8793             );
8794          }
8795         this.dragSpecs.startSize = size;
8796         this.dragSpecs.startPoint = [x, y];
8797         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8798     },
8799     
8800     /** 
8801      * @private Called after the drag operation by the DDProxy
8802      */
8803     onEndProxyDrag : function(e){
8804         Roo.get(this.proxy).setDisplayed(false);
8805         var endPoint = Roo.lib.Event.getXY(e);
8806         if(this.overlay){
8807             this.overlay.hide();
8808         }
8809         var newSize;
8810         if(this.orientation == Roo.SplitBar.HORIZONTAL){
8811             newSize = this.dragSpecs.startSize + 
8812                 (this.placement == Roo.SplitBar.LEFT ?
8813                     endPoint[0] - this.dragSpecs.startPoint[0] :
8814                     this.dragSpecs.startPoint[0] - endPoint[0]
8815                 );
8816         }else{
8817             newSize = this.dragSpecs.startSize + 
8818                 (this.placement == Roo.SplitBar.TOP ?
8819                     endPoint[1] - this.dragSpecs.startPoint[1] :
8820                     this.dragSpecs.startPoint[1] - endPoint[1]
8821                 );
8822         }
8823         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8824         if(newSize != this.dragSpecs.startSize){
8825             if(this.fireEvent('beforeapply', this, newSize) !== false){
8826                 this.adapter.setElementSize(this, newSize);
8827                 this.fireEvent("moved", this, newSize);
8828                 this.fireEvent("resize", this, newSize);
8829             }
8830         }
8831     },
8832     
8833     /**
8834      * Get the adapter this SplitBar uses
8835      * @return The adapter object
8836      */
8837     getAdapter : function(){
8838         return this.adapter;
8839     },
8840     
8841     /**
8842      * Set the adapter this SplitBar uses
8843      * @param {Object} adapter A SplitBar adapter object
8844      */
8845     setAdapter : function(adapter){
8846         this.adapter = adapter;
8847         this.adapter.init(this);
8848     },
8849     
8850     /**
8851      * Gets the minimum size for the resizing element
8852      * @return {Number} The minimum size
8853      */
8854     getMinimumSize : function(){
8855         return this.minSize;
8856     },
8857     
8858     /**
8859      * Sets the minimum size for the resizing element
8860      * @param {Number} minSize The minimum size
8861      */
8862     setMinimumSize : function(minSize){
8863         this.minSize = minSize;
8864     },
8865     
8866     /**
8867      * Gets the maximum size for the resizing element
8868      * @return {Number} The maximum size
8869      */
8870     getMaximumSize : function(){
8871         return this.maxSize;
8872     },
8873     
8874     /**
8875      * Sets the maximum size for the resizing element
8876      * @param {Number} maxSize The maximum size
8877      */
8878     setMaximumSize : function(maxSize){
8879         this.maxSize = maxSize;
8880     },
8881     
8882     /**
8883      * Sets the initialize size for the resizing element
8884      * @param {Number} size The initial size
8885      */
8886     setCurrentSize : function(size){
8887         var oldAnimate = this.animate;
8888         this.animate = false;
8889         this.adapter.setElementSize(this, size);
8890         this.animate = oldAnimate;
8891     },
8892     
8893     /**
8894      * Destroy this splitbar. 
8895      * @param {Boolean} removeEl True to remove the element
8896      */
8897     destroy : function(removeEl){
8898         if(this.shim){
8899             this.shim.remove();
8900         }
8901         this.dd.unreg();
8902         this.proxy.parentNode.removeChild(this.proxy);
8903         if(removeEl){
8904             this.el.remove();
8905         }
8906     }
8907 });
8908
8909 /**
8910  * @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.
8911  */
8912 Roo.SplitBar.createProxy = function(dir){
8913     var proxy = new Roo.Element(document.createElement("div"));
8914     proxy.unselectable();
8915     var cls = 'x-splitbar-proxy';
8916     proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8917     document.body.appendChild(proxy.dom);
8918     return proxy.dom;
8919 };
8920
8921 /** 
8922  * @class Roo.SplitBar.BasicLayoutAdapter
8923  * Default Adapter. It assumes the splitter and resizing element are not positioned
8924  * elements and only gets/sets the width of the element. Generally used for table based layouts.
8925  */
8926 Roo.SplitBar.BasicLayoutAdapter = function(){
8927 };
8928
8929 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8930     // do nothing for now
8931     init : function(s){
8932     
8933     },
8934     /**
8935      * Called before drag operations to get the current size of the resizing element. 
8936      * @param {Roo.SplitBar} s The SplitBar using this adapter
8937      */
8938      getElementSize : function(s){
8939         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8940             return s.resizingEl.getWidth();
8941         }else{
8942             return s.resizingEl.getHeight();
8943         }
8944     },
8945     
8946     /**
8947      * Called after drag operations to set the size of the resizing element.
8948      * @param {Roo.SplitBar} s The SplitBar using this adapter
8949      * @param {Number} newSize The new size to set
8950      * @param {Function} onComplete A function to be invoked when resizing is complete
8951      */
8952     setElementSize : function(s, newSize, onComplete){
8953         if(s.orientation == Roo.SplitBar.HORIZONTAL){
8954             if(!s.animate){
8955                 s.resizingEl.setWidth(newSize);
8956                 if(onComplete){
8957                     onComplete(s, newSize);
8958                 }
8959             }else{
8960                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8961             }
8962         }else{
8963             
8964             if(!s.animate){
8965                 s.resizingEl.setHeight(newSize);
8966                 if(onComplete){
8967                     onComplete(s, newSize);
8968                 }
8969             }else{
8970                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8971             }
8972         }
8973     }
8974 };
8975
8976 /** 
8977  *@class Roo.SplitBar.AbsoluteLayoutAdapter
8978  * @extends Roo.SplitBar.BasicLayoutAdapter
8979  * Adapter that  moves the splitter element to align with the resized sizing element. 
8980  * Used with an absolute positioned SplitBar.
8981  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8982  * document.body, make sure you assign an id to the body element.
8983  */
8984 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8985     this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8986     this.container = Roo.get(container);
8987 };
8988
8989 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8990     init : function(s){
8991         this.basic.init(s);
8992     },
8993     
8994     getElementSize : function(s){
8995         return this.basic.getElementSize(s);
8996     },
8997     
8998     setElementSize : function(s, newSize, onComplete){
8999         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
9000     },
9001     
9002     moveSplitter : function(s){
9003         var yes = Roo.SplitBar;
9004         switch(s.placement){
9005             case yes.LEFT:
9006                 s.el.setX(s.resizingEl.getRight());
9007                 break;
9008             case yes.RIGHT:
9009                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9010                 break;
9011             case yes.TOP:
9012                 s.el.setY(s.resizingEl.getBottom());
9013                 break;
9014             case yes.BOTTOM:
9015                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9016                 break;
9017         }
9018     }
9019 };
9020
9021 /**
9022  * Orientation constant - Create a vertical SplitBar
9023  * @static
9024  * @type Number
9025  */
9026 Roo.SplitBar.VERTICAL = 1;
9027
9028 /**
9029  * Orientation constant - Create a horizontal SplitBar
9030  * @static
9031  * @type Number
9032  */
9033 Roo.SplitBar.HORIZONTAL = 2;
9034
9035 /**
9036  * Placement constant - The resizing element is to the left of the splitter element
9037  * @static
9038  * @type Number
9039  */
9040 Roo.SplitBar.LEFT = 1;
9041
9042 /**
9043  * Placement constant - The resizing element is to the right of the splitter element
9044  * @static
9045  * @type Number
9046  */
9047 Roo.SplitBar.RIGHT = 2;
9048
9049 /**
9050  * Placement constant - The resizing element is positioned above the splitter element
9051  * @static
9052  * @type Number
9053  */
9054 Roo.SplitBar.TOP = 3;
9055
9056 /**
9057  * Placement constant - The resizing element is positioned under splitter element
9058  * @static
9059  * @type Number
9060  */
9061 Roo.SplitBar.BOTTOM = 4;
9062 /*
9063  * Based on:
9064  * Ext JS Library 1.1.1
9065  * Copyright(c) 2006-2007, Ext JS, LLC.
9066  *
9067  * Originally Released Under LGPL - original licence link has changed is not relivant.
9068  *
9069  * Fork - LGPL
9070  * <script type="text/javascript">
9071  */
9072
9073 /**
9074  * @class Roo.View
9075  * @extends Roo.util.Observable
9076  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
9077  * This class also supports single and multi selection modes. <br>
9078  * Create a data model bound view:
9079  <pre><code>
9080  var store = new Roo.data.Store(...);
9081
9082  var view = new Roo.View({
9083     el : "my-element",
9084     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
9085  
9086     singleSelect: true,
9087     selectedClass: "ydataview-selected",
9088     store: store
9089  });
9090
9091  // listen for node click?
9092  view.on("click", function(vw, index, node, e){
9093  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9094  });
9095
9096  // load XML data
9097  dataModel.load("foobar.xml");
9098  </code></pre>
9099  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9100  * <br><br>
9101  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9102  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9103  * 
9104  * Note: old style constructor is still suported (container, template, config)
9105  * 
9106  * @constructor
9107  * Create a new View
9108  * @param {Object} config The config object
9109  * 
9110  */
9111 Roo.View = function(config, depreciated_tpl, depreciated_config){
9112     
9113     if (typeof(depreciated_tpl) == 'undefined') {
9114         // new way.. - universal constructor.
9115         Roo.apply(this, config);
9116         this.el  = Roo.get(this.el);
9117     } else {
9118         // old format..
9119         this.el  = Roo.get(config);
9120         this.tpl = depreciated_tpl;
9121         Roo.apply(this, depreciated_config);
9122     }
9123      
9124     
9125     if(typeof(this.tpl) == "string"){
9126         this.tpl = new Roo.Template(this.tpl);
9127     } else {
9128         // support xtype ctors..
9129         this.tpl = new Roo.factory(this.tpl, Roo);
9130     }
9131     
9132     
9133     this.tpl.compile();
9134    
9135
9136      
9137     /** @private */
9138     this.addEvents({
9139     /**
9140      * @event beforeclick
9141      * Fires before a click is processed. Returns false to cancel the default action.
9142      * @param {Roo.View} this
9143      * @param {Number} index The index of the target node
9144      * @param {HTMLElement} node The target node
9145      * @param {Roo.EventObject} e The raw event object
9146      */
9147         "beforeclick" : true,
9148     /**
9149      * @event click
9150      * Fires when a template node is clicked.
9151      * @param {Roo.View} this
9152      * @param {Number} index The index of the target node
9153      * @param {HTMLElement} node The target node
9154      * @param {Roo.EventObject} e The raw event object
9155      */
9156         "click" : true,
9157     /**
9158      * @event dblclick
9159      * Fires when a template node is double clicked.
9160      * @param {Roo.View} this
9161      * @param {Number} index The index of the target node
9162      * @param {HTMLElement} node The target node
9163      * @param {Roo.EventObject} e The raw event object
9164      */
9165         "dblclick" : true,
9166     /**
9167      * @event contextmenu
9168      * Fires when a template node is right clicked.
9169      * @param {Roo.View} this
9170      * @param {Number} index The index of the target node
9171      * @param {HTMLElement} node The target node
9172      * @param {Roo.EventObject} e The raw event object
9173      */
9174         "contextmenu" : true,
9175     /**
9176      * @event selectionchange
9177      * Fires when the selected nodes change.
9178      * @param {Roo.View} this
9179      * @param {Array} selections Array of the selected nodes
9180      */
9181         "selectionchange" : true,
9182
9183     /**
9184      * @event beforeselect
9185      * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9186      * @param {Roo.View} this
9187      * @param {HTMLElement} node The node to be selected
9188      * @param {Array} selections Array of currently selected nodes
9189      */
9190         "beforeselect" : true
9191     });
9192
9193     this.el.on({
9194         "click": this.onClick,
9195         "dblclick": this.onDblClick,
9196         "contextmenu": this.onContextMenu,
9197         scope:this
9198     });
9199
9200     this.selections = [];
9201     this.nodes = [];
9202     this.cmp = new Roo.CompositeElementLite([]);
9203     if(this.store){
9204         this.store = Roo.factory(this.store, Roo.data);
9205         this.setStore(this.store, true);
9206     }
9207     Roo.View.superclass.constructor.call(this);
9208 };
9209
9210 Roo.extend(Roo.View, Roo.util.Observable, {
9211     
9212      /**
9213      * @cfg {Roo.data.Store} store Data store to load data from.
9214      */
9215     store : false,
9216     
9217     /**
9218      * @cfg {String|Roo.Element} el The container element.
9219      */
9220     el : '',
9221     
9222     /**
9223      * @cfg {String|Roo.Template} tpl The template used by this View 
9224      */
9225     tpl : false,
9226     
9227     /**
9228      * @cfg {String} selectedClass The css class to add to selected nodes
9229      */
9230     selectedClass : "x-view-selected",
9231      /**
9232      * @cfg {String} emptyText The empty text to show when nothing is loaded.
9233      */
9234     emptyText : "",
9235     /**
9236      * @cfg {Boolean} multiSelect Allow multiple selection
9237      */
9238     
9239     multiSelect : false,
9240     /**
9241      * @cfg {Boolean} singleSelect Allow single selection
9242      */
9243     singleSelect:  false,
9244     
9245     /**
9246      * Returns the element this view is bound to.
9247      * @return {Roo.Element}
9248      */
9249     getEl : function(){
9250         return this.el;
9251     },
9252
9253     /**
9254      * Refreshes the view.
9255      */
9256     refresh : function(){
9257         var t = this.tpl;
9258         this.clearSelections();
9259         this.el.update("");
9260         var html = [];
9261         var records = this.store.getRange();
9262         if(records.length < 1){
9263             this.el.update(this.emptyText);
9264             return;
9265         }
9266         for(var i = 0, len = records.length; i < len; i++){
9267             var data = this.prepareData(records[i].data, i, records[i]);
9268             html[html.length] = t.apply(data);
9269         }
9270         this.el.update(html.join(""));
9271         this.nodes = this.el.dom.childNodes;
9272         this.updateIndexes(0);
9273     },
9274
9275     /**
9276      * Function to override to reformat the data that is sent to
9277      * the template for each node.
9278      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9279      * a JSON object for an UpdateManager bound view).
9280      */
9281     prepareData : function(data){
9282         return data;
9283     },
9284
9285     onUpdate : function(ds, record){
9286         this.clearSelections();
9287         var index = this.store.indexOf(record);
9288         var n = this.nodes[index];
9289         this.tpl.insertBefore(n, this.prepareData(record.data));
9290         n.parentNode.removeChild(n);
9291         this.updateIndexes(index, index);
9292     },
9293
9294     onAdd : function(ds, records, index){
9295         this.clearSelections();
9296         if(this.nodes.length == 0){
9297             this.refresh();
9298             return;
9299         }
9300         var n = this.nodes[index];
9301         for(var i = 0, len = records.length; i < len; i++){
9302             var d = this.prepareData(records[i].data);
9303             if(n){
9304                 this.tpl.insertBefore(n, d);
9305             }else{
9306                 this.tpl.append(this.el, d);
9307             }
9308         }
9309         this.updateIndexes(index);
9310     },
9311
9312     onRemove : function(ds, record, index){
9313         this.clearSelections();
9314         this.el.dom.removeChild(this.nodes[index]);
9315         this.updateIndexes(index);
9316     },
9317
9318     /**
9319      * Refresh an individual node.
9320      * @param {Number} index
9321      */
9322     refreshNode : function(index){
9323         this.onUpdate(this.store, this.store.getAt(index));
9324     },
9325
9326     updateIndexes : function(startIndex, endIndex){
9327         var ns = this.nodes;
9328         startIndex = startIndex || 0;
9329         endIndex = endIndex || ns.length - 1;
9330         for(var i = startIndex; i <= endIndex; i++){
9331             ns[i].nodeIndex = i;
9332         }
9333     },
9334
9335     /**
9336      * Changes the data store this view uses and refresh the view.
9337      * @param {Store} store
9338      */
9339     setStore : function(store, initial){
9340         if(!initial && this.store){
9341             this.store.un("datachanged", this.refresh);
9342             this.store.un("add", this.onAdd);
9343             this.store.un("remove", this.onRemove);
9344             this.store.un("update", this.onUpdate);
9345             this.store.un("clear", this.refresh);
9346         }
9347         if(store){
9348           
9349             store.on("datachanged", this.refresh, this);
9350             store.on("add", this.onAdd, this);
9351             store.on("remove", this.onRemove, this);
9352             store.on("update", this.onUpdate, this);
9353             store.on("clear", this.refresh, this);
9354         }
9355         
9356         if(store){
9357             this.refresh();
9358         }
9359     },
9360
9361     /**
9362      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9363      * @param {HTMLElement} node
9364      * @return {HTMLElement} The template node
9365      */
9366     findItemFromChild : function(node){
9367         var el = this.el.dom;
9368         if(!node || node.parentNode == el){
9369                     return node;
9370             }
9371             var p = node.parentNode;
9372             while(p && p != el){
9373             if(p.parentNode == el){
9374                 return p;
9375             }
9376             p = p.parentNode;
9377         }
9378             return null;
9379     },
9380
9381     /** @ignore */
9382     onClick : function(e){
9383         var item = this.findItemFromChild(e.getTarget());
9384         if(item){
9385             var index = this.indexOf(item);
9386             if(this.onItemClick(item, index, e) !== false){
9387                 this.fireEvent("click", this, index, item, e);
9388             }
9389         }else{
9390             this.clearSelections();
9391         }
9392     },
9393
9394     /** @ignore */
9395     onContextMenu : function(e){
9396         var item = this.findItemFromChild(e.getTarget());
9397         if(item){
9398             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9399         }
9400     },
9401
9402     /** @ignore */
9403     onDblClick : function(e){
9404         var item = this.findItemFromChild(e.getTarget());
9405         if(item){
9406             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9407         }
9408     },
9409
9410     onItemClick : function(item, index, e){
9411         if(this.fireEvent("beforeclick", this, index, item, e) === false){
9412             return false;
9413         }
9414         if(this.multiSelect || this.singleSelect){
9415             if(this.multiSelect && e.shiftKey && this.lastSelection){
9416                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9417             }else{
9418                 this.select(item, this.multiSelect && e.ctrlKey);
9419                 this.lastSelection = item;
9420             }
9421             e.preventDefault();
9422         }
9423         return true;
9424     },
9425
9426     /**
9427      * Get the number of selected nodes.
9428      * @return {Number}
9429      */
9430     getSelectionCount : function(){
9431         return this.selections.length;
9432     },
9433
9434     /**
9435      * Get the currently selected nodes.
9436      * @return {Array} An array of HTMLElements
9437      */
9438     getSelectedNodes : function(){
9439         return this.selections;
9440     },
9441
9442     /**
9443      * Get the indexes of the selected nodes.
9444      * @return {Array}
9445      */
9446     getSelectedIndexes : function(){
9447         var indexes = [], s = this.selections;
9448         for(var i = 0, len = s.length; i < len; i++){
9449             indexes.push(s[i].nodeIndex);
9450         }
9451         return indexes;
9452     },
9453
9454     /**
9455      * Clear all selections
9456      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9457      */
9458     clearSelections : function(suppressEvent){
9459         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9460             this.cmp.elements = this.selections;
9461             this.cmp.removeClass(this.selectedClass);
9462             this.selections = [];
9463             if(!suppressEvent){
9464                 this.fireEvent("selectionchange", this, this.selections);
9465             }
9466         }
9467     },
9468
9469     /**
9470      * Returns true if the passed node is selected
9471      * @param {HTMLElement/Number} node The node or node index
9472      * @return {Boolean}
9473      */
9474     isSelected : function(node){
9475         var s = this.selections;
9476         if(s.length < 1){
9477             return false;
9478         }
9479         node = this.getNode(node);
9480         return s.indexOf(node) !== -1;
9481     },
9482
9483     /**
9484      * Selects nodes.
9485      * @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
9486      * @param {Boolean} keepExisting (optional) true to keep existing selections
9487      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9488      */
9489     select : function(nodeInfo, keepExisting, suppressEvent){
9490         if(nodeInfo instanceof Array){
9491             if(!keepExisting){
9492                 this.clearSelections(true);
9493             }
9494             for(var i = 0, len = nodeInfo.length; i < len; i++){
9495                 this.select(nodeInfo[i], true, true);
9496             }
9497         } else{
9498             var node = this.getNode(nodeInfo);
9499             if(node && !this.isSelected(node)){
9500                 if(!keepExisting){
9501                     this.clearSelections(true);
9502                 }
9503                 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9504                     Roo.fly(node).addClass(this.selectedClass);
9505                     this.selections.push(node);
9506                     if(!suppressEvent){
9507                         this.fireEvent("selectionchange", this, this.selections);
9508                     }
9509                 }
9510             }
9511         }
9512     },
9513
9514     /**
9515      * Gets a template node.
9516      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9517      * @return {HTMLElement} The node or null if it wasn't found
9518      */
9519     getNode : function(nodeInfo){
9520         if(typeof nodeInfo == "string"){
9521             return document.getElementById(nodeInfo);
9522         }else if(typeof nodeInfo == "number"){
9523             return this.nodes[nodeInfo];
9524         }
9525         return nodeInfo;
9526     },
9527
9528     /**
9529      * Gets a range template nodes.
9530      * @param {Number} startIndex
9531      * @param {Number} endIndex
9532      * @return {Array} An array of nodes
9533      */
9534     getNodes : function(start, end){
9535         var ns = this.nodes;
9536         start = start || 0;
9537         end = typeof end == "undefined" ? ns.length - 1 : end;
9538         var nodes = [];
9539         if(start <= end){
9540             for(var i = start; i <= end; i++){
9541                 nodes.push(ns[i]);
9542             }
9543         } else{
9544             for(var i = start; i >= end; i--){
9545                 nodes.push(ns[i]);
9546             }
9547         }
9548         return nodes;
9549     },
9550
9551     /**
9552      * Finds the index of the passed node
9553      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9554      * @return {Number} The index of the node or -1
9555      */
9556     indexOf : function(node){
9557         node = this.getNode(node);
9558         if(typeof node.nodeIndex == "number"){
9559             return node.nodeIndex;
9560         }
9561         var ns = this.nodes;
9562         for(var i = 0, len = ns.length; i < len; i++){
9563             if(ns[i] == node){
9564                 return i;
9565             }
9566         }
9567         return -1;
9568     }
9569 });
9570 /*
9571  * Based on:
9572  * Ext JS Library 1.1.1
9573  * Copyright(c) 2006-2007, Ext JS, LLC.
9574  *
9575  * Originally Released Under LGPL - original licence link has changed is not relivant.
9576  *
9577  * Fork - LGPL
9578  * <script type="text/javascript">
9579  */
9580
9581 /**
9582  * @class Roo.JsonView
9583  * @extends Roo.View
9584  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9585 <pre><code>
9586 var view = new Roo.JsonView({
9587     container: "my-element",
9588     tpl: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
9589     multiSelect: true, 
9590     jsonRoot: "data" 
9591 });
9592
9593 // listen for node click?
9594 view.on("click", function(vw, index, node, e){
9595     alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9596 });
9597
9598 // direct load of JSON data
9599 view.load("foobar.php");
9600
9601 // Example from my blog list
9602 var tpl = new Roo.Template(
9603     '&lt;div class="entry"&gt;' +
9604     '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
9605     "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
9606     "&lt;/div&gt;&lt;hr /&gt;"
9607 );
9608
9609 var moreView = new Roo.JsonView({
9610     container :  "entry-list", 
9611     template : tpl,
9612     jsonRoot: "posts"
9613 });
9614 moreView.on("beforerender", this.sortEntries, this);
9615 moreView.load({
9616     url: "/blog/get-posts.php",
9617     params: "allposts=true",
9618     text: "Loading Blog Entries..."
9619 });
9620 </code></pre>
9621
9622 * Note: old code is supported with arguments : (container, template, config)
9623
9624
9625  * @constructor
9626  * Create a new JsonView
9627  * 
9628  * @param {Object} config The config object
9629  * 
9630  */
9631 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9632     
9633     
9634     Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9635
9636     var um = this.el.getUpdateManager();
9637     um.setRenderer(this);
9638     um.on("update", this.onLoad, this);
9639     um.on("failure", this.onLoadException, this);
9640
9641     /**
9642      * @event beforerender
9643      * Fires before rendering of the downloaded JSON data.
9644      * @param {Roo.JsonView} this
9645      * @param {Object} data The JSON data loaded
9646      */
9647     /**
9648      * @event load
9649      * Fires when data is loaded.
9650      * @param {Roo.JsonView} this
9651      * @param {Object} data The JSON data loaded
9652      * @param {Object} response The raw Connect response object
9653      */
9654     /**
9655      * @event loadexception
9656      * Fires when loading fails.
9657      * @param {Roo.JsonView} this
9658      * @param {Object} response The raw Connect response object
9659      */
9660     this.addEvents({
9661         'beforerender' : true,
9662         'load' : true,
9663         'loadexception' : true
9664     });
9665 };
9666 Roo.extend(Roo.JsonView, Roo.View, {
9667     /**
9668      * @type {String} The root property in the loaded JSON object that contains the data
9669      */
9670     jsonRoot : "",
9671
9672     /**
9673      * Refreshes the view.
9674      */
9675     refresh : function(){
9676         this.clearSelections();
9677         this.el.update("");
9678         var html = [];
9679         var o = this.jsonData;
9680         if(o && o.length > 0){
9681             for(var i = 0, len = o.length; i < len; i++){
9682                 var data = this.prepareData(o[i], i, o);
9683                 html[html.length] = this.tpl.apply(data);
9684             }
9685         }else{
9686             html.push(this.emptyText);
9687         }
9688         this.el.update(html.join(""));
9689         this.nodes = this.el.dom.childNodes;
9690         this.updateIndexes(0);
9691     },
9692
9693     /**
9694      * 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.
9695      * @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:
9696      <pre><code>
9697      view.load({
9698          url: "your-url.php",
9699          params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9700          callback: yourFunction,
9701          scope: yourObject, //(optional scope)
9702          discardUrl: false,
9703          nocache: false,
9704          text: "Loading...",
9705          timeout: 30,
9706          scripts: false
9707      });
9708      </code></pre>
9709      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9710      * 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.
9711      * @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}
9712      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9713      * @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.
9714      */
9715     load : function(){
9716         var um = this.el.getUpdateManager();
9717         um.update.apply(um, arguments);
9718     },
9719
9720     render : function(el, response){
9721         this.clearSelections();
9722         this.el.update("");
9723         var o;
9724         try{
9725             o = Roo.util.JSON.decode(response.responseText);
9726             if(this.jsonRoot){
9727                 
9728                 o = o[this.jsonRoot];
9729             }
9730         } catch(e){
9731         }
9732         /**
9733          * The current JSON data or null
9734          */
9735         this.jsonData = o;
9736         this.beforeRender();
9737         this.refresh();
9738     },
9739
9740 /**
9741  * Get the number of records in the current JSON dataset
9742  * @return {Number}
9743  */
9744     getCount : function(){
9745         return this.jsonData ? this.jsonData.length : 0;
9746     },
9747
9748 /**
9749  * Returns the JSON object for the specified node(s)
9750  * @param {HTMLElement/Array} node The node or an array of nodes
9751  * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9752  * you get the JSON object for the node
9753  */
9754     getNodeData : function(node){
9755         if(node instanceof Array){
9756             var data = [];
9757             for(var i = 0, len = node.length; i < len; i++){
9758                 data.push(this.getNodeData(node[i]));
9759             }
9760             return data;
9761         }
9762         return this.jsonData[this.indexOf(node)] || null;
9763     },
9764
9765     beforeRender : function(){
9766         this.snapshot = this.jsonData;
9767         if(this.sortInfo){
9768             this.sort.apply(this, this.sortInfo);
9769         }
9770         this.fireEvent("beforerender", this, this.jsonData);
9771     },
9772
9773     onLoad : function(el, o){
9774         this.fireEvent("load", this, this.jsonData, o);
9775     },
9776
9777     onLoadException : function(el, o){
9778         this.fireEvent("loadexception", this, o);
9779     },
9780
9781 /**
9782  * Filter the data by a specific property.
9783  * @param {String} property A property on your JSON objects
9784  * @param {String/RegExp} value Either string that the property values
9785  * should start with, or a RegExp to test against the property
9786  */
9787     filter : function(property, value){
9788         if(this.jsonData){
9789             var data = [];
9790             var ss = this.snapshot;
9791             if(typeof value == "string"){
9792                 var vlen = value.length;
9793                 if(vlen == 0){
9794                     this.clearFilter();
9795                     return;
9796                 }
9797                 value = value.toLowerCase();
9798                 for(var i = 0, len = ss.length; i < len; i++){
9799                     var o = ss[i];
9800                     if(o[property].substr(0, vlen).toLowerCase() == value){
9801                         data.push(o);
9802                     }
9803                 }
9804             } else if(value.exec){ // regex?
9805                 for(var i = 0, len = ss.length; i < len; i++){
9806                     var o = ss[i];
9807                     if(value.test(o[property])){
9808                         data.push(o);
9809                     }
9810                 }
9811             } else{
9812                 return;
9813             }
9814             this.jsonData = data;
9815             this.refresh();
9816         }
9817     },
9818
9819 /**
9820  * Filter by a function. The passed function will be called with each
9821  * object in the current dataset. If the function returns true the value is kept,
9822  * otherwise it is filtered.
9823  * @param {Function} fn
9824  * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9825  */
9826     filterBy : function(fn, scope){
9827         if(this.jsonData){
9828             var data = [];
9829             var ss = this.snapshot;
9830             for(var i = 0, len = ss.length; i < len; i++){
9831                 var o = ss[i];
9832                 if(fn.call(scope || this, o)){
9833                     data.push(o);
9834                 }
9835             }
9836             this.jsonData = data;
9837             this.refresh();
9838         }
9839     },
9840
9841 /**
9842  * Clears the current filter.
9843  */
9844     clearFilter : function(){
9845         if(this.snapshot && this.jsonData != this.snapshot){
9846             this.jsonData = this.snapshot;
9847             this.refresh();
9848         }
9849     },
9850
9851
9852 /**
9853  * Sorts the data for this view and refreshes it.
9854  * @param {String} property A property on your JSON objects to sort on
9855  * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9856  * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9857  */
9858     sort : function(property, dir, sortType){
9859         this.sortInfo = Array.prototype.slice.call(arguments, 0);
9860         if(this.jsonData){
9861             var p = property;
9862             var dsc = dir && dir.toLowerCase() == "desc";
9863             var f = function(o1, o2){
9864                 var v1 = sortType ? sortType(o1[p]) : o1[p];
9865                 var v2 = sortType ? sortType(o2[p]) : o2[p];
9866                 ;
9867                 if(v1 < v2){
9868                     return dsc ? +1 : -1;
9869                 } else if(v1 > v2){
9870                     return dsc ? -1 : +1;
9871                 } else{
9872                     return 0;
9873                 }
9874             };
9875             this.jsonData.sort(f);
9876             this.refresh();
9877             if(this.jsonData != this.snapshot){
9878                 this.snapshot.sort(f);
9879             }
9880         }
9881     }
9882 });/*
9883  * Based on:
9884  * Ext JS Library 1.1.1
9885  * Copyright(c) 2006-2007, Ext JS, LLC.
9886  *
9887  * Originally Released Under LGPL - original licence link has changed is not relivant.
9888  *
9889  * Fork - LGPL
9890  * <script type="text/javascript">
9891  */
9892  
9893
9894 /**
9895  * @class Roo.ColorPalette
9896  * @extends Roo.Component
9897  * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
9898  * Here's an example of typical usage:
9899  * <pre><code>
9900 var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
9901 cp.render('my-div');
9902
9903 cp.on('select', function(palette, selColor){
9904     // do something with selColor
9905 });
9906 </code></pre>
9907  * @constructor
9908  * Create a new ColorPalette
9909  * @param {Object} config The config object
9910  */
9911 Roo.ColorPalette = function(config){
9912     Roo.ColorPalette.superclass.constructor.call(this, config);
9913     this.addEvents({
9914         /**
9915              * @event select
9916              * Fires when a color is selected
9917              * @param {ColorPalette} this
9918              * @param {String} color The 6-digit color hex code (without the # symbol)
9919              */
9920         select: true
9921     });
9922
9923     if(this.handler){
9924         this.on("select", this.handler, this.scope, true);
9925     }
9926 };
9927 Roo.extend(Roo.ColorPalette, Roo.Component, {
9928     /**
9929      * @cfg {String} itemCls
9930      * The CSS class to apply to the containing element (defaults to "x-color-palette")
9931      */
9932     itemCls : "x-color-palette",
9933     /**
9934      * @cfg {String} value
9935      * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
9936      * the hex codes are case-sensitive.
9937      */
9938     value : null,
9939     clickEvent:'click',
9940     // private
9941     ctype: "Roo.ColorPalette",
9942
9943     /**
9944      * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9945      */
9946     allowReselect : false,
9947
9948     /**
9949      * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
9950      * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
9951      * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9952      * of colors with the width setting until the box is symmetrical.</p>
9953      * <p>You can override individual colors if needed:</p>
9954      * <pre><code>
9955 var cp = new Roo.ColorPalette();
9956 cp.colors[0] = "FF0000";  // change the first box to red
9957 </code></pre>
9958
9959 Or you can provide a custom array of your own for complete control:
9960 <pre><code>
9961 var cp = new Roo.ColorPalette();
9962 cp.colors = ["000000", "993300", "333300"];
9963 </code></pre>
9964      * @type Array
9965      */
9966     colors : [
9967         "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9968         "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9969         "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9970         "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9971         "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9972     ],
9973
9974     // private
9975     onRender : function(container, position){
9976         var t = new Roo.MasterTemplate(
9977             '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
9978         );
9979         var c = this.colors;
9980         for(var i = 0, len = c.length; i < len; i++){
9981             t.add([c[i]]);
9982         }
9983         var el = document.createElement("div");
9984         el.className = this.itemCls;
9985         t.overwrite(el);
9986         container.dom.insertBefore(el, position);
9987         this.el = Roo.get(el);
9988         this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
9989         if(this.clickEvent != 'click'){
9990             this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
9991         }
9992     },
9993
9994     // private
9995     afterRender : function(){
9996         Roo.ColorPalette.superclass.afterRender.call(this);
9997         if(this.value){
9998             var s = this.value;
9999             this.value = null;
10000             this.select(s);
10001         }
10002     },
10003
10004     // private
10005     handleClick : function(e, t){
10006         e.preventDefault();
10007         if(!this.disabled){
10008             var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10009             this.select(c.toUpperCase());
10010         }
10011     },
10012
10013     /**
10014      * Selects the specified color in the palette (fires the select event)
10015      * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10016      */
10017     select : function(color){
10018         color = color.replace("#", "");
10019         if(color != this.value || this.allowReselect){
10020             var el = this.el;
10021             if(this.value){
10022                 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10023             }
10024             el.child("a.color-"+color).addClass("x-color-palette-sel");
10025             this.value = color;
10026             this.fireEvent("select", this, color);
10027         }
10028     }
10029 });/*
10030  * Based on:
10031  * Ext JS Library 1.1.1
10032  * Copyright(c) 2006-2007, Ext JS, LLC.
10033  *
10034  * Originally Released Under LGPL - original licence link has changed is not relivant.
10035  *
10036  * Fork - LGPL
10037  * <script type="text/javascript">
10038  */
10039  
10040 /**
10041  * @class Roo.DatePicker
10042  * @extends Roo.Component
10043  * Simple date picker class.
10044  * @constructor
10045  * Create a new DatePicker
10046  * @param {Object} config The config object
10047  */
10048 Roo.DatePicker = function(config){
10049     Roo.DatePicker.superclass.constructor.call(this, config);
10050
10051     this.value = config && config.value ?
10052                  config.value.clearTime() : new Date().clearTime();
10053
10054     this.addEvents({
10055         /**
10056              * @event select
10057              * Fires when a date is selected
10058              * @param {DatePicker} this
10059              * @param {Date} date The selected date
10060              */
10061         select: true
10062     });
10063
10064     if(this.handler){
10065         this.on("select", this.handler,  this.scope || this);
10066     }
10067     // build the disabledDatesRE
10068     if(!this.disabledDatesRE && this.disabledDates){
10069         var dd = this.disabledDates;
10070         var re = "(?:";
10071         for(var i = 0; i < dd.length; i++){
10072             re += dd[i];
10073             if(i != dd.length-1) re += "|";
10074         }
10075         this.disabledDatesRE = new RegExp(re + ")");
10076     }
10077 };
10078
10079 Roo.extend(Roo.DatePicker, Roo.Component, {
10080     /**
10081      * @cfg {String} todayText
10082      * The text to display on the button that selects the current date (defaults to "Today")
10083      */
10084     todayText : "Today",
10085     /**
10086      * @cfg {String} okText
10087      * The text to display on the ok button
10088      */
10089     okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
10090     /**
10091      * @cfg {String} cancelText
10092      * The text to display on the cancel button
10093      */
10094     cancelText : "Cancel",
10095     /**
10096      * @cfg {String} todayTip
10097      * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10098      */
10099     todayTip : "{0} (Spacebar)",
10100     /**
10101      * @cfg {Date} minDate
10102      * Minimum allowable date (JavaScript date object, defaults to null)
10103      */
10104     minDate : null,
10105     /**
10106      * @cfg {Date} maxDate
10107      * Maximum allowable date (JavaScript date object, defaults to null)
10108      */
10109     maxDate : null,
10110     /**
10111      * @cfg {String} minText
10112      * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10113      */
10114     minText : "This date is before the minimum date",
10115     /**
10116      * @cfg {String} maxText
10117      * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10118      */
10119     maxText : "This date is after the maximum date",
10120     /**
10121      * @cfg {String} format
10122      * The default date format string which can be overriden for localization support.  The format must be
10123      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10124      */
10125     format : "m/d/y",
10126     /**
10127      * @cfg {Array} disabledDays
10128      * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10129      */
10130     disabledDays : null,
10131     /**
10132      * @cfg {String} disabledDaysText
10133      * The tooltip to display when the date falls on a disabled day (defaults to "")
10134      */
10135     disabledDaysText : "",
10136     /**
10137      * @cfg {RegExp} disabledDatesRE
10138      * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10139      */
10140     disabledDatesRE : null,
10141     /**
10142      * @cfg {String} disabledDatesText
10143      * The tooltip text to display when the date falls on a disabled date (defaults to "")
10144      */
10145     disabledDatesText : "",
10146     /**
10147      * @cfg {Boolean} constrainToViewport
10148      * True to constrain the date picker to the viewport (defaults to true)
10149      */
10150     constrainToViewport : true,
10151     /**
10152      * @cfg {Array} monthNames
10153      * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10154      */
10155     monthNames : Date.monthNames,
10156     /**
10157      * @cfg {Array} dayNames
10158      * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10159      */
10160     dayNames : Date.dayNames,
10161     /**
10162      * @cfg {String} nextText
10163      * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10164      */
10165     nextText: 'Next Month (Control+Right)',
10166     /**
10167      * @cfg {String} prevText
10168      * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10169      */
10170     prevText: 'Previous Month (Control+Left)',
10171     /**
10172      * @cfg {String} monthYearText
10173      * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10174      */
10175     monthYearText: 'Choose a month (Control+Up/Down to move years)',
10176     /**
10177      * @cfg {Number} startDay
10178      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10179      */
10180     startDay : 0,
10181     /**
10182      * @cfg {Bool} showClear
10183      * Show a clear button (usefull for date form elements that can be blank.)
10184      */
10185     
10186     showClear: false,
10187     
10188     /**
10189      * Sets the value of the date field
10190      * @param {Date} value The date to set
10191      */
10192     setValue : function(value){
10193         var old = this.value;
10194         this.value = value.clearTime(true);
10195         if(this.el){
10196             this.update(this.value);
10197         }
10198     },
10199
10200     /**
10201      * Gets the current selected value of the date field
10202      * @return {Date} The selected date
10203      */
10204     getValue : function(){
10205         return this.value;
10206     },
10207
10208     // private
10209     focus : function(){
10210         if(this.el){
10211             this.update(this.activeDate);
10212         }
10213     },
10214
10215     // private
10216     onRender : function(container, position){
10217         var m = [
10218              '<table cellspacing="0">',
10219                 '<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>',
10220                 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10221         var dn = this.dayNames;
10222         for(var i = 0; i < 7; i++){
10223             var d = this.startDay+i;
10224             if(d > 6){
10225                 d = d-7;
10226             }
10227             m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10228         }
10229         m[m.length] = "</tr></thead><tbody><tr>";
10230         for(var i = 0; i < 42; i++) {
10231             if(i % 7 == 0 && i != 0){
10232                 m[m.length] = "</tr><tr>";
10233             }
10234             m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10235         }
10236         m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10237             '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10238
10239         var el = document.createElement("div");
10240         el.className = "x-date-picker";
10241         el.innerHTML = m.join("");
10242
10243         container.dom.insertBefore(el, position);
10244
10245         this.el = Roo.get(el);
10246         this.eventEl = Roo.get(el.firstChild);
10247
10248         new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10249             handler: this.showPrevMonth,
10250             scope: this,
10251             preventDefault:true,
10252             stopDefault:true
10253         });
10254
10255         new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10256             handler: this.showNextMonth,
10257             scope: this,
10258             preventDefault:true,
10259             stopDefault:true
10260         });
10261
10262         this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
10263
10264         this.monthPicker = this.el.down('div.x-date-mp');
10265         this.monthPicker.enableDisplayMode('block');
10266         
10267         var kn = new Roo.KeyNav(this.eventEl, {
10268             "left" : function(e){
10269                 e.ctrlKey ?
10270                     this.showPrevMonth() :
10271                     this.update(this.activeDate.add("d", -1));
10272             },
10273
10274             "right" : function(e){
10275                 e.ctrlKey ?
10276                     this.showNextMonth() :
10277                     this.update(this.activeDate.add("d", 1));
10278             },
10279
10280             "up" : function(e){
10281                 e.ctrlKey ?
10282                     this.showNextYear() :
10283                     this.update(this.activeDate.add("d", -7));
10284             },
10285
10286             "down" : function(e){
10287                 e.ctrlKey ?
10288                     this.showPrevYear() :
10289                     this.update(this.activeDate.add("d", 7));
10290             },
10291
10292             "pageUp" : function(e){
10293                 this.showNextMonth();
10294             },
10295
10296             "pageDown" : function(e){
10297                 this.showPrevMonth();
10298             },
10299
10300             "enter" : function(e){
10301                 e.stopPropagation();
10302                 return true;
10303             },
10304
10305             scope : this
10306         });
10307
10308         this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
10309
10310         this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
10311
10312         this.el.unselectable();
10313         
10314         this.cells = this.el.select("table.x-date-inner tbody td");
10315         this.textNodes = this.el.query("table.x-date-inner tbody span");
10316
10317         this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10318             text: "&#160;",
10319             tooltip: this.monthYearText
10320         });
10321
10322         this.mbtn.on('click', this.showMonthPicker, this);
10323         this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10324
10325
10326         var today = (new Date()).dateFormat(this.format);
10327         
10328         var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10329         if (this.showClear) {
10330             baseTb.add( new Roo.Toolbar.Fill());
10331         }
10332         baseTb.add({
10333             text: String.format(this.todayText, today),
10334             tooltip: String.format(this.todayTip, today),
10335             handler: this.selectToday,
10336             scope: this
10337         });
10338         
10339         //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10340             
10341         //});
10342         if (this.showClear) {
10343             
10344             baseTb.add( new Roo.Toolbar.Fill());
10345             baseTb.add({
10346                 text: '&#160;',
10347                 cls: 'x-btn-icon x-btn-clear',
10348                 handler: function() {
10349                     //this.value = '';
10350                     this.fireEvent("select", this, '');
10351                 },
10352                 scope: this
10353             });
10354         }
10355         
10356         
10357         if(Roo.isIE){
10358             this.el.repaint();
10359         }
10360         this.update(this.value);
10361     },
10362
10363     createMonthPicker : function(){
10364         if(!this.monthPicker.dom.firstChild){
10365             var buf = ['<table border="0" cellspacing="0">'];
10366             for(var i = 0; i < 6; i++){
10367                 buf.push(
10368                     '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10369                     '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10370                     i == 0 ?
10371                     '<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>' :
10372                     '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10373                 );
10374             }
10375             buf.push(
10376                 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10377                     this.okText,
10378                     '</button><button type="button" class="x-date-mp-cancel">',
10379                     this.cancelText,
10380                     '</button></td></tr>',
10381                 '</table>'
10382             );
10383             this.monthPicker.update(buf.join(''));
10384             this.monthPicker.on('click', this.onMonthClick, this);
10385             this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10386
10387             this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10388             this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10389
10390             this.mpMonths.each(function(m, a, i){
10391                 i += 1;
10392                 if((i%2) == 0){
10393                     m.dom.xmonth = 5 + Math.round(i * .5);
10394                 }else{
10395                     m.dom.xmonth = Math.round((i-1) * .5);
10396                 }
10397             });
10398         }
10399     },
10400
10401     showMonthPicker : function(){
10402         this.createMonthPicker();
10403         var size = this.el.getSize();
10404         this.monthPicker.setSize(size);
10405         this.monthPicker.child('table').setSize(size);
10406
10407         this.mpSelMonth = (this.activeDate || this.value).getMonth();
10408         this.updateMPMonth(this.mpSelMonth);
10409         this.mpSelYear = (this.activeDate || this.value).getFullYear();
10410         this.updateMPYear(this.mpSelYear);
10411
10412         this.monthPicker.slideIn('t', {duration:.2});
10413     },
10414
10415     updateMPYear : function(y){
10416         this.mpyear = y;
10417         var ys = this.mpYears.elements;
10418         for(var i = 1; i <= 10; i++){
10419             var td = ys[i-1], y2;
10420             if((i%2) == 0){
10421                 y2 = y + Math.round(i * .5);
10422                 td.firstChild.innerHTML = y2;
10423                 td.xyear = y2;
10424             }else{
10425                 y2 = y - (5-Math.round(i * .5));
10426                 td.firstChild.innerHTML = y2;
10427                 td.xyear = y2;
10428             }
10429             this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10430         }
10431     },
10432
10433     updateMPMonth : function(sm){
10434         this.mpMonths.each(function(m, a, i){
10435             m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10436         });
10437     },
10438
10439     selectMPMonth: function(m){
10440         
10441     },
10442
10443     onMonthClick : function(e, t){
10444         e.stopEvent();
10445         var el = new Roo.Element(t), pn;
10446         if(el.is('button.x-date-mp-cancel')){
10447             this.hideMonthPicker();
10448         }
10449         else if(el.is('button.x-date-mp-ok')){
10450             this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10451             this.hideMonthPicker();
10452         }
10453         else if(pn = el.up('td.x-date-mp-month', 2)){
10454             this.mpMonths.removeClass('x-date-mp-sel');
10455             pn.addClass('x-date-mp-sel');
10456             this.mpSelMonth = pn.dom.xmonth;
10457         }
10458         else if(pn = el.up('td.x-date-mp-year', 2)){
10459             this.mpYears.removeClass('x-date-mp-sel');
10460             pn.addClass('x-date-mp-sel');
10461             this.mpSelYear = pn.dom.xyear;
10462         }
10463         else if(el.is('a.x-date-mp-prev')){
10464             this.updateMPYear(this.mpyear-10);
10465         }
10466         else if(el.is('a.x-date-mp-next')){
10467             this.updateMPYear(this.mpyear+10);
10468         }
10469     },
10470
10471     onMonthDblClick : function(e, t){
10472         e.stopEvent();
10473         var el = new Roo.Element(t), pn;
10474         if(pn = el.up('td.x-date-mp-month', 2)){
10475             this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10476             this.hideMonthPicker();
10477         }
10478         else if(pn = el.up('td.x-date-mp-year', 2)){
10479             this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10480             this.hideMonthPicker();
10481         }
10482     },
10483
10484     hideMonthPicker : function(disableAnim){
10485         if(this.monthPicker){
10486             if(disableAnim === true){
10487                 this.monthPicker.hide();
10488             }else{
10489                 this.monthPicker.slideOut('t', {duration:.2});
10490             }
10491         }
10492     },
10493
10494     // private
10495     showPrevMonth : function(e){
10496         this.update(this.activeDate.add("mo", -1));
10497     },
10498
10499     // private
10500     showNextMonth : function(e){
10501         this.update(this.activeDate.add("mo", 1));
10502     },
10503
10504     // private
10505     showPrevYear : function(){
10506         this.update(this.activeDate.add("y", -1));
10507     },
10508
10509     // private
10510     showNextYear : function(){
10511         this.update(this.activeDate.add("y", 1));
10512     },
10513
10514     // private
10515     handleMouseWheel : function(e){
10516         var delta = e.getWheelDelta();
10517         if(delta > 0){
10518             this.showPrevMonth();
10519             e.stopEvent();
10520         } else if(delta < 0){
10521             this.showNextMonth();
10522             e.stopEvent();
10523         }
10524     },
10525
10526     // private
10527     handleDateClick : function(e, t){
10528         e.stopEvent();
10529         if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10530             this.setValue(new Date(t.dateValue));
10531             this.fireEvent("select", this, this.value);
10532         }
10533     },
10534
10535     // private
10536     selectToday : function(){
10537         this.setValue(new Date().clearTime());
10538         this.fireEvent("select", this, this.value);
10539     },
10540
10541     // private
10542     update : function(date){
10543         var vd = this.activeDate;
10544         this.activeDate = date;
10545         if(vd && this.el){
10546             var t = date.getTime();
10547             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10548                 this.cells.removeClass("x-date-selected");
10549                 this.cells.each(function(c){
10550                    if(c.dom.firstChild.dateValue == t){
10551                        c.addClass("x-date-selected");
10552                        setTimeout(function(){
10553                             try{c.dom.firstChild.focus();}catch(e){}
10554                        }, 50);
10555                        return false;
10556                    }
10557                 });
10558                 return;
10559             }
10560         }
10561         var days = date.getDaysInMonth();
10562         var firstOfMonth = date.getFirstDateOfMonth();
10563         var startingPos = firstOfMonth.getDay()-this.startDay;
10564
10565         if(startingPos <= this.startDay){
10566             startingPos += 7;
10567         }
10568
10569         var pm = date.add("mo", -1);
10570         var prevStart = pm.getDaysInMonth()-startingPos;
10571
10572         var cells = this.cells.elements;
10573         var textEls = this.textNodes;
10574         days += startingPos;
10575
10576         // convert everything to numbers so it's fast
10577         var day = 86400000;
10578         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10579         var today = new Date().clearTime().getTime();
10580         var sel = date.clearTime().getTime();
10581         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10582         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10583         var ddMatch = this.disabledDatesRE;
10584         var ddText = this.disabledDatesText;
10585         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10586         var ddaysText = this.disabledDaysText;
10587         var format = this.format;
10588
10589         var setCellClass = function(cal, cell){
10590             cell.title = "";
10591             var t = d.getTime();
10592             cell.firstChild.dateValue = t;
10593             if(t == today){
10594                 cell.className += " x-date-today";
10595                 cell.title = cal.todayText;
10596             }
10597             if(t == sel){
10598                 cell.className += " x-date-selected";
10599                 setTimeout(function(){
10600                     try{cell.firstChild.focus();}catch(e){}
10601                 }, 50);
10602             }
10603             // disabling
10604             if(t < min) {
10605                 cell.className = " x-date-disabled";
10606                 cell.title = cal.minText;
10607                 return;
10608             }
10609             if(t > max) {
10610                 cell.className = " x-date-disabled";
10611                 cell.title = cal.maxText;
10612                 return;
10613             }
10614             if(ddays){
10615                 if(ddays.indexOf(d.getDay()) != -1){
10616                     cell.title = ddaysText;
10617                     cell.className = " x-date-disabled";
10618                 }
10619             }
10620             if(ddMatch && format){
10621                 var fvalue = d.dateFormat(format);
10622                 if(ddMatch.test(fvalue)){
10623                     cell.title = ddText.replace("%0", fvalue);
10624                     cell.className = " x-date-disabled";
10625                 }
10626             }
10627         };
10628
10629         var i = 0;
10630         for(; i < startingPos; i++) {
10631             textEls[i].innerHTML = (++prevStart);
10632             d.setDate(d.getDate()+1);
10633             cells[i].className = "x-date-prevday";
10634             setCellClass(this, cells[i]);
10635         }
10636         for(; i < days; i++){
10637             intDay = i - startingPos + 1;
10638             textEls[i].innerHTML = (intDay);
10639             d.setDate(d.getDate()+1);
10640             cells[i].className = "x-date-active";
10641             setCellClass(this, cells[i]);
10642         }
10643         var extraDays = 0;
10644         for(; i < 42; i++) {
10645              textEls[i].innerHTML = (++extraDays);
10646              d.setDate(d.getDate()+1);
10647              cells[i].className = "x-date-nextday";
10648              setCellClass(this, cells[i]);
10649         }
10650
10651         this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10652
10653         if(!this.internalRender){
10654             var main = this.el.dom.firstChild;
10655             var w = main.offsetWidth;
10656             this.el.setWidth(w + this.el.getBorderWidth("lr"));
10657             Roo.fly(main).setWidth(w);
10658             this.internalRender = true;
10659             // opera does not respect the auto grow header center column
10660             // then, after it gets a width opera refuses to recalculate
10661             // without a second pass
10662             if(Roo.isOpera && !this.secondPass){
10663                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10664                 this.secondPass = true;
10665                 this.update.defer(10, this, [date]);
10666             }
10667         }
10668     }
10669 });/*
10670  * Based on:
10671  * Ext JS Library 1.1.1
10672  * Copyright(c) 2006-2007, Ext JS, LLC.
10673  *
10674  * Originally Released Under LGPL - original licence link has changed is not relivant.
10675  *
10676  * Fork - LGPL
10677  * <script type="text/javascript">
10678  */
10679 /**
10680  * @class Roo.TabPanel
10681  * @extends Roo.util.Observable
10682  * A lightweight tab container.
10683  * <br><br>
10684  * Usage:
10685  * <pre><code>
10686 // basic tabs 1, built from existing content
10687 var tabs = new Roo.TabPanel("tabs1");
10688 tabs.addTab("script", "View Script");
10689 tabs.addTab("markup", "View Markup");
10690 tabs.activate("script");
10691
10692 // more advanced tabs, built from javascript
10693 var jtabs = new Roo.TabPanel("jtabs");
10694 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10695
10696 // set up the UpdateManager
10697 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10698 var updater = tab2.getUpdateManager();
10699 updater.setDefaultUrl("ajax1.htm");
10700 tab2.on('activate', updater.refresh, updater, true);
10701
10702 // Use setUrl for Ajax loading
10703 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10704 tab3.setUrl("ajax2.htm", null, true);
10705
10706 // Disabled tab
10707 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10708 tab4.disable();
10709
10710 jtabs.activate("jtabs-1");
10711  * </code></pre>
10712  * @constructor
10713  * Create a new TabPanel.
10714  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10715  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10716  */
10717 Roo.TabPanel = function(container, config){
10718     /**
10719     * The container element for this TabPanel.
10720     * @type Roo.Element
10721     */
10722     this.el = Roo.get(container, true);
10723     if(config){
10724         if(typeof config == "boolean"){
10725             this.tabPosition = config ? "bottom" : "top";
10726         }else{
10727             Roo.apply(this, config);
10728         }
10729     }
10730     if(this.tabPosition == "bottom"){
10731         this.bodyEl = Roo.get(this.createBody(this.el.dom));
10732         this.el.addClass("x-tabs-bottom");
10733     }
10734     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10735     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10736     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10737     if(Roo.isIE){
10738         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10739     }
10740     if(this.tabPosition != "bottom"){
10741     /** The body element that contains {@link Roo.TabPanelItem} bodies.
10742      * @type Roo.Element
10743      */
10744       this.bodyEl = Roo.get(this.createBody(this.el.dom));
10745       this.el.addClass("x-tabs-top");
10746     }
10747     this.items = [];
10748
10749     this.bodyEl.setStyle("position", "relative");
10750
10751     this.active = null;
10752     this.activateDelegate = this.activate.createDelegate(this);
10753
10754     this.addEvents({
10755         /**
10756          * @event tabchange
10757          * Fires when the active tab changes
10758          * @param {Roo.TabPanel} this
10759          * @param {Roo.TabPanelItem} activePanel The new active tab
10760          */
10761         "tabchange": true,
10762         /**
10763          * @event beforetabchange
10764          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10765          * @param {Roo.TabPanel} this
10766          * @param {Object} e Set cancel to true on this object to cancel the tab change
10767          * @param {Roo.TabPanelItem} tab The tab being changed to
10768          */
10769         "beforetabchange" : true
10770     });
10771
10772     Roo.EventManager.onWindowResize(this.onResize, this);
10773     this.cpad = this.el.getPadding("lr");
10774     this.hiddenCount = 0;
10775
10776     Roo.TabPanel.superclass.constructor.call(this);
10777 };
10778
10779 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10780         /*
10781          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10782          */
10783     tabPosition : "top",
10784         /*
10785          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10786          */
10787     currentTabWidth : 0,
10788         /*
10789          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10790          */
10791     minTabWidth : 40,
10792         /*
10793          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10794          */
10795     maxTabWidth : 250,
10796         /*
10797          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10798          */
10799     preferredTabWidth : 175,
10800         /*
10801          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10802          */
10803     resizeTabs : false,
10804         /*
10805          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10806          */
10807     monitorResize : true,
10808
10809     /**
10810      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10811      * @param {String} id The id of the div to use <b>or create</b>
10812      * @param {String} text The text for the tab
10813      * @param {String} content (optional) Content to put in the TabPanelItem body
10814      * @param {Boolean} closable (optional) True to create a close icon on the tab
10815      * @return {Roo.TabPanelItem} The created TabPanelItem
10816      */
10817     addTab : function(id, text, content, closable){
10818         var item = new Roo.TabPanelItem(this, id, text, closable);
10819         this.addTabItem(item);
10820         if(content){
10821             item.setContent(content);
10822         }
10823         return item;
10824     },
10825
10826     /**
10827      * Returns the {@link Roo.TabPanelItem} with the specified id/index
10828      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10829      * @return {Roo.TabPanelItem}
10830      */
10831     getTab : function(id){
10832         return this.items[id];
10833     },
10834
10835     /**
10836      * Hides the {@link Roo.TabPanelItem} with the specified id/index
10837      * @param {String/Number} id The id or index of the TabPanelItem to hide.
10838      */
10839     hideTab : function(id){
10840         var t = this.items[id];
10841         if(!t.isHidden()){
10842            t.setHidden(true);
10843            this.hiddenCount++;
10844            this.autoSizeTabs();
10845         }
10846     },
10847
10848     /**
10849      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10850      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10851      */
10852     unhideTab : function(id){
10853         var t = this.items[id];
10854         if(t.isHidden()){
10855            t.setHidden(false);
10856            this.hiddenCount--;
10857            this.autoSizeTabs();
10858         }
10859     },
10860
10861     /**
10862      * Adds an existing {@link Roo.TabPanelItem}.
10863      * @param {Roo.TabPanelItem} item The TabPanelItem to add
10864      */
10865     addTabItem : function(item){
10866         this.items[item.id] = item;
10867         this.items.push(item);
10868         if(this.resizeTabs){
10869            item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10870            this.autoSizeTabs();
10871         }else{
10872             item.autoSize();
10873         }
10874     },
10875
10876     /**
10877      * Removes a {@link Roo.TabPanelItem}.
10878      * @param {String/Number} id The id or index of the TabPanelItem to remove.
10879      */
10880     removeTab : function(id){
10881         var items = this.items;
10882         var tab = items[id];
10883         if(!tab) { return; }
10884         var index = items.indexOf(tab);
10885         if(this.active == tab && items.length > 1){
10886             var newTab = this.getNextAvailable(index);
10887             if(newTab) {
10888                 newTab.activate();
10889             }
10890         }
10891         this.stripEl.dom.removeChild(tab.pnode.dom);
10892         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10893             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10894         }
10895         items.splice(index, 1);
10896         delete this.items[tab.id];
10897         tab.fireEvent("close", tab);
10898         tab.purgeListeners();
10899         this.autoSizeTabs();
10900     },
10901
10902     getNextAvailable : function(start){
10903         var items = this.items;
10904         var index = start;
10905         // look for a next tab that will slide over to
10906         // replace the one being removed
10907         while(index < items.length){
10908             var item = items[++index];
10909             if(item && !item.isHidden()){
10910                 return item;
10911             }
10912         }
10913         // if one isn't found select the previous tab (on the left)
10914         index = start;
10915         while(index >= 0){
10916             var item = items[--index];
10917             if(item && !item.isHidden()){
10918                 return item;
10919             }
10920         }
10921         return null;
10922     },
10923
10924     /**
10925      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10926      * @param {String/Number} id The id or index of the TabPanelItem to disable.
10927      */
10928     disableTab : function(id){
10929         var tab = this.items[id];
10930         if(tab && this.active != tab){
10931             tab.disable();
10932         }
10933     },
10934
10935     /**
10936      * Enables a {@link Roo.TabPanelItem} that is disabled.
10937      * @param {String/Number} id The id or index of the TabPanelItem to enable.
10938      */
10939     enableTab : function(id){
10940         var tab = this.items[id];
10941         tab.enable();
10942     },
10943
10944     /**
10945      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10946      * @param {String/Number} id The id or index of the TabPanelItem to activate.
10947      * @return {Roo.TabPanelItem} The TabPanelItem.
10948      */
10949     activate : function(id){
10950         var tab = this.items[id];
10951         if(!tab){
10952             return null;
10953         }
10954         if(tab == this.active || tab.disabled){
10955             return tab;
10956         }
10957         var e = {};
10958         this.fireEvent("beforetabchange", this, e, tab);
10959         if(e.cancel !== true && !tab.disabled){
10960             if(this.active){
10961                 this.active.hide();
10962             }
10963             this.active = this.items[id];
10964             this.active.show();
10965             this.fireEvent("tabchange", this, this.active);
10966         }
10967         return tab;
10968     },
10969
10970     /**
10971      * Gets the active {@link Roo.TabPanelItem}.
10972      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10973      */
10974     getActiveTab : function(){
10975         return this.active;
10976     },
10977
10978     /**
10979      * Updates the tab body element to fit the height of the container element
10980      * for overflow scrolling
10981      * @param {Number} targetHeight (optional) Override the starting height from the elements height
10982      */
10983     syncHeight : function(targetHeight){
10984         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10985         var bm = this.bodyEl.getMargins();
10986         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10987         this.bodyEl.setHeight(newHeight);
10988         return newHeight;
10989     },
10990
10991     onResize : function(){
10992         if(this.monitorResize){
10993             this.autoSizeTabs();
10994         }
10995     },
10996
10997     /**
10998      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10999      */
11000     beginUpdate : function(){
11001         this.updating = true;
11002     },
11003
11004     /**
11005      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11006      */
11007     endUpdate : function(){
11008         this.updating = false;
11009         this.autoSizeTabs();
11010     },
11011
11012     /**
11013      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11014      */
11015     autoSizeTabs : function(){
11016         var count = this.items.length;
11017         var vcount = count - this.hiddenCount;
11018         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11019         var w = Math.max(this.el.getWidth() - this.cpad, 10);
11020         var availWidth = Math.floor(w / vcount);
11021         var b = this.stripBody;
11022         if(b.getWidth() > w){
11023             var tabs = this.items;
11024             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11025             if(availWidth < this.minTabWidth){
11026                 /*if(!this.sleft){    // incomplete scrolling code
11027                     this.createScrollButtons();
11028                 }
11029                 this.showScroll();
11030                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11031             }
11032         }else{
11033             if(this.currentTabWidth < this.preferredTabWidth){
11034                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11035             }
11036         }
11037     },
11038
11039     /**
11040      * Returns the number of tabs in this TabPanel.
11041      * @return {Number}
11042      */
11043      getCount : function(){
11044          return this.items.length;
11045      },
11046
11047     /**
11048      * Resizes all the tabs to the passed width
11049      * @param {Number} The new width
11050      */
11051     setTabWidth : function(width){
11052         this.currentTabWidth = width;
11053         for(var i = 0, len = this.items.length; i < len; i++) {
11054                 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11055         }
11056     },
11057
11058     /**
11059      * Destroys this TabPanel
11060      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11061      */
11062     destroy : function(removeEl){
11063         Roo.EventManager.removeResizeListener(this.onResize, this);
11064         for(var i = 0, len = this.items.length; i < len; i++){
11065             this.items[i].purgeListeners();
11066         }
11067         if(removeEl === true){
11068             this.el.update("");
11069             this.el.remove();
11070         }
11071     }
11072 });
11073
11074 /**
11075  * @class Roo.TabPanelItem
11076  * @extends Roo.util.Observable
11077  * Represents an individual item (tab plus body) in a TabPanel.
11078  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11079  * @param {String} id The id of this TabPanelItem
11080  * @param {String} text The text for the tab of this TabPanelItem
11081  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11082  */
11083 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11084     /**
11085      * The {@link Roo.TabPanel} this TabPanelItem belongs to
11086      * @type Roo.TabPanel
11087      */
11088     this.tabPanel = tabPanel;
11089     /**
11090      * The id for this TabPanelItem
11091      * @type String
11092      */
11093     this.id = id;
11094     /** @private */
11095     this.disabled = false;
11096     /** @private */
11097     this.text = text;
11098     /** @private */
11099     this.loaded = false;
11100     this.closable = closable;
11101
11102     /**
11103      * The body element for this TabPanelItem.
11104      * @type Roo.Element
11105      */
11106     this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11107     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11108     this.bodyEl.setStyle("display", "block");
11109     this.bodyEl.setStyle("zoom", "1");
11110     this.hideAction();
11111
11112     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11113     /** @private */
11114     this.el = Roo.get(els.el, true);
11115     this.inner = Roo.get(els.inner, true);
11116     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11117     this.pnode = Roo.get(els.el.parentNode, true);
11118     this.el.on("mousedown", this.onTabMouseDown, this);
11119     this.el.on("click", this.onTabClick, this);
11120     /** @private */
11121     if(closable){
11122         var c = Roo.get(els.close, true);
11123         c.dom.title = this.closeText;
11124         c.addClassOnOver("close-over");
11125         c.on("click", this.closeClick, this);
11126      }
11127
11128     this.addEvents({
11129          /**
11130          * @event activate
11131          * Fires when this tab becomes the active tab.
11132          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11133          * @param {Roo.TabPanelItem} this
11134          */
11135         "activate": true,
11136         /**
11137          * @event beforeclose
11138          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11139          * @param {Roo.TabPanelItem} this
11140          * @param {Object} e Set cancel to true on this object to cancel the close.
11141          */
11142         "beforeclose": true,
11143         /**
11144          * @event close
11145          * Fires when this tab is closed.
11146          * @param {Roo.TabPanelItem} this
11147          */
11148          "close": true,
11149         /**
11150          * @event deactivate
11151          * Fires when this tab is no longer the active tab.
11152          * @param {Roo.TabPanel} tabPanel The parent TabPanel
11153          * @param {Roo.TabPanelItem} this
11154          */
11155          "deactivate" : true
11156     });
11157     this.hidden = false;
11158
11159     Roo.TabPanelItem.superclass.constructor.call(this);
11160 };
11161
11162 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11163     purgeListeners : function(){
11164        Roo.util.Observable.prototype.purgeListeners.call(this);
11165        this.el.removeAllListeners();
11166     },
11167     /**
11168      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11169      */
11170     show : function(){
11171         this.pnode.addClass("on");
11172         this.showAction();
11173         if(Roo.isOpera){
11174             this.tabPanel.stripWrap.repaint();
11175         }
11176         this.fireEvent("activate", this.tabPanel, this);
11177     },
11178
11179     /**
11180      * Returns true if this tab is the active tab.
11181      * @return {Boolean}
11182      */
11183     isActive : function(){
11184         return this.tabPanel.getActiveTab() == this;
11185     },
11186
11187     /**
11188      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11189      */
11190     hide : function(){
11191         this.pnode.removeClass("on");
11192         this.hideAction();
11193         this.fireEvent("deactivate", this.tabPanel, this);
11194     },
11195
11196     hideAction : function(){
11197         this.bodyEl.hide();
11198         this.bodyEl.setStyle("position", "absolute");
11199         this.bodyEl.setLeft("-20000px");
11200         this.bodyEl.setTop("-20000px");
11201     },
11202
11203     showAction : function(){
11204         this.bodyEl.setStyle("position", "relative");
11205         this.bodyEl.setTop("");
11206         this.bodyEl.setLeft("");
11207         this.bodyEl.show();
11208     },
11209
11210     /**
11211      * Set the tooltip for the tab.
11212      * @param {String} tooltip The tab's tooltip
11213      */
11214     setTooltip : function(text){
11215         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11216             this.textEl.dom.qtip = text;
11217             this.textEl.dom.removeAttribute('title');
11218         }else{
11219             this.textEl.dom.title = text;
11220         }
11221     },
11222
11223     onTabClick : function(e){
11224         e.preventDefault();
11225         this.tabPanel.activate(this.id);
11226     },
11227
11228     onTabMouseDown : function(e){
11229         e.preventDefault();
11230         this.tabPanel.activate(this.id);
11231     },
11232
11233     getWidth : function(){
11234         return this.inner.getWidth();
11235     },
11236
11237     setWidth : function(width){
11238         var iwidth = width - this.pnode.getPadding("lr");
11239         this.inner.setWidth(iwidth);
11240         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11241         this.pnode.setWidth(width);
11242     },
11243
11244     /**
11245      * Show or hide the tab
11246      * @param {Boolean} hidden True to hide or false to show.
11247      */
11248     setHidden : function(hidden){
11249         this.hidden = hidden;
11250         this.pnode.setStyle("display", hidden ? "none" : "");
11251     },
11252
11253     /**
11254      * Returns true if this tab is "hidden"
11255      * @return {Boolean}
11256      */
11257     isHidden : function(){
11258         return this.hidden;
11259     },
11260
11261     /**
11262      * Returns the text for this tab
11263      * @return {String}
11264      */
11265     getText : function(){
11266         return this.text;
11267     },
11268
11269     autoSize : function(){
11270         //this.el.beginMeasure();
11271         this.textEl.setWidth(1);
11272         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11273         //this.el.endMeasure();
11274     },
11275
11276     /**
11277      * Sets the text for the tab (Note: this also sets the tooltip text)
11278      * @param {String} text The tab's text and tooltip
11279      */
11280     setText : function(text){
11281         this.text = text;
11282         this.textEl.update(text);
11283         this.setTooltip(text);
11284         if(!this.tabPanel.resizeTabs){
11285             this.autoSize();
11286         }
11287     },
11288     /**
11289      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11290      */
11291     activate : function(){
11292         this.tabPanel.activate(this.id);
11293     },
11294
11295     /**
11296      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11297      */
11298     disable : function(){
11299         if(this.tabPanel.active != this){
11300             this.disabled = true;
11301             this.pnode.addClass("disabled");
11302         }
11303     },
11304
11305     /**
11306      * Enables this TabPanelItem if it was previously disabled.
11307      */
11308     enable : function(){
11309         this.disabled = false;
11310         this.pnode.removeClass("disabled");
11311     },
11312
11313     /**
11314      * Sets the content for this TabPanelItem.
11315      * @param {String} content The content
11316      * @param {Boolean} loadScripts true to look for and load scripts
11317      */
11318     setContent : function(content, loadScripts){
11319         this.bodyEl.update(content, loadScripts);
11320     },
11321
11322     /**
11323      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11324      * @return {Roo.UpdateManager} The UpdateManager
11325      */
11326     getUpdateManager : function(){
11327         return this.bodyEl.getUpdateManager();
11328     },
11329
11330     /**
11331      * Set a URL to be used to load the content for this TabPanelItem.
11332      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11333      * @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)
11334      * @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)
11335      * @return {Roo.UpdateManager} The UpdateManager
11336      */
11337     setUrl : function(url, params, loadOnce){
11338         if(this.refreshDelegate){
11339             this.un('activate', this.refreshDelegate);
11340         }
11341         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11342         this.on("activate", this.refreshDelegate);
11343         return this.bodyEl.getUpdateManager();
11344     },
11345
11346     /** @private */
11347     _handleRefresh : function(url, params, loadOnce){
11348         if(!loadOnce || !this.loaded){
11349             var updater = this.bodyEl.getUpdateManager();
11350             updater.update(url, params, this._setLoaded.createDelegate(this));
11351         }
11352     },
11353
11354     /**
11355      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
11356      *   Will fail silently if the setUrl method has not been called.
11357      *   This does not activate the panel, just updates its content.
11358      */
11359     refresh : function(){
11360         if(this.refreshDelegate){
11361            this.loaded = false;
11362            this.refreshDelegate();
11363         }
11364     },
11365
11366     /** @private */
11367     _setLoaded : function(){
11368         this.loaded = true;
11369     },
11370
11371     /** @private */
11372     closeClick : function(e){
11373         var o = {};
11374         e.stopEvent();
11375         this.fireEvent("beforeclose", this, o);
11376         if(o.cancel !== true){
11377             this.tabPanel.removeTab(this.id);
11378         }
11379     },
11380     /**
11381      * The text displayed in the tooltip for the close icon.
11382      * @type String
11383      */
11384     closeText : "Close this tab"
11385 });
11386
11387 /** @private */
11388 Roo.TabPanel.prototype.createStrip = function(container){
11389     var strip = document.createElement("div");
11390     strip.className = "x-tabs-wrap";
11391     container.appendChild(strip);
11392     return strip;
11393 };
11394 /** @private */
11395 Roo.TabPanel.prototype.createStripList = function(strip){
11396     // div wrapper for retard IE
11397     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>';
11398     return strip.firstChild.firstChild.firstChild.firstChild;
11399 };
11400 /** @private */
11401 Roo.TabPanel.prototype.createBody = function(container){
11402     var body = document.createElement("div");
11403     Roo.id(body, "tab-body");
11404     Roo.fly(body).addClass("x-tabs-body");
11405     container.appendChild(body);
11406     return body;
11407 };
11408 /** @private */
11409 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11410     var body = Roo.getDom(id);
11411     if(!body){
11412         body = document.createElement("div");
11413         body.id = id;
11414     }
11415     Roo.fly(body).addClass("x-tabs-item-body");
11416     bodyEl.insertBefore(body, bodyEl.firstChild);
11417     return body;
11418 };
11419 /** @private */
11420 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11421     var td = document.createElement("td");
11422     stripEl.appendChild(td);
11423     if(closable){
11424         td.className = "x-tabs-closable";
11425         if(!this.closeTpl){
11426             this.closeTpl = new Roo.Template(
11427                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11428                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11429                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
11430             );
11431         }
11432         var el = this.closeTpl.overwrite(td, {"text": text});
11433         var close = el.getElementsByTagName("div")[0];
11434         var inner = el.getElementsByTagName("em")[0];
11435         return {"el": el, "close": close, "inner": inner};
11436     } else {
11437         if(!this.tabTpl){
11438             this.tabTpl = new Roo.Template(
11439                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11440                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11441             );
11442         }
11443         var el = this.tabTpl.overwrite(td, {"text": text});
11444         var inner = el.getElementsByTagName("em")[0];
11445         return {"el": el, "inner": inner};
11446     }
11447 };