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