Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / pkgs / ext-dd-debug.js
1 /*!
2  * Ext JS Library 3.1.1
3  * Copyright(c) 2006-2010 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /*
8  * These classes are derivatives of the similarly named classes in the YUI Library.
9  * The original license:
10  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
11  * Code licensed under the BSD License:
12  * http://developer.yahoo.net/yui/license.txt
13  */
14
15 (function() {
16
17 var Event=Ext.EventManager;
18 var Dom=Ext.lib.Dom;
19
20 /**
21  * @class Ext.dd.DragDrop
22  * Defines the interface and base operation of items that that can be
23  * dragged or can be drop targets.  It was designed to be extended, overriding
24  * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
25  * Up to three html elements can be associated with a DragDrop instance:
26  * <ul>
27  * <li>linked element: the element that is passed into the constructor.
28  * This is the element which defines the boundaries for interaction with
29  * other DragDrop objects.</li>
30  * <li>handle element(s): The drag operation only occurs if the element that
31  * was clicked matches a handle element.  By default this is the linked
32  * element, but there are times that you will want only a portion of the
33  * linked element to initiate the drag operation, and the setHandleElId()
34  * method provides a way to define this.</li>
35  * <li>drag element: this represents the element that would be moved along
36  * with the cursor during a drag operation.  By default, this is the linked
37  * element itself as in {@link Ext.dd.DD}.  setDragElId() lets you define
38  * a separate element that would be moved, as in {@link Ext.dd.DDProxy}.
39  * </li>
40  * </ul>
41  * This class should not be instantiated until the onload event to ensure that
42  * the associated elements are available.
43  * The following would define a DragDrop obj that would interact with any
44  * other DragDrop obj in the "group1" group:
45  * <pre>
46  *  dd = new Ext.dd.DragDrop("div1", "group1");
47  * </pre>
48  * Since none of the event handlers have been implemented, nothing would
49  * actually happen if you were to run the code above.  Normally you would
50  * override this class or one of the default implementations, but you can
51  * also override the methods you want on an instance of the class...
52  * <pre>
53  *  dd.onDragDrop = function(e, id) {
54  *  &nbsp;&nbsp;alert("dd was dropped on " + id);
55  *  }
56  * </pre>
57  * @constructor
58  * @param {String} id of the element that is linked to this instance
59  * @param {String} sGroup the group of related DragDrop objects
60  * @param {object} config an object containing configurable attributes
61  *                Valid properties for DragDrop:
62  *                    padding, isTarget, maintainOffset, primaryButtonOnly
63  */
64 Ext.dd.DragDrop = function(id, sGroup, config) {
65     if(id) {
66         this.init(id, sGroup, config);
67     }
68 };
69
70 Ext.dd.DragDrop.prototype = {
71
72     /**
73      * Set to false to enable a DragDrop object to fire drag events while dragging
74      * over its own Element. Defaults to true - DragDrop objects do not by default
75      * fire drag events to themselves.
76      * @property ignoreSelf
77      * @type Boolean
78      */
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      * Ext.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 object who's property names identify HTML tags to be considered invalid as drag handles.
120      * A non-null property value identifies the tag as invalid. Defaults to the 
121      * following value which prevents drag operations from being initiated by &lt;a> elements:<pre><code>
122 {
123     A: "A"
124 }</code></pre>
125      * @property invalidHandleTypes
126      * @type Object
127      */
128     invalidHandleTypes: null,
129
130     /**
131      * An object who's property names identify the IDs of elements to be considered invalid as drag handles.
132      * A non-null property value identifies the ID as invalid. For example, to prevent
133      * dragging from being initiated on element ID "foo", use:<pre><code>
134 {
135     foo: true
136 }</code></pre>
137      * @property invalidHandleIds
138      * @type Object
139      */
140     invalidHandleIds: null,
141
142     /**
143      * An Array of CSS class names for elements to be considered in valid as drag handles.
144      * @property invalidHandleClasses
145      * @type Array
146      */
147     invalidHandleClasses: null,
148
149     /**
150      * The linked element's absolute X position at the time the drag was
151      * started
152      * @property startPageX
153      * @type int
154      * @private
155      */
156     startPageX: 0,
157
158     /**
159      * The linked element's absolute X position at the time the drag was
160      * started
161      * @property startPageY
162      * @type int
163      * @private
164      */
165     startPageY: 0,
166
167     /**
168      * The group defines a logical collection of DragDrop objects that are
169      * related.  Instances only get events when interacting with other
170      * DragDrop object in the same group.  This lets us define multiple
171      * groups using a single DragDrop subclass if we want.
172      * @property groups
173      * @type object An object in the format {'group1':true, 'group2':true}
174      */
175     groups: null,
176
177     /**
178      * Individual drag/drop instances can be locked.  This will prevent
179      * onmousedown start drag.
180      * @property locked
181      * @type boolean
182      * @private
183      */
184     locked: false,
185
186     /**
187      * Lock this instance
188      * @method lock
189      */
190     lock: function() { this.locked = true; },
191
192     /**
193      * When set to true, other DD objects in cooperating DDGroups do not receive
194      * notification events when this DD object is dragged over them. Defaults to false.
195      * @property moveOnly
196      * @type boolean
197      */
198     moveOnly: false,
199
200     /**
201      * Unlock this instace
202      * @method unlock
203      */
204     unlock: function() { this.locked = false; },
205
206     /**
207      * By default, all instances can be a drop target.  This can be disabled by
208      * setting isTarget to false.
209      * @property isTarget
210      * @type boolean
211      */
212     isTarget: true,
213
214     /**
215      * The padding configured for this drag and drop object for calculating
216      * the drop zone intersection with this object.
217      * @property padding
218      * @type int[] An array containing the 4 padding values: [top, right, bottom, left]
219      */
220     padding: null,
221
222     /**
223      * Cached reference to the linked element
224      * @property _domRef
225      * @private
226      */
227     _domRef: null,
228
229     /**
230      * Internal typeof flag
231      * @property __ygDragDrop
232      * @private
233      */
234     __ygDragDrop: true,
235
236     /**
237      * Set to true when horizontal contraints are applied
238      * @property constrainX
239      * @type boolean
240      * @private
241      */
242     constrainX: false,
243
244     /**
245      * Set to true when vertical contraints are applied
246      * @property constrainY
247      * @type boolean
248      * @private
249      */
250     constrainY: false,
251
252     /**
253      * The left constraint
254      * @property minX
255      * @type int
256      * @private
257      */
258     minX: 0,
259
260     /**
261      * The right constraint
262      * @property maxX
263      * @type int
264      * @private
265      */
266     maxX: 0,
267
268     /**
269      * The up constraint
270      * @property minY
271      * @type int
272      * @type int
273      * @private
274      */
275     minY: 0,
276
277     /**
278      * The down constraint
279      * @property maxY
280      * @type int
281      * @private
282      */
283     maxY: 0,
284
285     /**
286      * Maintain offsets when we resetconstraints.  Set to true when you want
287      * the position of the element relative to its parent to stay the same
288      * when the page changes
289      *
290      * @property maintainOffset
291      * @type boolean
292      */
293     maintainOffset: false,
294
295     /**
296      * Array of pixel locations the element will snap to if we specified a
297      * horizontal graduation/interval.  This array is generated automatically
298      * when you define a tick interval.
299      * @property xTicks
300      * @type int[]
301      */
302     xTicks: null,
303
304     /**
305      * Array of pixel locations the element will snap to if we specified a
306      * vertical graduation/interval.  This array is generated automatically
307      * when you define a tick interval.
308      * @property yTicks
309      * @type int[]
310      */
311     yTicks: null,
312
313     /**
314      * By default the drag and drop instance will only respond to the primary
315      * button click (left button for a right-handed mouse).  Set to true to
316      * allow drag and drop to start with any mouse click that is propogated
317      * by the browser
318      * @property primaryButtonOnly
319      * @type boolean
320      */
321     primaryButtonOnly: true,
322
323     /**
324      * The availabe property is false until the linked dom element is accessible.
325      * @property available
326      * @type boolean
327      */
328     available: false,
329
330     /**
331      * By default, drags can only be initiated if the mousedown occurs in the
332      * region the linked element is.  This is done in part to work around a
333      * bug in some browsers that mis-report the mousedown if the previous
334      * mouseup happened outside of the window.  This property is set to true
335      * if outer handles are defined.
336      *
337      * @property hasOuterHandles
338      * @type boolean
339      * @default false
340      */
341     hasOuterHandles: false,
342
343     /**
344      * Code that executes immediately before the startDrag event
345      * @method b4StartDrag
346      * @private
347      */
348     b4StartDrag: function(x, y) { },
349
350     /**
351      * Abstract method called after a drag/drop object is clicked
352      * and the drag or mousedown time thresholds have beeen met.
353      * @method startDrag
354      * @param {int} X click location
355      * @param {int} Y click location
356      */
357     startDrag: function(x, y) { /* override this */ },
358
359     /**
360      * Code that executes immediately before the onDrag event
361      * @method b4Drag
362      * @private
363      */
364     b4Drag: function(e) { },
365
366     /**
367      * Abstract method called during the onMouseMove event while dragging an
368      * object.
369      * @method onDrag
370      * @param {Event} e the mousemove event
371      */
372     onDrag: function(e) { /* override this */ },
373
374     /**
375      * Abstract method called when this element fist begins hovering over
376      * another DragDrop obj
377      * @method onDragEnter
378      * @param {Event} e the mousemove event
379      * @param {String|DragDrop[]} id In POINT mode, the element
380      * id this is hovering over.  In INTERSECT mode, an array of one or more
381      * dragdrop items being hovered over.
382      */
383     onDragEnter: function(e, id) { /* override this */ },
384
385     /**
386      * Code that executes immediately before the onDragOver event
387      * @method b4DragOver
388      * @private
389      */
390     b4DragOver: function(e) { },
391
392     /**
393      * Abstract method called when this element is hovering over another
394      * DragDrop obj
395      * @method onDragOver
396      * @param {Event} e the mousemove event
397      * @param {String|DragDrop[]} id In POINT mode, the element
398      * id this is hovering over.  In INTERSECT mode, an array of dd items
399      * being hovered over.
400      */
401     onDragOver: function(e, id) { /* override this */ },
402
403     /**
404      * Code that executes immediately before the onDragOut event
405      * @method b4DragOut
406      * @private
407      */
408     b4DragOut: function(e) { },
409
410     /**
411      * Abstract method called when we are no longer hovering over an element
412      * @method onDragOut
413      * @param {Event} e the mousemove event
414      * @param {String|DragDrop[]} id In POINT mode, the element
415      * id this was hovering over.  In INTERSECT mode, an array of dd items
416      * that the mouse is no longer over.
417      */
418     onDragOut: function(e, id) { /* override this */ },
419
420     /**
421      * Code that executes immediately before the onDragDrop event
422      * @method b4DragDrop
423      * @private
424      */
425     b4DragDrop: function(e) { },
426
427     /**
428      * Abstract method called when this item is dropped on another DragDrop
429      * obj
430      * @method onDragDrop
431      * @param {Event} e the mouseup event
432      * @param {String|DragDrop[]} id In POINT mode, the element
433      * id this was dropped on.  In INTERSECT mode, an array of dd items this
434      * was dropped on.
435      */
436     onDragDrop: function(e, id) { /* override this */ },
437
438     /**
439      * Abstract method called when this item is dropped on an area with no
440      * drop target
441      * @method onInvalidDrop
442      * @param {Event} e the mouseup event
443      */
444     onInvalidDrop: function(e) { /* override this */ },
445
446     /**
447      * Code that executes immediately before the endDrag event
448      * @method b4EndDrag
449      * @private
450      */
451     b4EndDrag: function(e) { },
452
453     /**
454      * Fired when we are done dragging the object
455      * @method endDrag
456      * @param {Event} e the mouseup event
457      */
458     endDrag: function(e) { /* override this */ },
459
460     /**
461      * Code executed immediately before the onMouseDown event
462      * @method b4MouseDown
463      * @param {Event} e the mousedown event
464      * @private
465      */
466     b4MouseDown: function(e) {  },
467
468     /**
469      * Event handler that fires when a drag/drop obj gets a mousedown
470      * @method onMouseDown
471      * @param {Event} e the mousedown event
472      */
473     onMouseDown: function(e) { /* override this */ },
474
475     /**
476      * Event handler that fires when a drag/drop obj gets a mouseup
477      * @method onMouseUp
478      * @param {Event} e the mouseup event
479      */
480     onMouseUp: function(e) { /* override this */ },
481
482     /**
483      * Override the onAvailable method to do what is needed after the initial
484      * position was determined.
485      * @method onAvailable
486      */
487     onAvailable: function () {
488     },
489
490     /**
491      * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
492      * @type Object
493      */
494     defaultPadding : {left:0, right:0, top:0, bottom:0},
495
496     /**
497      * Initializes the drag drop object's constraints to restrict movement to a certain element.
498  *
499  * Usage:
500  <pre><code>
501  var dd = new Ext.dd.DDProxy("dragDiv1", "proxytest",
502                 { dragElId: "existingProxyDiv" });
503  dd.startDrag = function(){
504      this.constrainTo("parent-id");
505  };
506  </code></pre>
507  * Or you can initalize it using the {@link Ext.Element} object:
508  <pre><code>
509  Ext.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
510      startDrag : function(){
511          this.constrainTo("parent-id");
512      }
513  });
514  </code></pre>
515      * @param {Mixed} constrainTo The element to constrain to.
516      * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
517      * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
518      * an object containing the sides to pad. For example: {right:10, bottom:10}
519      * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
520      */
521     constrainTo : function(constrainTo, pad, inContent){
522         if(Ext.isNumber(pad)){
523             pad = {left: pad, right:pad, top:pad, bottom:pad};
524         }
525         pad = pad || this.defaultPadding;
526         var b = Ext.get(this.getEl()).getBox(),
527             ce = Ext.get(constrainTo),
528             s = ce.getScroll(),
529             c, 
530             cd = ce.dom;
531         if(cd == document.body){
532             c = { x: s.left, y: s.top, width: Ext.lib.Dom.getViewWidth(), height: Ext.lib.Dom.getViewHeight()};
533         }else{
534             var xy = ce.getXY();
535             c = {x : xy[0], y: xy[1], width: cd.clientWidth, height: cd.clientHeight};
536         }
537
538
539         var topSpace = b.y - c.y,
540             leftSpace = b.x - c.x;
541
542         this.resetConstraints();
543         this.setXConstraint(leftSpace - (pad.left||0), // left
544                 c.width - leftSpace - b.width - (pad.right||0), //right
545                                 this.xTickSize
546         );
547         this.setYConstraint(topSpace - (pad.top||0), //top
548                 c.height - topSpace - b.height - (pad.bottom||0), //bottom
549                                 this.yTickSize
550         );
551     },
552
553     /**
554      * Returns a reference to the linked element
555      * @method getEl
556      * @return {HTMLElement} the html element
557      */
558     getEl: function() {
559         if (!this._domRef) {
560             this._domRef = Ext.getDom(this.id);
561         }
562
563         return this._domRef;
564     },
565
566     /**
567      * Returns a reference to the actual element to drag.  By default this is
568      * the same as the html element, but it can be assigned to another
569      * element. An example of this can be found in Ext.dd.DDProxy
570      * @method getDragEl
571      * @return {HTMLElement} the html element
572      */
573     getDragEl: function() {
574         return Ext.getDom(this.dragElId);
575     },
576
577     /**
578      * Sets up the DragDrop object.  Must be called in the constructor of any
579      * Ext.dd.DragDrop subclass
580      * @method init
581      * @param id the id of the linked element
582      * @param {String} sGroup the group of related items
583      * @param {object} config configuration attributes
584      */
585     init: function(id, sGroup, config) {
586         this.initTarget(id, sGroup, config);
587         Event.on(this.id, "mousedown", this.handleMouseDown, this);
588         // Event.on(this.id, "selectstart", Event.preventDefault);
589     },
590
591     /**
592      * Initializes Targeting functionality only... the object does not
593      * get a mousedown handler.
594      * @method initTarget
595      * @param id the id of the linked element
596      * @param {String} sGroup the group of related items
597      * @param {object} config configuration attributes
598      */
599     initTarget: function(id, sGroup, config) {
600
601         // configuration attributes
602         this.config = config || {};
603
604         // create a local reference to the drag and drop manager
605         this.DDM = Ext.dd.DDM;
606         // initialize the groups array
607         this.groups = {};
608
609         // assume that we have an element reference instead of an id if the
610         // parameter is not a string
611         if (typeof id !== "string") {
612             id = Ext.id(id);
613         }
614
615         // set the id
616         this.id = id;
617
618         // add to an interaction group
619         this.addToGroup((sGroup) ? sGroup : "default");
620
621         // We don't want to register this as the handle with the manager
622         // so we just set the id rather than calling the setter.
623         this.handleElId = id;
624
625         // the linked element is the element that gets dragged by default
626         this.setDragElId(id);
627
628         // by default, clicked anchors will not start drag operations.
629         this.invalidHandleTypes = { A: "A" };
630         this.invalidHandleIds = {};
631         this.invalidHandleClasses = [];
632
633         this.applyConfig();
634
635         this.handleOnAvailable();
636     },
637
638     /**
639      * Applies the configuration parameters that were passed into the constructor.
640      * This is supposed to happen at each level through the inheritance chain.  So
641      * a DDProxy implentation will execute apply config on DDProxy, DD, and
642      * DragDrop in order to get all of the parameters that are available in
643      * each object.
644      * @method applyConfig
645      */
646     applyConfig: function() {
647
648         // configurable properties:
649         //    padding, isTarget, maintainOffset, primaryButtonOnly
650         this.padding           = this.config.padding || [0, 0, 0, 0];
651         this.isTarget          = (this.config.isTarget !== false);
652         this.maintainOffset    = (this.config.maintainOffset);
653         this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
654
655     },
656
657     /**
658      * Executed when the linked element is available
659      * @method handleOnAvailable
660      * @private
661      */
662     handleOnAvailable: function() {
663         this.available = true;
664         this.resetConstraints();
665         this.onAvailable();
666     },
667
668      /**
669      * Configures the padding for the target zone in px.  Effectively expands
670      * (or reduces) the virtual object size for targeting calculations.
671      * Supports css-style shorthand; if only one parameter is passed, all sides
672      * will have that padding, and if only two are passed, the top and bottom
673      * will have the first param, the left and right the second.
674      * @method setPadding
675      * @param {int} iTop    Top pad
676      * @param {int} iRight  Right pad
677      * @param {int} iBot    Bot pad
678      * @param {int} iLeft   Left pad
679      */
680     setPadding: function(iTop, iRight, iBot, iLeft) {
681         // this.padding = [iLeft, iRight, iTop, iBot];
682         if (!iRight && 0 !== iRight) {
683             this.padding = [iTop, iTop, iTop, iTop];
684         } else if (!iBot && 0 !== iBot) {
685             this.padding = [iTop, iRight, iTop, iRight];
686         } else {
687             this.padding = [iTop, iRight, iBot, iLeft];
688         }
689     },
690
691     /**
692      * Stores the initial placement of the linked element.
693      * @method setInitPosition
694      * @param {int} diffX   the X offset, default 0
695      * @param {int} diffY   the Y offset, default 0
696      */
697     setInitPosition: function(diffX, diffY) {
698         var el = this.getEl();
699
700         if (!this.DDM.verifyEl(el)) {
701             return;
702         }
703
704         var dx = diffX || 0;
705         var dy = diffY || 0;
706
707         var p = Dom.getXY( el );
708
709         this.initPageX = p[0] - dx;
710         this.initPageY = p[1] - dy;
711
712         this.lastPageX = p[0];
713         this.lastPageY = p[1];
714
715
716         this.setStartPosition(p);
717     },
718
719     /**
720      * Sets the start position of the element.  This is set when the obj
721      * is initialized, the reset when a drag is started.
722      * @method setStartPosition
723      * @param pos current position (from previous lookup)
724      * @private
725      */
726     setStartPosition: function(pos) {
727         var p = pos || Dom.getXY( this.getEl() );
728         this.deltaSetXY = null;
729
730         this.startPageX = p[0];
731         this.startPageY = p[1];
732     },
733
734     /**
735      * Add this instance to a group of related drag/drop objects.  All
736      * instances belong to at least one group, and can belong to as many
737      * groups as needed.
738      * @method addToGroup
739      * @param sGroup {string} the name of the group
740      */
741     addToGroup: function(sGroup) {
742         this.groups[sGroup] = true;
743         this.DDM.regDragDrop(this, sGroup);
744     },
745
746     /**
747      * Remove's this instance from the supplied interaction group
748      * @method removeFromGroup
749      * @param {string}  sGroup  The group to drop
750      */
751     removeFromGroup: function(sGroup) {
752         if (this.groups[sGroup]) {
753             delete this.groups[sGroup];
754         }
755
756         this.DDM.removeDDFromGroup(this, sGroup);
757     },
758
759     /**
760      * Allows you to specify that an element other than the linked element
761      * will be moved with the cursor during a drag
762      * @method setDragElId
763      * @param id {string} the id of the element that will be used to initiate the drag
764      */
765     setDragElId: function(id) {
766         this.dragElId = id;
767     },
768
769     /**
770      * Allows you to specify a child of the linked element that should be
771      * used to initiate the drag operation.  An example of this would be if
772      * you have a content div with text and links.  Clicking anywhere in the
773      * content area would normally start the drag operation.  Use this method
774      * to specify that an element inside of the content div is the element
775      * that starts the drag operation.
776      * @method setHandleElId
777      * @param id {string} the id of the element that will be used to
778      * initiate the drag.
779      */
780     setHandleElId: function(id) {
781         if (typeof id !== "string") {
782             id = Ext.id(id);
783         }
784         this.handleElId = id;
785         this.DDM.regHandle(this.id, id);
786     },
787
788     /**
789      * Allows you to set an element outside of the linked element as a drag
790      * handle
791      * @method setOuterHandleElId
792      * @param id the id of the element that will be used to initiate the drag
793      */
794     setOuterHandleElId: function(id) {
795         if (typeof id !== "string") {
796             id = Ext.id(id);
797         }
798         Event.on(id, "mousedown",
799                 this.handleMouseDown, this);
800         this.setHandleElId(id);
801
802         this.hasOuterHandles = true;
803     },
804
805     /**
806      * Remove all drag and drop hooks for this element
807      * @method unreg
808      */
809     unreg: function() {
810         Event.un(this.id, "mousedown",
811                 this.handleMouseDown);
812         this._domRef = null;
813         this.DDM._remove(this);
814     },
815
816     destroy : function(){
817         this.unreg();
818     },
819
820     /**
821      * Returns true if this instance is locked, or the drag drop mgr is locked
822      * (meaning that all drag/drop is disabled on the page.)
823      * @method isLocked
824      * @return {boolean} true if this obj or all drag/drop is locked, else
825      * false
826      */
827     isLocked: function() {
828         return (this.DDM.isLocked() || this.locked);
829     },
830
831     /**
832      * Fired when this object is clicked
833      * @method handleMouseDown
834      * @param {Event} e
835      * @param {Ext.dd.DragDrop} oDD the clicked dd object (this dd obj)
836      * @private
837      */
838     handleMouseDown: function(e, oDD){
839         if (this.primaryButtonOnly && e.button != 0) {
840             return;
841         }
842
843         if (this.isLocked()) {
844             return;
845         }
846
847         this.DDM.refreshCache(this.groups);
848
849         var pt = new Ext.lib.Point(Ext.lib.Event.getPageX(e), Ext.lib.Event.getPageY(e));
850         if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
851         } else {
852             if (this.clickValidator(e)) {
853
854                 // set the initial element position
855                 this.setStartPosition();
856
857
858                 this.b4MouseDown(e);
859                 this.onMouseDown(e);
860
861                 this.DDM.handleMouseDown(e, this);
862
863                 this.DDM.stopEvent(e);
864             } else {
865
866
867             }
868         }
869     },
870
871     clickValidator: function(e) {
872         var target = e.getTarget();
873         return ( this.isValidHandleChild(target) &&
874                     (this.id == this.handleElId ||
875                         this.DDM.handleWasClicked(target, this.id)) );
876     },
877
878     /**
879      * Allows you to specify a tag name that should not start a drag operation
880      * when clicked.  This is designed to facilitate embedding links within a
881      * drag handle that do something other than start the drag.
882      * @method addInvalidHandleType
883      * @param {string} tagName the type of element to exclude
884      */
885     addInvalidHandleType: function(tagName) {
886         var type = tagName.toUpperCase();
887         this.invalidHandleTypes[type] = type;
888     },
889
890     /**
891      * Lets you to specify an element id for a child of a drag handle
892      * that should not initiate a drag
893      * @method addInvalidHandleId
894      * @param {string} id the element id of the element you wish to ignore
895      */
896     addInvalidHandleId: function(id) {
897         if (typeof id !== "string") {
898             id = Ext.id(id);
899         }
900         this.invalidHandleIds[id] = id;
901     },
902
903     /**
904      * Lets you specify a css class of elements that will not initiate a drag
905      * @method addInvalidHandleClass
906      * @param {string} cssClass the class of the elements you wish to ignore
907      */
908     addInvalidHandleClass: function(cssClass) {
909         this.invalidHandleClasses.push(cssClass);
910     },
911
912     /**
913      * Unsets an excluded tag name set by addInvalidHandleType
914      * @method removeInvalidHandleType
915      * @param {string} tagName the type of element to unexclude
916      */
917     removeInvalidHandleType: function(tagName) {
918         var type = tagName.toUpperCase();
919         // this.invalidHandleTypes[type] = null;
920         delete this.invalidHandleTypes[type];
921     },
922
923     /**
924      * Unsets an invalid handle id
925      * @method removeInvalidHandleId
926      * @param {string} id the id of the element to re-enable
927      */
928     removeInvalidHandleId: function(id) {
929         if (typeof id !== "string") {
930             id = Ext.id(id);
931         }
932         delete this.invalidHandleIds[id];
933     },
934
935     /**
936      * Unsets an invalid css class
937      * @method removeInvalidHandleClass
938      * @param {string} cssClass the class of the element(s) you wish to
939      * re-enable
940      */
941     removeInvalidHandleClass: function(cssClass) {
942         for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
943             if (this.invalidHandleClasses[i] == cssClass) {
944                 delete this.invalidHandleClasses[i];
945             }
946         }
947     },
948
949     /**
950      * Checks the tag exclusion list to see if this click should be ignored
951      * @method isValidHandleChild
952      * @param {HTMLElement} node the HTMLElement to evaluate
953      * @return {boolean} true if this is a valid tag type, false if not
954      */
955     isValidHandleChild: function(node) {
956
957         var valid = true;
958         // var n = (node.nodeName == "#text") ? node.parentNode : node;
959         var nodeName;
960         try {
961             nodeName = node.nodeName.toUpperCase();
962         } catch(e) {
963             nodeName = node.nodeName;
964         }
965         valid = valid && !this.invalidHandleTypes[nodeName];
966         valid = valid && !this.invalidHandleIds[node.id];
967
968         for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
969             valid = !Ext.fly(node).hasClass(this.invalidHandleClasses[i]);
970         }
971
972
973         return valid;
974
975     },
976
977     /**
978      * Create the array of horizontal tick marks if an interval was specified
979      * in setXConstraint().
980      * @method setXTicks
981      * @private
982      */
983     setXTicks: function(iStartX, iTickSize) {
984         this.xTicks = [];
985         this.xTickSize = iTickSize;
986
987         var tickMap = {};
988
989         for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
990             if (!tickMap[i]) {
991                 this.xTicks[this.xTicks.length] = i;
992                 tickMap[i] = true;
993             }
994         }
995
996         for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
997             if (!tickMap[i]) {
998                 this.xTicks[this.xTicks.length] = i;
999                 tickMap[i] = true;
1000             }
1001         }
1002
1003         this.xTicks.sort(this.DDM.numericSort) ;
1004     },
1005
1006     /**
1007      * Create the array of vertical tick marks if an interval was specified in
1008      * setYConstraint().
1009      * @method setYTicks
1010      * @private
1011      */
1012     setYTicks: function(iStartY, iTickSize) {
1013         this.yTicks = [];
1014         this.yTickSize = iTickSize;
1015
1016         var tickMap = {};
1017
1018         for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1019             if (!tickMap[i]) {
1020                 this.yTicks[this.yTicks.length] = i;
1021                 tickMap[i] = true;
1022             }
1023         }
1024
1025         for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1026             if (!tickMap[i]) {
1027                 this.yTicks[this.yTicks.length] = i;
1028                 tickMap[i] = true;
1029             }
1030         }
1031
1032         this.yTicks.sort(this.DDM.numericSort) ;
1033     },
1034
1035     /**
1036      * By default, the element can be dragged any place on the screen.  Use
1037      * this method to limit the horizontal travel of the element.  Pass in
1038      * 0,0 for the parameters if you want to lock the drag to the y axis.
1039      * @method setXConstraint
1040      * @param {int} iLeft the number of pixels the element can move to the left
1041      * @param {int} iRight the number of pixels the element can move to the
1042      * right
1043      * @param {int} iTickSize optional parameter for specifying that the
1044      * element
1045      * should move iTickSize pixels at a time.
1046      */
1047     setXConstraint: function(iLeft, iRight, iTickSize) {
1048         this.leftConstraint = iLeft;
1049         this.rightConstraint = iRight;
1050
1051         this.minX = this.initPageX - iLeft;
1052         this.maxX = this.initPageX + iRight;
1053         if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1054
1055         this.constrainX = true;
1056     },
1057
1058     /**
1059      * Clears any constraints applied to this instance.  Also clears ticks
1060      * since they can't exist independent of a constraint at this time.
1061      * @method clearConstraints
1062      */
1063     clearConstraints: function() {
1064         this.constrainX = false;
1065         this.constrainY = false;
1066         this.clearTicks();
1067     },
1068
1069     /**
1070      * Clears any tick interval defined for this instance
1071      * @method clearTicks
1072      */
1073     clearTicks: function() {
1074         this.xTicks = null;
1075         this.yTicks = null;
1076         this.xTickSize = 0;
1077         this.yTickSize = 0;
1078     },
1079
1080     /**
1081      * By default, the element can be dragged any place on the screen.  Set
1082      * this to limit the vertical travel of the element.  Pass in 0,0 for the
1083      * parameters if you want to lock the drag to the x axis.
1084      * @method setYConstraint
1085      * @param {int} iUp the number of pixels the element can move up
1086      * @param {int} iDown the number of pixels the element can move down
1087      * @param {int} iTickSize optional parameter for specifying that the
1088      * element should move iTickSize pixels at a time.
1089      */
1090     setYConstraint: function(iUp, iDown, iTickSize) {
1091         this.topConstraint = iUp;
1092         this.bottomConstraint = iDown;
1093
1094         this.minY = this.initPageY - iUp;
1095         this.maxY = this.initPageY + iDown;
1096         if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1097
1098         this.constrainY = true;
1099
1100     },
1101
1102     /**
1103      * resetConstraints must be called if you manually reposition a dd element.
1104      * @method resetConstraints
1105      * @param {boolean} maintainOffset
1106      */
1107     resetConstraints: function() {
1108
1109
1110         // Maintain offsets if necessary
1111         if (this.initPageX || this.initPageX === 0) {
1112             // figure out how much this thing has moved
1113             var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1114             var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1115
1116             this.setInitPosition(dx, dy);
1117
1118         // This is the first time we have detected the element's position
1119         } else {
1120             this.setInitPosition();
1121         }
1122
1123         if (this.constrainX) {
1124             this.setXConstraint( this.leftConstraint,
1125                                  this.rightConstraint,
1126                                  this.xTickSize        );
1127         }
1128
1129         if (this.constrainY) {
1130             this.setYConstraint( this.topConstraint,
1131                                  this.bottomConstraint,
1132                                  this.yTickSize         );
1133         }
1134     },
1135
1136     /**
1137      * Normally the drag element is moved pixel by pixel, but we can specify
1138      * that it move a number of pixels at a time.  This method resolves the
1139      * location when we have it set up like this.
1140      * @method getTick
1141      * @param {int} val where we want to place the object
1142      * @param {int[]} tickArray sorted array of valid points
1143      * @return {int} the closest tick
1144      * @private
1145      */
1146     getTick: function(val, tickArray) {
1147
1148         if (!tickArray) {
1149             // If tick interval is not defined, it is effectively 1 pixel,
1150             // so we return the value passed to us.
1151             return val;
1152         } else if (tickArray[0] >= val) {
1153             // The value is lower than the first tick, so we return the first
1154             // tick.
1155             return tickArray[0];
1156         } else {
1157             for (var i=0, len=tickArray.length; i<len; ++i) {
1158                 var next = i + 1;
1159                 if (tickArray[next] && tickArray[next] >= val) {
1160                     var diff1 = val - tickArray[i];
1161                     var diff2 = tickArray[next] - val;
1162                     return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1163                 }
1164             }
1165
1166             // The value is larger than the last tick, so we return the last
1167             // tick.
1168             return tickArray[tickArray.length - 1];
1169         }
1170     },
1171
1172     /**
1173      * toString method
1174      * @method toString
1175      * @return {string} string representation of the dd obj
1176      */
1177     toString: function() {
1178         return ("DragDrop " + this.id);
1179     }
1180
1181 };
1182
1183 })();
1184 /**
1185  * The drag and drop utility provides a framework for building drag and drop
1186  * applications.  In addition to enabling drag and drop for specific elements,
1187  * the drag and drop elements are tracked by the manager class, and the
1188  * interactions between the various elements are tracked during the drag and
1189  * the implementing code is notified about these important moments.
1190  */
1191
1192 // Only load the library once.  Rewriting the manager class would orphan
1193 // existing drag and drop instances.
1194 if (!Ext.dd.DragDropMgr) {
1195
1196 /**
1197  * @class Ext.dd.DragDropMgr
1198  * DragDropMgr is a singleton that tracks the element interaction for
1199  * all DragDrop items in the window.  Generally, you will not call
1200  * this class directly, but it does have helper methods that could
1201  * be useful in your DragDrop implementations.
1202  * @singleton
1203  */
1204 Ext.dd.DragDropMgr = function() {
1205
1206     var Event = Ext.EventManager;
1207
1208     return {
1209
1210         /**
1211          * Two dimensional Array of registered DragDrop objects.  The first
1212          * dimension is the DragDrop item group, the second the DragDrop
1213          * object.
1214          * @property ids
1215          * @type {string: string}
1216          * @private
1217          * @static
1218          */
1219         ids: {},
1220
1221         /**
1222          * Array of element ids defined as drag handles.  Used to determine
1223          * if the element that generated the mousedown event is actually the
1224          * handle and not the html element itself.
1225          * @property handleIds
1226          * @type {string: string}
1227          * @private
1228          * @static
1229          */
1230         handleIds: {},
1231
1232         /**
1233          * the DragDrop object that is currently being dragged
1234          * @property dragCurrent
1235          * @type DragDrop
1236          * @private
1237          * @static
1238          **/
1239         dragCurrent: null,
1240
1241         /**
1242          * the DragDrop object(s) that are being hovered over
1243          * @property dragOvers
1244          * @type Array
1245          * @private
1246          * @static
1247          */
1248         dragOvers: {},
1249
1250         /**
1251          * the X distance between the cursor and the object being dragged
1252          * @property deltaX
1253          * @type int
1254          * @private
1255          * @static
1256          */
1257         deltaX: 0,
1258
1259         /**
1260          * the Y distance between the cursor and the object being dragged
1261          * @property deltaY
1262          * @type int
1263          * @private
1264          * @static
1265          */
1266         deltaY: 0,
1267
1268         /**
1269          * Flag to determine if we should prevent the default behavior of the
1270          * events we define. By default this is true, but this can be set to
1271          * false if you need the default behavior (not recommended)
1272          * @property preventDefault
1273          * @type boolean
1274          * @static
1275          */
1276         preventDefault: true,
1277
1278         /**
1279          * Flag to determine if we should stop the propagation of the events
1280          * we generate. This is true by default but you may want to set it to
1281          * false if the html element contains other features that require the
1282          * mouse click.
1283          * @property stopPropagation
1284          * @type boolean
1285          * @static
1286          */
1287         stopPropagation: true,
1288
1289         /**
1290          * Internal flag that is set to true when drag and drop has been
1291          * intialized
1292          * @property initialized
1293          * @private
1294          * @static
1295          */
1296         initialized: false,
1297
1298         /**
1299          * All drag and drop can be disabled.
1300          * @property locked
1301          * @private
1302          * @static
1303          */
1304         locked: false,
1305
1306         /**
1307          * Called the first time an element is registered.
1308          * @method init
1309          * @private
1310          * @static
1311          */
1312         init: function() {
1313             this.initialized = true;
1314         },
1315
1316         /**
1317          * In point mode, drag and drop interaction is defined by the
1318          * location of the cursor during the drag/drop
1319          * @property POINT
1320          * @type int
1321          * @static
1322          */
1323         POINT: 0,
1324
1325         /**
1326          * In intersect mode, drag and drop interaction is defined by the
1327          * overlap of two or more drag and drop objects.
1328          * @property INTERSECT
1329          * @type int
1330          * @static
1331          */
1332         INTERSECT: 1,
1333
1334         /**
1335          * The current drag and drop mode.  Default: POINT
1336          * @property mode
1337          * @type int
1338          * @static
1339          */
1340         mode: 0,
1341
1342         /**
1343          * Runs method on all drag and drop objects
1344          * @method _execOnAll
1345          * @private
1346          * @static
1347          */
1348         _execOnAll: function(sMethod, args) {
1349             for (var i in this.ids) {
1350                 for (var j in this.ids[i]) {
1351                     var oDD = this.ids[i][j];
1352                     if (! this.isTypeOfDD(oDD)) {
1353                         continue;
1354                     }
1355                     oDD[sMethod].apply(oDD, args);
1356                 }
1357             }
1358         },
1359
1360         /**
1361          * Drag and drop initialization.  Sets up the global event handlers
1362          * @method _onLoad
1363          * @private
1364          * @static
1365          */
1366         _onLoad: function() {
1367
1368             this.init();
1369
1370
1371             Event.on(document, "mouseup",   this.handleMouseUp, this, true);
1372             Event.on(document, "mousemove", this.handleMouseMove, this, true);
1373             Event.on(window,   "unload",    this._onUnload, this, true);
1374             Event.on(window,   "resize",    this._onResize, this, true);
1375             // Event.on(window,   "mouseout",    this._test);
1376
1377         },
1378
1379         /**
1380          * Reset constraints on all drag and drop objs
1381          * @method _onResize
1382          * @private
1383          * @static
1384          */
1385         _onResize: function(e) {
1386             this._execOnAll("resetConstraints", []);
1387         },
1388
1389         /**
1390          * Lock all drag and drop functionality
1391          * @method lock
1392          * @static
1393          */
1394         lock: function() { this.locked = true; },
1395
1396         /**
1397          * Unlock all drag and drop functionality
1398          * @method unlock
1399          * @static
1400          */
1401         unlock: function() { this.locked = false; },
1402
1403         /**
1404          * Is drag and drop locked?
1405          * @method isLocked
1406          * @return {boolean} True if drag and drop is locked, false otherwise.
1407          * @static
1408          */
1409         isLocked: function() { return this.locked; },
1410
1411         /**
1412          * Location cache that is set for all drag drop objects when a drag is
1413          * initiated, cleared when the drag is finished.
1414          * @property locationCache
1415          * @private
1416          * @static
1417          */
1418         locationCache: {},
1419
1420         /**
1421          * Set useCache to false if you want to force object the lookup of each
1422          * drag and drop linked element constantly during a drag.
1423          * @property useCache
1424          * @type boolean
1425          * @static
1426          */
1427         useCache: true,
1428
1429         /**
1430          * The number of pixels that the mouse needs to move after the
1431          * mousedown before the drag is initiated.  Default=3;
1432          * @property clickPixelThresh
1433          * @type int
1434          * @static
1435          */
1436         clickPixelThresh: 3,
1437
1438         /**
1439          * The number of milliseconds after the mousedown event to initiate the
1440          * drag if we don't get a mouseup event. Default=350
1441          * @property clickTimeThresh
1442          * @type int
1443          * @static
1444          */
1445         clickTimeThresh: 350,
1446
1447         /**
1448          * Flag that indicates that either the drag pixel threshold or the
1449          * mousdown time threshold has been met
1450          * @property dragThreshMet
1451          * @type boolean
1452          * @private
1453          * @static
1454          */
1455         dragThreshMet: false,
1456
1457         /**
1458          * Timeout used for the click time threshold
1459          * @property clickTimeout
1460          * @type Object
1461          * @private
1462          * @static
1463          */
1464         clickTimeout: null,
1465
1466         /**
1467          * The X position of the mousedown event stored for later use when a
1468          * drag threshold is met.
1469          * @property startX
1470          * @type int
1471          * @private
1472          * @static
1473          */
1474         startX: 0,
1475
1476         /**
1477          * The Y position of the mousedown event stored for later use when a
1478          * drag threshold is met.
1479          * @property startY
1480          * @type int
1481          * @private
1482          * @static
1483          */
1484         startY: 0,
1485
1486         /**
1487          * Each DragDrop instance must be registered with the DragDropMgr.
1488          * This is executed in DragDrop.init()
1489          * @method regDragDrop
1490          * @param {DragDrop} oDD the DragDrop object to register
1491          * @param {String} sGroup the name of the group this element belongs to
1492          * @static
1493          */
1494         regDragDrop: function(oDD, sGroup) {
1495             if (!this.initialized) { this.init(); }
1496
1497             if (!this.ids[sGroup]) {
1498                 this.ids[sGroup] = {};
1499             }
1500             this.ids[sGroup][oDD.id] = oDD;
1501         },
1502
1503         /**
1504          * Removes the supplied dd instance from the supplied group. Executed
1505          * by DragDrop.removeFromGroup, so don't call this function directly.
1506          * @method removeDDFromGroup
1507          * @private
1508          * @static
1509          */
1510         removeDDFromGroup: function(oDD, sGroup) {
1511             if (!this.ids[sGroup]) {
1512                 this.ids[sGroup] = {};
1513             }
1514
1515             var obj = this.ids[sGroup];
1516             if (obj && obj[oDD.id]) {
1517                 delete obj[oDD.id];
1518             }
1519         },
1520
1521         /**
1522          * Unregisters a drag and drop item.  This is executed in
1523          * DragDrop.unreg, use that method instead of calling this directly.
1524          * @method _remove
1525          * @private
1526          * @static
1527          */
1528         _remove: function(oDD) {
1529             for (var g in oDD.groups) {
1530                 if (g && this.ids[g] && this.ids[g][oDD.id]) {
1531                     delete this.ids[g][oDD.id];
1532                 }
1533             }
1534             delete this.handleIds[oDD.id];
1535         },
1536
1537         /**
1538          * Each DragDrop handle element must be registered.  This is done
1539          * automatically when executing DragDrop.setHandleElId()
1540          * @method regHandle
1541          * @param {String} sDDId the DragDrop id this element is a handle for
1542          * @param {String} sHandleId the id of the element that is the drag
1543          * handle
1544          * @static
1545          */
1546         regHandle: function(sDDId, sHandleId) {
1547             if (!this.handleIds[sDDId]) {
1548                 this.handleIds[sDDId] = {};
1549             }
1550             this.handleIds[sDDId][sHandleId] = sHandleId;
1551         },
1552
1553         /**
1554          * Utility function to determine if a given element has been
1555          * registered as a drag drop item.
1556          * @method isDragDrop
1557          * @param {String} id the element id to check
1558          * @return {boolean} true if this element is a DragDrop item,
1559          * false otherwise
1560          * @static
1561          */
1562         isDragDrop: function(id) {
1563             return ( this.getDDById(id) ) ? true : false;
1564         },
1565
1566         /**
1567          * Returns the drag and drop instances that are in all groups the
1568          * passed in instance belongs to.
1569          * @method getRelated
1570          * @param {DragDrop} p_oDD the obj to get related data for
1571          * @param {boolean} bTargetsOnly if true, only return targetable objs
1572          * @return {DragDrop[]} the related instances
1573          * @static
1574          */
1575         getRelated: function(p_oDD, bTargetsOnly) {
1576             var oDDs = [];
1577             for (var i in p_oDD.groups) {
1578                 for (var j in this.ids[i]) {
1579                     var dd = this.ids[i][j];
1580                     if (! this.isTypeOfDD(dd)) {
1581                         continue;
1582                     }
1583                     if (!bTargetsOnly || dd.isTarget) {
1584                         oDDs[oDDs.length] = dd;
1585                     }
1586                 }
1587             }
1588
1589             return oDDs;
1590         },
1591
1592         /**
1593          * Returns true if the specified dd target is a legal target for
1594          * the specifice drag obj
1595          * @method isLegalTarget
1596          * @param {DragDrop} the drag obj
1597          * @param {DragDrop} the target
1598          * @return {boolean} true if the target is a legal target for the
1599          * dd obj
1600          * @static
1601          */
1602         isLegalTarget: function (oDD, oTargetDD) {
1603             var targets = this.getRelated(oDD, true);
1604             for (var i=0, len=targets.length;i<len;++i) {
1605                 if (targets[i].id == oTargetDD.id) {
1606                     return true;
1607                 }
1608             }
1609
1610             return false;
1611         },
1612
1613         /**
1614          * My goal is to be able to transparently determine if an object is
1615          * typeof DragDrop, and the exact subclass of DragDrop.  typeof
1616          * returns "object", oDD.constructor.toString() always returns
1617          * "DragDrop" and not the name of the subclass.  So for now it just
1618          * evaluates a well-known variable in DragDrop.
1619          * @method isTypeOfDD
1620          * @param {Object} the object to evaluate
1621          * @return {boolean} true if typeof oDD = DragDrop
1622          * @static
1623          */
1624         isTypeOfDD: function (oDD) {
1625             return (oDD && oDD.__ygDragDrop);
1626         },
1627
1628         /**
1629          * Utility function to determine if a given element has been
1630          * registered as a drag drop handle for the given Drag Drop object.
1631          * @method isHandle
1632          * @param {String} id the element id to check
1633          * @return {boolean} true if this element is a DragDrop handle, false
1634          * otherwise
1635          * @static
1636          */
1637         isHandle: function(sDDId, sHandleId) {
1638             return ( this.handleIds[sDDId] &&
1639                             this.handleIds[sDDId][sHandleId] );
1640         },
1641
1642         /**
1643          * Returns the DragDrop instance for a given id
1644          * @method getDDById
1645          * @param {String} id the id of the DragDrop object
1646          * @return {DragDrop} the drag drop object, null if it is not found
1647          * @static
1648          */
1649         getDDById: function(id) {
1650             for (var i in this.ids) {
1651                 if (this.ids[i][id]) {
1652                     return this.ids[i][id];
1653                 }
1654             }
1655             return null;
1656         },
1657
1658         /**
1659          * Fired after a registered DragDrop object gets the mousedown event.
1660          * Sets up the events required to track the object being dragged
1661          * @method handleMouseDown
1662          * @param {Event} e the event
1663          * @param oDD the DragDrop object being dragged
1664          * @private
1665          * @static
1666          */
1667         handleMouseDown: function(e, oDD) {
1668             if(Ext.QuickTips){
1669                 Ext.QuickTips.disable();
1670             }
1671             if(this.dragCurrent){
1672                 // the original browser mouseup wasn't handled (e.g. outside FF browser window)
1673                 // so clean up first to avoid breaking the next drag
1674                 this.handleMouseUp(e);
1675             }
1676             
1677             this.currentTarget = e.getTarget();
1678             this.dragCurrent = oDD;
1679
1680             var el = oDD.getEl();
1681
1682             // track start position
1683             this.startX = e.getPageX();
1684             this.startY = e.getPageY();
1685
1686             this.deltaX = this.startX - el.offsetLeft;
1687             this.deltaY = this.startY - el.offsetTop;
1688
1689             this.dragThreshMet = false;
1690
1691             this.clickTimeout = setTimeout(
1692                     function() {
1693                         var DDM = Ext.dd.DDM;
1694                         DDM.startDrag(DDM.startX, DDM.startY);
1695                     },
1696                     this.clickTimeThresh );
1697         },
1698
1699         /**
1700          * Fired when either the drag pixel threshol or the mousedown hold
1701          * time threshold has been met.
1702          * @method startDrag
1703          * @param x {int} the X position of the original mousedown
1704          * @param y {int} the Y position of the original mousedown
1705          * @static
1706          */
1707         startDrag: function(x, y) {
1708             clearTimeout(this.clickTimeout);
1709             if (this.dragCurrent) {
1710                 this.dragCurrent.b4StartDrag(x, y);
1711                 this.dragCurrent.startDrag(x, y);
1712             }
1713             this.dragThreshMet = true;
1714         },
1715
1716         /**
1717          * Internal function to handle the mouseup event.  Will be invoked
1718          * from the context of the document.
1719          * @method handleMouseUp
1720          * @param {Event} e the event
1721          * @private
1722          * @static
1723          */
1724         handleMouseUp: function(e) {
1725
1726             if(Ext.QuickTips){
1727                 Ext.QuickTips.enable();
1728             }
1729             if (! this.dragCurrent) {
1730                 return;
1731             }
1732
1733             clearTimeout(this.clickTimeout);
1734
1735             if (this.dragThreshMet) {
1736                 this.fireEvents(e, true);
1737             } else {
1738             }
1739
1740             this.stopDrag(e);
1741
1742             this.stopEvent(e);
1743         },
1744
1745         /**
1746          * Utility to stop event propagation and event default, if these
1747          * features are turned on.
1748          * @method stopEvent
1749          * @param {Event} e the event as returned by this.getEvent()
1750          * @static
1751          */
1752         stopEvent: function(e){
1753             if(this.stopPropagation) {
1754                 e.stopPropagation();
1755             }
1756
1757             if (this.preventDefault) {
1758                 e.preventDefault();
1759             }
1760         },
1761
1762         /**
1763          * Internal function to clean up event handlers after the drag
1764          * operation is complete
1765          * @method stopDrag
1766          * @param {Event} e the event
1767          * @private
1768          * @static
1769          */
1770         stopDrag: function(e) {
1771             // Fire the drag end event for the item that was dragged
1772             if (this.dragCurrent) {
1773                 if (this.dragThreshMet) {
1774                     this.dragCurrent.b4EndDrag(e);
1775                     this.dragCurrent.endDrag(e);
1776                 }
1777
1778                 this.dragCurrent.onMouseUp(e);
1779             }
1780
1781             this.dragCurrent = null;
1782             this.dragOvers = {};
1783         },
1784
1785         /**
1786          * Internal function to handle the mousemove event.  Will be invoked
1787          * from the context of the html element.
1788          *
1789          * @TODO figure out what we can do about mouse events lost when the
1790          * user drags objects beyond the window boundary.  Currently we can
1791          * detect this in internet explorer by verifying that the mouse is
1792          * down during the mousemove event.  Firefox doesn't give us the
1793          * button state on the mousemove event.
1794          * @method handleMouseMove
1795          * @param {Event} e the event
1796          * @private
1797          * @static
1798          */
1799         handleMouseMove: function(e) {
1800             if (! this.dragCurrent) {
1801                 return true;
1802             }
1803             // var button = e.which || e.button;
1804
1805             // check for IE mouseup outside of page boundary
1806             if (Ext.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1807                 this.stopEvent(e);
1808                 return this.handleMouseUp(e);
1809             }
1810
1811             if (!this.dragThreshMet) {
1812                 var diffX = Math.abs(this.startX - e.getPageX());
1813                 var diffY = Math.abs(this.startY - e.getPageY());
1814                 if (diffX > this.clickPixelThresh ||
1815                             diffY > this.clickPixelThresh) {
1816                     this.startDrag(this.startX, this.startY);
1817                 }
1818             }
1819
1820             if (this.dragThreshMet) {
1821                 this.dragCurrent.b4Drag(e);
1822                 this.dragCurrent.onDrag(e);
1823                 if(!this.dragCurrent.moveOnly){
1824                     this.fireEvents(e, false);
1825                 }
1826             }
1827
1828             this.stopEvent(e);
1829
1830             return true;
1831         },
1832
1833         /**
1834          * Iterates over all of the DragDrop elements to find ones we are
1835          * hovering over or dropping on
1836          * @method fireEvents
1837          * @param {Event} e the event
1838          * @param {boolean} isDrop is this a drop op or a mouseover op?
1839          * @private
1840          * @static
1841          */
1842         fireEvents: function(e, isDrop) {
1843             var dc = this.dragCurrent;
1844
1845             // If the user did the mouse up outside of the window, we could
1846             // get here even though we have ended the drag.
1847             if (!dc || dc.isLocked()) {
1848                 return;
1849             }
1850
1851             var pt = e.getPoint();
1852
1853             // cache the previous dragOver array
1854             var oldOvers = [];
1855
1856             var outEvts   = [];
1857             var overEvts  = [];
1858             var dropEvts  = [];
1859             var enterEvts = [];
1860
1861             // Check to see if the object(s) we were hovering over is no longer
1862             // being hovered over so we can fire the onDragOut event
1863             for (var i in this.dragOvers) {
1864
1865                 var ddo = this.dragOvers[i];
1866
1867                 if (! this.isTypeOfDD(ddo)) {
1868                     continue;
1869                 }
1870
1871                 if (! this.isOverTarget(pt, ddo, this.mode)) {
1872                     outEvts.push( ddo );
1873                 }
1874
1875                 oldOvers[i] = true;
1876                 delete this.dragOvers[i];
1877             }
1878
1879             for (var sGroup in dc.groups) {
1880
1881                 if ("string" != typeof sGroup) {
1882                     continue;
1883                 }
1884
1885                 for (i in this.ids[sGroup]) {
1886                     var oDD = this.ids[sGroup][i];
1887                     if (! this.isTypeOfDD(oDD)) {
1888                         continue;
1889                     }
1890
1891                     if (oDD.isTarget && !oDD.isLocked() && ((oDD != dc) || (dc.ignoreSelf === false))) {
1892                         if (this.isOverTarget(pt, oDD, this.mode)) {
1893                             // look for drop interactions
1894                             if (isDrop) {
1895                                 dropEvts.push( oDD );
1896                             // look for drag enter and drag over interactions
1897                             } else {
1898
1899                                 // initial drag over: dragEnter fires
1900                                 if (!oldOvers[oDD.id]) {
1901                                     enterEvts.push( oDD );
1902                                 // subsequent drag overs: dragOver fires
1903                                 } else {
1904                                     overEvts.push( oDD );
1905                                 }
1906
1907                                 this.dragOvers[oDD.id] = oDD;
1908                             }
1909                         }
1910                     }
1911                 }
1912             }
1913
1914             if (this.mode) {
1915                 if (outEvts.length) {
1916                     dc.b4DragOut(e, outEvts);
1917                     dc.onDragOut(e, outEvts);
1918                 }
1919
1920                 if (enterEvts.length) {
1921                     dc.onDragEnter(e, enterEvts);
1922                 }
1923
1924                 if (overEvts.length) {
1925                     dc.b4DragOver(e, overEvts);
1926                     dc.onDragOver(e, overEvts);
1927                 }
1928
1929                 if (dropEvts.length) {
1930                     dc.b4DragDrop(e, dropEvts);
1931                     dc.onDragDrop(e, dropEvts);
1932                 }
1933
1934             } else {
1935                 // fire dragout events
1936                 var len = 0;
1937                 for (i=0, len=outEvts.length; i<len; ++i) {
1938                     dc.b4DragOut(e, outEvts[i].id);
1939                     dc.onDragOut(e, outEvts[i].id);
1940                 }
1941
1942                 // fire enter events
1943                 for (i=0,len=enterEvts.length; i<len; ++i) {
1944                     // dc.b4DragEnter(e, oDD.id);
1945                     dc.onDragEnter(e, enterEvts[i].id);
1946                 }
1947
1948                 // fire over events
1949                 for (i=0,len=overEvts.length; i<len; ++i) {
1950                     dc.b4DragOver(e, overEvts[i].id);
1951                     dc.onDragOver(e, overEvts[i].id);
1952                 }
1953
1954                 // fire drop events
1955                 for (i=0, len=dropEvts.length; i<len; ++i) {
1956                     dc.b4DragDrop(e, dropEvts[i].id);
1957                     dc.onDragDrop(e, dropEvts[i].id);
1958                 }
1959
1960             }
1961
1962             // notify about a drop that did not find a target
1963             if (isDrop && !dropEvts.length) {
1964                 dc.onInvalidDrop(e);
1965             }
1966
1967         },
1968
1969         /**
1970          * Helper function for getting the best match from the list of drag
1971          * and drop objects returned by the drag and drop events when we are
1972          * in INTERSECT mode.  It returns either the first object that the
1973          * cursor is over, or the object that has the greatest overlap with
1974          * the dragged element.
1975          * @method getBestMatch
1976          * @param  {DragDrop[]} dds The array of drag and drop objects
1977          * targeted
1978          * @return {DragDrop}       The best single match
1979          * @static
1980          */
1981         getBestMatch: function(dds) {
1982             var winner = null;
1983             // Return null if the input is not what we expect
1984             //if (!dds || !dds.length || dds.length == 0) {
1985                // winner = null;
1986             // If there is only one item, it wins
1987             //} else if (dds.length == 1) {
1988
1989             var len = dds.length;
1990
1991             if (len == 1) {
1992                 winner = dds[0];
1993             } else {
1994                 // Loop through the targeted items
1995                 for (var i=0; i<len; ++i) {
1996                     var dd = dds[i];
1997                     // If the cursor is over the object, it wins.  If the
1998                     // cursor is over multiple matches, the first one we come
1999                     // to wins.
2000                     if (dd.cursorIsOver) {
2001                         winner = dd;
2002                         break;
2003                     // Otherwise the object with the most overlap wins
2004                     } else {
2005                         if (!winner ||
2006                             winner.overlap.getArea() < dd.overlap.getArea()) {
2007                             winner = dd;
2008                         }
2009                     }
2010                 }
2011             }
2012
2013             return winner;
2014         },
2015
2016         /**
2017          * Refreshes the cache of the top-left and bottom-right points of the
2018          * drag and drop objects in the specified group(s).  This is in the
2019          * format that is stored in the drag and drop instance, so typical
2020          * usage is:
2021          * <code>
2022          * Ext.dd.DragDropMgr.refreshCache(ddinstance.groups);
2023          * </code>
2024          * Alternatively:
2025          * <code>
2026          * Ext.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2027          * </code>
2028          * @TODO this really should be an indexed array.  Alternatively this
2029          * method could accept both.
2030          * @method refreshCache
2031          * @param {Object} groups an associative array of groups to refresh
2032          * @static
2033          */
2034         refreshCache: function(groups) {
2035             for (var sGroup in groups) {
2036                 if ("string" != typeof sGroup) {
2037                     continue;
2038                 }
2039                 for (var i in this.ids[sGroup]) {
2040                     var oDD = this.ids[sGroup][i];
2041
2042                     if (this.isTypeOfDD(oDD)) {
2043                     // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2044                         var loc = this.getLocation(oDD);
2045                         if (loc) {
2046                             this.locationCache[oDD.id] = loc;
2047                         } else {
2048                             delete this.locationCache[oDD.id];
2049                             // this will unregister the drag and drop object if
2050                             // the element is not in a usable state
2051                             // oDD.unreg();
2052                         }
2053                     }
2054                 }
2055             }
2056         },
2057
2058         /**
2059          * This checks to make sure an element exists and is in the DOM.  The
2060          * main purpose is to handle cases where innerHTML is used to remove
2061          * drag and drop objects from the DOM.  IE provides an 'unspecified
2062          * error' when trying to access the offsetParent of such an element
2063          * @method verifyEl
2064          * @param {HTMLElement} el the element to check
2065          * @return {boolean} true if the element looks usable
2066          * @static
2067          */
2068         verifyEl: function(el) {
2069             if (el) {
2070                 var parent;
2071                 if(Ext.isIE){
2072                     try{
2073                         parent = el.offsetParent;
2074                     }catch(e){}
2075                 }else{
2076                     parent = el.offsetParent;
2077                 }
2078                 if (parent) {
2079                     return true;
2080                 }
2081             }
2082
2083             return false;
2084         },
2085
2086         /**
2087          * Returns a Region object containing the drag and drop element's position
2088          * and size, including the padding configured for it
2089          * @method getLocation
2090          * @param {DragDrop} oDD the drag and drop object to get the
2091          *                       location for
2092          * @return {Ext.lib.Region} a Region object representing the total area
2093          *                             the element occupies, including any padding
2094          *                             the instance is configured for.
2095          * @static
2096          */
2097         getLocation: function(oDD) {
2098             if (! this.isTypeOfDD(oDD)) {
2099                 return null;
2100             }
2101
2102             var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2103
2104             try {
2105                 pos= Ext.lib.Dom.getXY(el);
2106             } catch (e) { }
2107
2108             if (!pos) {
2109                 return null;
2110             }
2111
2112             x1 = pos[0];
2113             x2 = x1 + el.offsetWidth;
2114             y1 = pos[1];
2115             y2 = y1 + el.offsetHeight;
2116
2117             t = y1 - oDD.padding[0];
2118             r = x2 + oDD.padding[1];
2119             b = y2 + oDD.padding[2];
2120             l = x1 - oDD.padding[3];
2121
2122             return new Ext.lib.Region( t, r, b, l );
2123         },
2124
2125         /**
2126          * Checks the cursor location to see if it over the target
2127          * @method isOverTarget
2128          * @param {Ext.lib.Point} pt The point to evaluate
2129          * @param {DragDrop} oTarget the DragDrop object we are inspecting
2130          * @return {boolean} true if the mouse is over the target
2131          * @private
2132          * @static
2133          */
2134         isOverTarget: function(pt, oTarget, intersect) {
2135             // use cache if available
2136             var loc = this.locationCache[oTarget.id];
2137             if (!loc || !this.useCache) {
2138                 loc = this.getLocation(oTarget);
2139                 this.locationCache[oTarget.id] = loc;
2140
2141             }
2142
2143             if (!loc) {
2144                 return false;
2145             }
2146
2147             oTarget.cursorIsOver = loc.contains( pt );
2148
2149             // DragDrop is using this as a sanity check for the initial mousedown
2150             // in this case we are done.  In POINT mode, if the drag obj has no
2151             // contraints, we are also done. Otherwise we need to evaluate the
2152             // location of the target as related to the actual location of the
2153             // dragged element.
2154             var dc = this.dragCurrent;
2155             if (!dc || !dc.getTargetCoord ||
2156                     (!intersect && !dc.constrainX && !dc.constrainY)) {
2157                 return oTarget.cursorIsOver;
2158             }
2159
2160             oTarget.overlap = null;
2161
2162             // Get the current location of the drag element, this is the
2163             // location of the mouse event less the delta that represents
2164             // where the original mousedown happened on the element.  We
2165             // need to consider constraints and ticks as well.
2166             var pos = dc.getTargetCoord(pt.x, pt.y);
2167
2168             var el = dc.getDragEl();
2169             var curRegion = new Ext.lib.Region( pos.y,
2170                                                    pos.x + el.offsetWidth,
2171                                                    pos.y + el.offsetHeight,
2172                                                    pos.x );
2173
2174             var overlap = curRegion.intersect(loc);
2175
2176             if (overlap) {
2177                 oTarget.overlap = overlap;
2178                 return (intersect) ? true : oTarget.cursorIsOver;
2179             } else {
2180                 return false;
2181             }
2182         },
2183
2184         /**
2185          * unload event handler
2186          * @method _onUnload
2187          * @private
2188          * @static
2189          */
2190         _onUnload: function(e, me) {
2191             Ext.dd.DragDropMgr.unregAll();
2192         },
2193
2194         /**
2195          * Cleans up the drag and drop events and objects.
2196          * @method unregAll
2197          * @private
2198          * @static
2199          */
2200         unregAll: function() {
2201
2202             if (this.dragCurrent) {
2203                 this.stopDrag();
2204                 this.dragCurrent = null;
2205             }
2206
2207             this._execOnAll("unreg", []);
2208
2209             for (var i in this.elementCache) {
2210                 delete this.elementCache[i];
2211             }
2212
2213             this.elementCache = {};
2214             this.ids = {};
2215         },
2216
2217         /**
2218          * A cache of DOM elements
2219          * @property elementCache
2220          * @private
2221          * @static
2222          */
2223         elementCache: {},
2224
2225         /**
2226          * Get the wrapper for the DOM element specified
2227          * @method getElWrapper
2228          * @param {String} id the id of the element to get
2229          * @return {Ext.dd.DDM.ElementWrapper} the wrapped element
2230          * @private
2231          * @deprecated This wrapper isn't that useful
2232          * @static
2233          */
2234         getElWrapper: function(id) {
2235             var oWrapper = this.elementCache[id];
2236             if (!oWrapper || !oWrapper.el) {
2237                 oWrapper = this.elementCache[id] =
2238                     new this.ElementWrapper(Ext.getDom(id));
2239             }
2240             return oWrapper;
2241         },
2242
2243         /**
2244          * Returns the actual DOM element
2245          * @method getElement
2246          * @param {String} id the id of the elment to get
2247          * @return {Object} The element
2248          * @deprecated use Ext.lib.Ext.getDom instead
2249          * @static
2250          */
2251         getElement: function(id) {
2252             return Ext.getDom(id);
2253         },
2254
2255         /**
2256          * Returns the style property for the DOM element (i.e.,
2257          * document.getElById(id).style)
2258          * @method getCss
2259          * @param {String} id the id of the elment to get
2260          * @return {Object} The style property of the element
2261          * @deprecated use Ext.lib.Dom instead
2262          * @static
2263          */
2264         getCss: function(id) {
2265             var el = Ext.getDom(id);
2266             return (el) ? el.style : null;
2267         },
2268
2269         /**
2270          * Inner class for cached elements
2271          * @class Ext.dd.DragDropMgr.ElementWrapper
2272          * @for DragDropMgr
2273          * @private
2274          * @deprecated
2275          */
2276         ElementWrapper: function(el) {
2277                 /**
2278                  * The element
2279                  * @property el
2280                  */
2281                 this.el = el || null;
2282                 /**
2283                  * The element id
2284                  * @property id
2285                  */
2286                 this.id = this.el && el.id;
2287                 /**
2288                  * A reference to the style property
2289                  * @property css
2290                  */
2291                 this.css = this.el && el.style;
2292             },
2293
2294         /**
2295          * Returns the X position of an html element
2296          * @method getPosX
2297          * @param el the element for which to get the position
2298          * @return {int} the X coordinate
2299          * @for DragDropMgr
2300          * @deprecated use Ext.lib.Dom.getX instead
2301          * @static
2302          */
2303         getPosX: function(el) {
2304             return Ext.lib.Dom.getX(el);
2305         },
2306
2307         /**
2308          * Returns the Y position of an html element
2309          * @method getPosY
2310          * @param el the element for which to get the position
2311          * @return {int} the Y coordinate
2312          * @deprecated use Ext.lib.Dom.getY instead
2313          * @static
2314          */
2315         getPosY: function(el) {
2316             return Ext.lib.Dom.getY(el);
2317         },
2318
2319         /**
2320          * Swap two nodes.  In IE, we use the native method, for others we
2321          * emulate the IE behavior
2322          * @method swapNode
2323          * @param n1 the first node to swap
2324          * @param n2 the other node to swap
2325          * @static
2326          */
2327         swapNode: function(n1, n2) {
2328             if (n1.swapNode) {
2329                 n1.swapNode(n2);
2330             } else {
2331                 var p = n2.parentNode;
2332                 var s = n2.nextSibling;
2333
2334                 if (s == n1) {
2335                     p.insertBefore(n1, n2);
2336                 } else if (n2 == n1.nextSibling) {
2337                     p.insertBefore(n2, n1);
2338                 } else {
2339                     n1.parentNode.replaceChild(n2, n1);
2340                     p.insertBefore(n1, s);
2341                 }
2342             }
2343         },
2344
2345         /**
2346          * Returns the current scroll position
2347          * @method getScroll
2348          * @private
2349          * @static
2350          */
2351         getScroll: function () {
2352             var t, l, dde=document.documentElement, db=document.body;
2353             if (dde && (dde.scrollTop || dde.scrollLeft)) {
2354                 t = dde.scrollTop;
2355                 l = dde.scrollLeft;
2356             } else if (db) {
2357                 t = db.scrollTop;
2358                 l = db.scrollLeft;
2359             } else {
2360
2361             }
2362             return { top: t, left: l };
2363         },
2364
2365         /**
2366          * Returns the specified element style property
2367          * @method getStyle
2368          * @param {HTMLElement} el          the element
2369          * @param {string}      styleProp   the style property
2370          * @return {string} The value of the style property
2371          * @deprecated use Ext.lib.Dom.getStyle
2372          * @static
2373          */
2374         getStyle: function(el, styleProp) {
2375             return Ext.fly(el).getStyle(styleProp);
2376         },
2377
2378         /**
2379          * Gets the scrollTop
2380          * @method getScrollTop
2381          * @return {int} the document's scrollTop
2382          * @static
2383          */
2384         getScrollTop: function () { return this.getScroll().top; },
2385
2386         /**
2387          * Gets the scrollLeft
2388          * @method getScrollLeft
2389          * @return {int} the document's scrollTop
2390          * @static
2391          */
2392         getScrollLeft: function () { return this.getScroll().left; },
2393
2394         /**
2395          * Sets the x/y position of an element to the location of the
2396          * target element.
2397          * @method moveToEl
2398          * @param {HTMLElement} moveEl      The element to move
2399          * @param {HTMLElement} targetEl    The position reference element
2400          * @static
2401          */
2402         moveToEl: function (moveEl, targetEl) {
2403             var aCoord = Ext.lib.Dom.getXY(targetEl);
2404             Ext.lib.Dom.setXY(moveEl, aCoord);
2405         },
2406
2407         /**
2408          * Numeric array sort function
2409          * @method numericSort
2410          * @static
2411          */
2412         numericSort: function(a, b) { return (a - b); },
2413
2414         /**
2415          * Internal counter
2416          * @property _timeoutCount
2417          * @private
2418          * @static
2419          */
2420         _timeoutCount: 0,
2421
2422         /**
2423          * Trying to make the load order less important.  Without this we get
2424          * an error if this file is loaded before the Event Utility.
2425          * @method _addListeners
2426          * @private
2427          * @static
2428          */
2429         _addListeners: function() {
2430             var DDM = Ext.dd.DDM;
2431             if ( Ext.lib.Event && document ) {
2432                 DDM._onLoad();
2433             } else {
2434                 if (DDM._timeoutCount > 2000) {
2435                 } else {
2436                     setTimeout(DDM._addListeners, 10);
2437                     if (document && document.body) {
2438                         DDM._timeoutCount += 1;
2439                     }
2440                 }
2441             }
2442         },
2443
2444         /**
2445          * Recursively searches the immediate parent and all child nodes for
2446          * the handle element in order to determine wheter or not it was
2447          * clicked.
2448          * @method handleWasClicked
2449          * @param node the html element to inspect
2450          * @static
2451          */
2452         handleWasClicked: function(node, id) {
2453             if (this.isHandle(id, node.id)) {
2454                 return true;
2455             } else {
2456                 // check to see if this is a text node child of the one we want
2457                 var p = node.parentNode;
2458
2459                 while (p) {
2460                     if (this.isHandle(id, p.id)) {
2461                         return true;
2462                     } else {
2463                         p = p.parentNode;
2464                     }
2465                 }
2466             }
2467
2468             return false;
2469         }
2470
2471     };
2472
2473 }();
2474
2475 // shorter alias, save a few bytes
2476 Ext.dd.DDM = Ext.dd.DragDropMgr;
2477 Ext.dd.DDM._addListeners();
2478
2479 }
2480
2481 /**
2482  * @class Ext.dd.DD
2483  * A DragDrop implementation where the linked element follows the
2484  * mouse cursor during a drag.
2485  * @extends Ext.dd.DragDrop
2486  * @constructor
2487  * @param {String} id the id of the linked element
2488  * @param {String} sGroup the group of related DragDrop items
2489  * @param {object} config an object containing configurable attributes
2490  *                Valid properties for DD:
2491  *                    scroll
2492  */
2493 Ext.dd.DD = function(id, sGroup, config) {
2494     if (id) {
2495         this.init(id, sGroup, config);
2496     }
2497 };
2498
2499 Ext.extend(Ext.dd.DD, Ext.dd.DragDrop, {
2500
2501     /**
2502      * When set to true, the utility automatically tries to scroll the browser
2503      * window when a drag and drop element is dragged near the viewport boundary.
2504      * Defaults to true.
2505      * @property scroll
2506      * @type boolean
2507      */
2508     scroll: true,
2509
2510     /**
2511      * Sets the pointer offset to the distance between the linked element's top
2512      * left corner and the location the element was clicked
2513      * @method autoOffset
2514      * @param {int} iPageX the X coordinate of the click
2515      * @param {int} iPageY the Y coordinate of the click
2516      */
2517     autoOffset: function(iPageX, iPageY) {
2518         var x = iPageX - this.startPageX;
2519         var y = iPageY - this.startPageY;
2520         this.setDelta(x, y);
2521     },
2522
2523     /**
2524      * Sets the pointer offset.  You can call this directly to force the
2525      * offset to be in a particular location (e.g., pass in 0,0 to set it
2526      * to the center of the object)
2527      * @method setDelta
2528      * @param {int} iDeltaX the distance from the left
2529      * @param {int} iDeltaY the distance from the top
2530      */
2531     setDelta: function(iDeltaX, iDeltaY) {
2532         this.deltaX = iDeltaX;
2533         this.deltaY = iDeltaY;
2534     },
2535
2536     /**
2537      * Sets the drag element to the location of the mousedown or click event,
2538      * maintaining the cursor location relative to the location on the element
2539      * that was clicked.  Override this if you want to place the element in a
2540      * location other than where the cursor is.
2541      * @method setDragElPos
2542      * @param {int} iPageX the X coordinate of the mousedown or drag event
2543      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2544      */
2545     setDragElPos: function(iPageX, iPageY) {
2546         // the first time we do this, we are going to check to make sure
2547         // the element has css positioning
2548
2549         var el = this.getDragEl();
2550         this.alignElWithMouse(el, iPageX, iPageY);
2551     },
2552
2553     /**
2554      * Sets the element to the location of the mousedown or click event,
2555      * maintaining the cursor location relative to the location on the element
2556      * that was clicked.  Override this if you want to place the element in a
2557      * location other than where the cursor is.
2558      * @method alignElWithMouse
2559      * @param {HTMLElement} el the element to move
2560      * @param {int} iPageX the X coordinate of the mousedown or drag event
2561      * @param {int} iPageY the Y coordinate of the mousedown or drag event
2562      */
2563     alignElWithMouse: function(el, iPageX, iPageY) {
2564         var oCoord = this.getTargetCoord(iPageX, iPageY);
2565         var fly = el.dom ? el : Ext.fly(el, '_dd');
2566         if (!this.deltaSetXY) {
2567             var aCoord = [oCoord.x, oCoord.y];
2568             fly.setXY(aCoord);
2569             var newLeft = fly.getLeft(true);
2570             var newTop  = fly.getTop(true);
2571             this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2572         } else {
2573             fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2574         }
2575
2576         this.cachePosition(oCoord.x, oCoord.y);
2577         this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2578         return oCoord;
2579     },
2580
2581     /**
2582      * Saves the most recent position so that we can reset the constraints and
2583      * tick marks on-demand.  We need to know this so that we can calculate the
2584      * number of pixels the element is offset from its original position.
2585      * @method cachePosition
2586      * @param iPageX the current x position (optional, this just makes it so we
2587      * don't have to look it up again)
2588      * @param iPageY the current y position (optional, this just makes it so we
2589      * don't have to look it up again)
2590      */
2591     cachePosition: function(iPageX, iPageY) {
2592         if (iPageX) {
2593             this.lastPageX = iPageX;
2594             this.lastPageY = iPageY;
2595         } else {
2596             var aCoord = Ext.lib.Dom.getXY(this.getEl());
2597             this.lastPageX = aCoord[0];
2598             this.lastPageY = aCoord[1];
2599         }
2600     },
2601
2602     /**
2603      * Auto-scroll the window if the dragged object has been moved beyond the
2604      * visible window boundary.
2605      * @method autoScroll
2606      * @param {int} x the drag element's x position
2607      * @param {int} y the drag element's y position
2608      * @param {int} h the height of the drag element
2609      * @param {int} w the width of the drag element
2610      * @private
2611      */
2612     autoScroll: function(x, y, h, w) {
2613
2614         if (this.scroll) {
2615             // The client height
2616             var clientH = Ext.lib.Dom.getViewHeight();
2617
2618             // The client width
2619             var clientW = Ext.lib.Dom.getViewWidth();
2620
2621             // The amt scrolled down
2622             var st = this.DDM.getScrollTop();
2623
2624             // The amt scrolled right
2625             var sl = this.DDM.getScrollLeft();
2626
2627             // Location of the bottom of the element
2628             var bot = h + y;
2629
2630             // Location of the right of the element
2631             var right = w + x;
2632
2633             // The distance from the cursor to the bottom of the visible area,
2634             // adjusted so that we don't scroll if the cursor is beyond the
2635             // element drag constraints
2636             var toBot = (clientH + st - y - this.deltaY);
2637
2638             // The distance from the cursor to the right of the visible area
2639             var toRight = (clientW + sl - x - this.deltaX);
2640
2641
2642             // How close to the edge the cursor must be before we scroll
2643             // var thresh = (document.all) ? 100 : 40;
2644             var thresh = 40;
2645
2646             // How many pixels to scroll per autoscroll op.  This helps to reduce
2647             // clunky scrolling. IE is more sensitive about this ... it needs this
2648             // value to be higher.
2649             var scrAmt = (document.all) ? 80 : 30;
2650
2651             // Scroll down if we are near the bottom of the visible page and the
2652             // obj extends below the crease
2653             if ( bot > clientH && toBot < thresh ) {
2654                 window.scrollTo(sl, st + scrAmt);
2655             }
2656
2657             // Scroll up if the window is scrolled down and the top of the object
2658             // goes above the top border
2659             if ( y < st && st > 0 && y - st < thresh ) {
2660                 window.scrollTo(sl, st - scrAmt);
2661             }
2662
2663             // Scroll right if the obj is beyond the right border and the cursor is
2664             // near the border.
2665             if ( right > clientW && toRight < thresh ) {
2666                 window.scrollTo(sl + scrAmt, st);
2667             }
2668
2669             // Scroll left if the window has been scrolled to the right and the obj
2670             // extends past the left border
2671             if ( x < sl && sl > 0 && x - sl < thresh ) {
2672                 window.scrollTo(sl - scrAmt, st);
2673             }
2674         }
2675     },
2676
2677     /**
2678      * Finds the location the element should be placed if we want to move
2679      * it to where the mouse location less the click offset would place us.
2680      * @method getTargetCoord
2681      * @param {int} iPageX the X coordinate of the click
2682      * @param {int} iPageY the Y coordinate of the click
2683      * @return an object that contains the coordinates (Object.x and Object.y)
2684      * @private
2685      */
2686     getTargetCoord: function(iPageX, iPageY) {
2687
2688
2689         var x = iPageX - this.deltaX;
2690         var y = iPageY - this.deltaY;
2691
2692         if (this.constrainX) {
2693             if (x < this.minX) { x = this.minX; }
2694             if (x > this.maxX) { x = this.maxX; }
2695         }
2696
2697         if (this.constrainY) {
2698             if (y < this.minY) { y = this.minY; }
2699             if (y > this.maxY) { y = this.maxY; }
2700         }
2701
2702         x = this.getTick(x, this.xTicks);
2703         y = this.getTick(y, this.yTicks);
2704
2705
2706         return {x:x, y:y};
2707     },
2708
2709     /**
2710      * Sets up config options specific to this class. Overrides
2711      * Ext.dd.DragDrop, but all versions of this method through the
2712      * inheritance chain are called
2713      */
2714     applyConfig: function() {
2715         Ext.dd.DD.superclass.applyConfig.call(this);
2716         this.scroll = (this.config.scroll !== false);
2717     },
2718
2719     /**
2720      * Event that fires prior to the onMouseDown event.  Overrides
2721      * Ext.dd.DragDrop.
2722      */
2723     b4MouseDown: function(e) {
2724         // this.resetConstraints();
2725         this.autoOffset(e.getPageX(),
2726                             e.getPageY());
2727     },
2728
2729     /**
2730      * Event that fires prior to the onDrag event.  Overrides
2731      * Ext.dd.DragDrop.
2732      */
2733     b4Drag: function(e) {
2734         this.setDragElPos(e.getPageX(),
2735                             e.getPageY());
2736     },
2737
2738     toString: function() {
2739         return ("DD " + this.id);
2740     }
2741
2742     //////////////////////////////////////////////////////////////////////////
2743     // Debugging ygDragDrop events that can be overridden
2744     //////////////////////////////////////////////////////////////////////////
2745     /*
2746     startDrag: function(x, y) {
2747     },
2748
2749     onDrag: function(e) {
2750     },
2751
2752     onDragEnter: function(e, id) {
2753     },
2754
2755     onDragOver: function(e, id) {
2756     },
2757
2758     onDragOut: function(e, id) {
2759     },
2760
2761     onDragDrop: function(e, id) {
2762     },
2763
2764     endDrag: function(e) {
2765     }
2766
2767     */
2768
2769 });
2770 /**
2771  * @class Ext.dd.DDProxy
2772  * A DragDrop implementation that inserts an empty, bordered div into
2773  * the document that follows the cursor during drag operations.  At the time of
2774  * the click, the frame div is resized to the dimensions of the linked html
2775  * element, and moved to the exact location of the linked element.
2776  *
2777  * References to the "frame" element refer to the single proxy element that
2778  * was created to be dragged in place of all DDProxy elements on the
2779  * page.
2780  *
2781  * @extends Ext.dd.DD
2782  * @constructor
2783  * @param {String} id the id of the linked html element
2784  * @param {String} sGroup the group of related DragDrop objects
2785  * @param {object} config an object containing configurable attributes
2786  *                Valid properties for DDProxy in addition to those in DragDrop:
2787  *                   resizeFrame, centerFrame, dragElId
2788  */
2789 Ext.dd.DDProxy = function(id, sGroup, config) {
2790     if (id) {
2791         this.init(id, sGroup, config);
2792         this.initFrame();
2793     }
2794 };
2795
2796 /**
2797  * The default drag frame div id
2798  * @property Ext.dd.DDProxy.dragElId
2799  * @type String
2800  * @static
2801  */
2802 Ext.dd.DDProxy.dragElId = "ygddfdiv";
2803
2804 Ext.extend(Ext.dd.DDProxy, Ext.dd.DD, {
2805
2806     /**
2807      * By default we resize the drag frame to be the same size as the element
2808      * we want to drag (this is to get the frame effect).  We can turn it off
2809      * if we want a different behavior.
2810      * @property resizeFrame
2811      * @type boolean
2812      */
2813     resizeFrame: true,
2814
2815     /**
2816      * By default the frame is positioned exactly where the drag element is, so
2817      * we use the cursor offset provided by Ext.dd.DD.  Another option that works only if
2818      * you do not have constraints on the obj is to have the drag frame centered
2819      * around the cursor.  Set centerFrame to true for this effect.
2820      * @property centerFrame
2821      * @type boolean
2822      */
2823     centerFrame: false,
2824
2825     /**
2826      * Creates the proxy element if it does not yet exist
2827      * @method createFrame
2828      */
2829     createFrame: function() {
2830         var self = this;
2831         var body = document.body;
2832
2833         if (!body || !body.firstChild) {
2834             setTimeout( function() { self.createFrame(); }, 50 );
2835             return;
2836         }
2837
2838         var div = this.getDragEl();
2839
2840         if (!div) {
2841             div    = document.createElement("div");
2842             div.id = this.dragElId;
2843             var s  = div.style;
2844
2845             s.position   = "absolute";
2846             s.visibility = "hidden";
2847             s.cursor     = "move";
2848             s.border     = "2px solid #aaa";
2849             s.zIndex     = 999;
2850
2851             // appendChild can blow up IE if invoked prior to the window load event
2852             // while rendering a table.  It is possible there are other scenarios
2853             // that would cause this to happen as well.
2854             body.insertBefore(div, body.firstChild);
2855         }
2856     },
2857
2858     /**
2859      * Initialization for the drag frame element.  Must be called in the
2860      * constructor of all subclasses
2861      * @method initFrame
2862      */
2863     initFrame: function() {
2864         this.createFrame();
2865     },
2866
2867     applyConfig: function() {
2868         Ext.dd.DDProxy.superclass.applyConfig.call(this);
2869
2870         this.resizeFrame = (this.config.resizeFrame !== false);
2871         this.centerFrame = (this.config.centerFrame);
2872         this.setDragElId(this.config.dragElId || Ext.dd.DDProxy.dragElId);
2873     },
2874
2875     /**
2876      * Resizes the drag frame to the dimensions of the clicked object, positions
2877      * it over the object, and finally displays it
2878      * @method showFrame
2879      * @param {int} iPageX X click position
2880      * @param {int} iPageY Y click position
2881      * @private
2882      */
2883     showFrame: function(iPageX, iPageY) {
2884         var el = this.getEl();
2885         var dragEl = this.getDragEl();
2886         var s = dragEl.style;
2887
2888         this._resizeProxy();
2889
2890         if (this.centerFrame) {
2891             this.setDelta( Math.round(parseInt(s.width,  10)/2),
2892                            Math.round(parseInt(s.height, 10)/2) );
2893         }
2894
2895         this.setDragElPos(iPageX, iPageY);
2896
2897         Ext.fly(dragEl).show();
2898     },
2899
2900     /**
2901      * The proxy is automatically resized to the dimensions of the linked
2902      * element when a drag is initiated, unless resizeFrame is set to false
2903      * @method _resizeProxy
2904      * @private
2905      */
2906     _resizeProxy: function() {
2907         if (this.resizeFrame) {
2908             var el = this.getEl();
2909             Ext.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2910         }
2911     },
2912
2913     // overrides Ext.dd.DragDrop
2914     b4MouseDown: function(e) {
2915         var x = e.getPageX();
2916         var y = e.getPageY();
2917         this.autoOffset(x, y);
2918         this.setDragElPos(x, y);
2919     },
2920
2921     // overrides Ext.dd.DragDrop
2922     b4StartDrag: function(x, y) {
2923         // show the drag frame
2924         this.showFrame(x, y);
2925     },
2926
2927     // overrides Ext.dd.DragDrop
2928     b4EndDrag: function(e) {
2929         Ext.fly(this.getDragEl()).hide();
2930     },
2931
2932     // overrides Ext.dd.DragDrop
2933     // By default we try to move the element to the last location of the frame.
2934     // This is so that the default behavior mirrors that of Ext.dd.DD.
2935     endDrag: function(e) {
2936
2937         var lel = this.getEl();
2938         var del = this.getDragEl();
2939
2940         // Show the drag frame briefly so we can get its position
2941         del.style.visibility = "";
2942
2943         this.beforeMove();
2944         // Hide the linked element before the move to get around a Safari
2945         // rendering bug.
2946         lel.style.visibility = "hidden";
2947         Ext.dd.DDM.moveToEl(lel, del);
2948         del.style.visibility = "hidden";
2949         lel.style.visibility = "";
2950
2951         this.afterDrag();
2952     },
2953
2954     beforeMove : function(){
2955
2956     },
2957
2958     afterDrag : function(){
2959
2960     },
2961
2962     toString: function() {
2963         return ("DDProxy " + this.id);
2964     }
2965
2966 });
2967 /**
2968  * @class Ext.dd.DDTarget
2969  * A DragDrop implementation that does not move, but can be a drop
2970  * target.  You would get the same result by simply omitting implementation
2971  * for the event callbacks, but this way we reduce the processing cost of the
2972  * event listener and the callbacks.
2973  * @extends Ext.dd.DragDrop
2974  * @constructor
2975  * @param {String} id the id of the element that is a drop target
2976  * @param {String} sGroup the group of related DragDrop objects
2977  * @param {object} config an object containing configurable attributes
2978  *                 Valid properties for DDTarget in addition to those in
2979  *                 DragDrop:
2980  *                    none
2981  */
2982 Ext.dd.DDTarget = function(id, sGroup, config) {
2983     if (id) {
2984         this.initTarget(id, sGroup, config);
2985     }
2986 };
2987
2988 // Ext.dd.DDTarget.prototype = new Ext.dd.DragDrop();
2989 Ext.extend(Ext.dd.DDTarget, Ext.dd.DragDrop, {
2990     /**
2991      * @hide
2992      * Overridden and disabled. A DDTarget does not support being dragged.
2993      * @method
2994      */
2995     getDragEl: Ext.emptyFn,
2996     /**
2997      * @hide
2998      * Overridden and disabled. A DDTarget does not support being dragged.
2999      * @method
3000      */
3001     isValidHandleChild: Ext.emptyFn,
3002     /**
3003      * @hide
3004      * Overridden and disabled. A DDTarget does not support being dragged.
3005      * @method
3006      */
3007     startDrag: Ext.emptyFn,
3008     /**
3009      * @hide
3010      * Overridden and disabled. A DDTarget does not support being dragged.
3011      * @method
3012      */
3013     endDrag: Ext.emptyFn,
3014     /**
3015      * @hide
3016      * Overridden and disabled. A DDTarget does not support being dragged.
3017      * @method
3018      */
3019     onDrag: Ext.emptyFn,
3020     /**
3021      * @hide
3022      * Overridden and disabled. A DDTarget does not support being dragged.
3023      * @method
3024      */
3025     onDragDrop: Ext.emptyFn,
3026     /**
3027      * @hide
3028      * Overridden and disabled. A DDTarget does not support being dragged.
3029      * @method
3030      */
3031     onDragEnter: Ext.emptyFn,
3032     /**
3033      * @hide
3034      * Overridden and disabled. A DDTarget does not support being dragged.
3035      * @method
3036      */
3037     onDragOut: Ext.emptyFn,
3038     /**
3039      * @hide
3040      * Overridden and disabled. A DDTarget does not support being dragged.
3041      * @method
3042      */
3043     onDragOver: Ext.emptyFn,
3044     /**
3045      * @hide
3046      * Overridden and disabled. A DDTarget does not support being dragged.
3047      * @method
3048      */
3049     onInvalidDrop: Ext.emptyFn,
3050     /**
3051      * @hide
3052      * Overridden and disabled. A DDTarget does not support being dragged.
3053      * @method
3054      */
3055     onMouseDown: Ext.emptyFn,
3056     /**
3057      * @hide
3058      * Overridden and disabled. A DDTarget does not support being dragged.
3059      * @method
3060      */
3061     onMouseUp: Ext.emptyFn,
3062     /**
3063      * @hide
3064      * Overridden and disabled. A DDTarget does not support being dragged.
3065      * @method
3066      */
3067     setXConstraint: Ext.emptyFn,
3068     /**
3069      * @hide
3070      * Overridden and disabled. A DDTarget does not support being dragged.
3071      * @method
3072      */
3073     setYConstraint: Ext.emptyFn,
3074     /**
3075      * @hide
3076      * Overridden and disabled. A DDTarget does not support being dragged.
3077      * @method
3078      */
3079     resetConstraints: Ext.emptyFn,
3080     /**
3081      * @hide
3082      * Overridden and disabled. A DDTarget does not support being dragged.
3083      * @method
3084      */
3085     clearConstraints: Ext.emptyFn,
3086     /**
3087      * @hide
3088      * Overridden and disabled. A DDTarget does not support being dragged.
3089      * @method
3090      */
3091     clearTicks: Ext.emptyFn,
3092     /**
3093      * @hide
3094      * Overridden and disabled. A DDTarget does not support being dragged.
3095      * @method
3096      */
3097     setInitPosition: Ext.emptyFn,
3098     /**
3099      * @hide
3100      * Overridden and disabled. A DDTarget does not support being dragged.
3101      * @method
3102      */
3103     setDragElId: Ext.emptyFn,
3104     /**
3105      * @hide
3106      * Overridden and disabled. A DDTarget does not support being dragged.
3107      * @method
3108      */
3109     setHandleElId: Ext.emptyFn,
3110     /**
3111      * @hide
3112      * Overridden and disabled. A DDTarget does not support being dragged.
3113      * @method
3114      */
3115     setOuterHandleElId: Ext.emptyFn,
3116     /**
3117      * @hide
3118      * Overridden and disabled. A DDTarget does not support being dragged.
3119      * @method
3120      */
3121     addInvalidHandleClass: Ext.emptyFn,
3122     /**
3123      * @hide
3124      * Overridden and disabled. A DDTarget does not support being dragged.
3125      * @method
3126      */
3127     addInvalidHandleId: Ext.emptyFn,
3128     /**
3129      * @hide
3130      * Overridden and disabled. A DDTarget does not support being dragged.
3131      * @method
3132      */
3133     addInvalidHandleType: Ext.emptyFn,
3134     /**
3135      * @hide
3136      * Overridden and disabled. A DDTarget does not support being dragged.
3137      * @method
3138      */
3139     removeInvalidHandleClass: Ext.emptyFn,
3140     /**
3141      * @hide
3142      * Overridden and disabled. A DDTarget does not support being dragged.
3143      * @method
3144      */
3145     removeInvalidHandleId: Ext.emptyFn,
3146     /**
3147      * @hide
3148      * Overridden and disabled. A DDTarget does not support being dragged.
3149      * @method
3150      */
3151     removeInvalidHandleType: Ext.emptyFn,
3152
3153     toString: function() {
3154         return ("DDTarget " + this.id);
3155     }
3156 });/**\r
3157  * @class Ext.dd.DragTracker\r
3158  * @extends Ext.util.Observable\r
3159  */\r
3160 Ext.dd.DragTracker = Ext.extend(Ext.util.Observable,  {\r
3161     /**\r
3162      * @cfg {Boolean} active\r
3163          * Defaults to <tt>false</tt>.\r
3164          */     \r
3165     active: false,\r
3166     /**\r
3167      * @cfg {Number} tolerance\r
3168          * Defaults to <tt>5</tt>.\r
3169          */     \r
3170     tolerance: 5,\r
3171     /**\r
3172      * @cfg {Boolean/Number} autoStart\r
3173          * Defaults to <tt>false</tt>. Specify <tt>true</tt> to defer trigger start by 1000 ms.\r
3174          * Specify a Number for the number of milliseconds to defer trigger start.\r
3175          */     \r
3176     autoStart: false,\r
3177     \r
3178     constructor : function(config){\r
3179         Ext.apply(this, config);\r
3180             this.addEvents(\r
3181                 /**\r
3182                  * @event mousedown\r
3183                  * @param {Object} this\r
3184                  * @param {Object} e event object\r
3185                  */\r
3186                 'mousedown',\r
3187                 /**\r
3188                  * @event mouseup\r
3189                  * @param {Object} this\r
3190                  * @param {Object} e event object\r
3191                  */\r
3192                 'mouseup',\r
3193                 /**\r
3194                  * @event mousemove\r
3195                  * @param {Object} this\r
3196                  * @param {Object} e event object\r
3197                  */\r
3198                 'mousemove',\r
3199                 /**\r
3200                  * @event dragstart\r
3201                  * @param {Object} this\r
3202                  * @param {Object} startXY the page coordinates of the event\r
3203                  */\r
3204                 'dragstart',\r
3205                 /**\r
3206                  * @event dragend\r
3207                  * @param {Object} this\r
3208                  * @param {Object} e event object\r
3209                  */\r
3210                 'dragend',\r
3211                 /**\r
3212                  * @event drag\r
3213                  * @param {Object} this\r
3214                  * @param {Object} e event object\r
3215                  */\r
3216                 'drag'\r
3217             );\r
3218         \r
3219             this.dragRegion = new Ext.lib.Region(0,0,0,0);\r
3220         \r
3221             if(this.el){\r
3222                 this.initEl(this.el);\r
3223             }\r
3224         Ext.dd.DragTracker.superclass.constructor.call(this, config);\r
3225     },\r
3226 \r
3227     initEl: function(el){\r
3228         this.el = Ext.get(el);\r
3229         el.on('mousedown', this.onMouseDown, this,\r
3230                 this.delegate ? {delegate: this.delegate} : undefined);\r
3231     },\r
3232 \r
3233     destroy : function(){\r
3234         this.el.un('mousedown', this.onMouseDown, this);\r
3235     },\r
3236 \r
3237     onMouseDown: function(e, target){\r
3238         if(this.fireEvent('mousedown', this, e) !== false && this.onBeforeStart(e) !== false){\r
3239             this.startXY = this.lastXY = e.getXY();\r
3240             this.dragTarget = this.delegate ? target : this.el.dom;\r
3241             if(this.preventDefault !== false){\r
3242                 e.preventDefault();\r
3243             }\r
3244             var doc = Ext.getDoc();\r
3245             doc.on('mouseup', this.onMouseUp, this);\r
3246             doc.on('mousemove', this.onMouseMove, this);\r
3247             doc.on('selectstart', this.stopSelect, this);\r
3248             if(this.autoStart){\r
3249                 this.timer = this.triggerStart.defer(this.autoStart === true ? 1000 : this.autoStart, this);\r
3250             }\r
3251         }\r
3252     },\r
3253 \r
3254     onMouseMove: function(e, target){\r
3255         // HACK: IE hack to see if button was released outside of window. */\r
3256         if(this.active && Ext.isIE && !e.browserEvent.button){\r
3257             e.preventDefault();\r
3258             this.onMouseUp(e);\r
3259             return;\r
3260         }\r
3261 \r
3262         e.preventDefault();\r
3263         var xy = e.getXY(), s = this.startXY;\r
3264         this.lastXY = xy;\r
3265         if(!this.active){\r
3266             if(Math.abs(s[0]-xy[0]) > this.tolerance || Math.abs(s[1]-xy[1]) > this.tolerance){\r
3267                 this.triggerStart();\r
3268             }else{\r
3269                 return;\r
3270             }\r
3271         }\r
3272         this.fireEvent('mousemove', this, e);\r
3273         this.onDrag(e);\r
3274         this.fireEvent('drag', this, e);\r
3275     },\r
3276 \r
3277     onMouseUp: function(e){\r
3278         var doc = Ext.getDoc();\r
3279         doc.un('mousemove', this.onMouseMove, this);\r
3280         doc.un('mouseup', this.onMouseUp, this);\r
3281         doc.un('selectstart', this.stopSelect, this);\r
3282         e.preventDefault();\r
3283         this.clearStart();\r
3284         var wasActive = this.active;\r
3285         this.active = false;\r
3286         delete this.elRegion;\r
3287         this.fireEvent('mouseup', this, e);\r
3288         if(wasActive){\r
3289             this.onEnd(e);\r
3290             this.fireEvent('dragend', this, e);\r
3291         }\r
3292     },\r
3293 \r
3294     triggerStart: function(isTimer){\r
3295         this.clearStart();\r
3296         this.active = true;\r
3297         this.onStart(this.startXY);\r
3298         this.fireEvent('dragstart', this, this.startXY);\r
3299     },\r
3300 \r
3301     clearStart : function(){\r
3302         if(this.timer){\r
3303             clearTimeout(this.timer);\r
3304             delete this.timer;\r
3305         }\r
3306     },\r
3307 \r
3308     stopSelect : function(e){\r
3309         e.stopEvent();\r
3310         return false;\r
3311     },\r
3312 \r
3313     onBeforeStart : function(e){\r
3314 \r
3315     },\r
3316 \r
3317     onStart : function(xy){\r
3318 \r
3319     },\r
3320 \r
3321     onDrag : function(e){\r
3322 \r
3323     },\r
3324 \r
3325     onEnd : function(e){\r
3326 \r
3327     },\r
3328 \r
3329     getDragTarget : function(){\r
3330         return this.dragTarget;\r
3331     },\r
3332 \r
3333     getDragCt : function(){\r
3334         return this.el;\r
3335     },\r
3336 \r
3337     getXY : function(constrain){\r
3338         return constrain ?\r
3339                this.constrainModes[constrain].call(this, this.lastXY) : this.lastXY;\r
3340     },\r
3341 \r
3342     getOffset : function(constrain){\r
3343         var xy = this.getXY(constrain);\r
3344         var s = this.startXY;\r
3345         return [s[0]-xy[0], s[1]-xy[1]];\r
3346     },\r
3347 \r
3348     constrainModes: {\r
3349         'point' : function(xy){\r
3350 \r
3351             if(!this.elRegion){\r
3352                 this.elRegion = this.getDragCt().getRegion();\r
3353             }\r
3354 \r
3355             var dr = this.dragRegion;\r
3356 \r
3357             dr.left = xy[0];\r
3358             dr.top = xy[1];\r
3359             dr.right = xy[0];\r
3360             dr.bottom = xy[1];\r
3361 \r
3362             dr.constrainTo(this.elRegion);\r
3363 \r
3364             return [dr.left, dr.top];\r
3365         }\r
3366     }\r
3367 });/**\r
3368  * @class Ext.dd.ScrollManager\r
3369  * <p>Provides automatic scrolling of overflow regions in the page during drag operations.</p>\r
3370  * <p>The ScrollManager configs will be used as the defaults for any scroll container registered with it,\r
3371  * but you can also override most of the configs per scroll container by adding a \r
3372  * <tt>ddScrollConfig</tt> object to the target element that contains these properties: {@link #hthresh},\r
3373  * {@link #vthresh}, {@link #increment} and {@link #frequency}.  Example usage:\r
3374  * <pre><code>\r
3375 var el = Ext.get('scroll-ct');\r
3376 el.ddScrollConfig = {\r
3377     vthresh: 50,\r
3378     hthresh: -1,\r
3379     frequency: 100,\r
3380     increment: 200\r
3381 };\r
3382 Ext.dd.ScrollManager.register(el);\r
3383 </code></pre>\r
3384  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>\r
3385  * @singleton\r
3386  */\r
3387 Ext.dd.ScrollManager = function(){\r
3388     var ddm = Ext.dd.DragDropMgr;\r
3389     var els = {};\r
3390     var dragEl = null;\r
3391     var proc = {};\r
3392     \r
3393     var onStop = function(e){\r
3394         dragEl = null;\r
3395         clearProc();\r
3396     };\r
3397     \r
3398     var triggerRefresh = function(){\r
3399         if(ddm.dragCurrent){\r
3400              ddm.refreshCache(ddm.dragCurrent.groups);\r
3401         }\r
3402     };\r
3403     \r
3404     var doScroll = function(){\r
3405         if(ddm.dragCurrent){\r
3406             var dds = Ext.dd.ScrollManager;\r
3407             var inc = proc.el.ddScrollConfig ?\r
3408                       proc.el.ddScrollConfig.increment : dds.increment;\r
3409             if(!dds.animate){\r
3410                 if(proc.el.scroll(proc.dir, inc)){\r
3411                     triggerRefresh();\r
3412                 }\r
3413             }else{\r
3414                 proc.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh);\r
3415             }\r
3416         }\r
3417     };\r
3418     \r
3419     var clearProc = function(){\r
3420         if(proc.id){\r
3421             clearInterval(proc.id);\r
3422         }\r
3423         proc.id = 0;\r
3424         proc.el = null;\r
3425         proc.dir = "";\r
3426     };\r
3427     \r
3428     var startProc = function(el, dir){\r
3429         clearProc();\r
3430         proc.el = el;\r
3431         proc.dir = dir;\r
3432         var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ? \r
3433                 el.ddScrollConfig.frequency : Ext.dd.ScrollManager.frequency;\r
3434         proc.id = setInterval(doScroll, freq);\r
3435     };\r
3436     \r
3437     var onFire = function(e, isDrop){\r
3438         if(isDrop || !ddm.dragCurrent){ return; }\r
3439         var dds = Ext.dd.ScrollManager;\r
3440         if(!dragEl || dragEl != ddm.dragCurrent){\r
3441             dragEl = ddm.dragCurrent;\r
3442             // refresh regions on drag start\r
3443             dds.refreshCache();\r
3444         }\r
3445         \r
3446         var xy = Ext.lib.Event.getXY(e);\r
3447         var pt = new Ext.lib.Point(xy[0], xy[1]);\r
3448         for(var id in els){\r
3449             var el = els[id], r = el._region;\r
3450             var c = el.ddScrollConfig ? el.ddScrollConfig : dds;\r
3451             if(r && r.contains(pt) && el.isScrollable()){\r
3452                 if(r.bottom - pt.y <= c.vthresh){\r
3453                     if(proc.el != el){\r
3454                         startProc(el, "down");\r
3455                     }\r
3456                     return;\r
3457                 }else if(r.right - pt.x <= c.hthresh){\r
3458                     if(proc.el != el){\r
3459                         startProc(el, "left");\r
3460                     }\r
3461                     return;\r
3462                 }else if(pt.y - r.top <= c.vthresh){\r
3463                     if(proc.el != el){\r
3464                         startProc(el, "up");\r
3465                     }\r
3466                     return;\r
3467                 }else if(pt.x - r.left <= c.hthresh){\r
3468                     if(proc.el != el){\r
3469                         startProc(el, "right");\r
3470                     }\r
3471                     return;\r
3472                 }\r
3473             }\r
3474         }\r
3475         clearProc();\r
3476     };\r
3477     \r
3478     ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);\r
3479     ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);\r
3480     \r
3481     return {\r
3482         /**\r
3483          * Registers new overflow element(s) to auto scroll\r
3484          * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either\r
3485          */\r
3486         register : function(el){\r
3487             if(Ext.isArray(el)){\r
3488                 for(var i = 0, len = el.length; i < len; i++) {\r
3489                         this.register(el[i]);\r
3490                 }\r
3491             }else{\r
3492                 el = Ext.get(el);\r
3493                 els[el.id] = el;\r
3494             }\r
3495         },\r
3496         \r
3497         /**\r
3498          * Unregisters overflow element(s) so they are no longer scrolled\r
3499          * @param {Mixed/Array} el The id of or the element to be removed or an array of either\r
3500          */\r
3501         unregister : function(el){\r
3502             if(Ext.isArray(el)){\r
3503                 for(var i = 0, len = el.length; i < len; i++) {\r
3504                         this.unregister(el[i]);\r
3505                 }\r
3506             }else{\r
3507                 el = Ext.get(el);\r
3508                 delete els[el.id];\r
3509             }\r
3510         },\r
3511         \r
3512         /**\r
3513          * The number of pixels from the top or bottom edge of a container the pointer needs to be to\r
3514          * trigger scrolling (defaults to 25)\r
3515          * @type Number\r
3516          */\r
3517         vthresh : 25,\r
3518         /**\r
3519          * The number of pixels from the right or left edge of a container the pointer needs to be to\r
3520          * trigger scrolling (defaults to 25)\r
3521          * @type Number\r
3522          */\r
3523         hthresh : 25,\r
3524 \r
3525         /**\r
3526          * The number of pixels to scroll in each scroll increment (defaults to 50)\r
3527          * @type Number\r
3528          */\r
3529         increment : 100,\r
3530         \r
3531         /**\r
3532          * The frequency of scrolls in milliseconds (defaults to 500)\r
3533          * @type Number\r
3534          */\r
3535         frequency : 500,\r
3536         \r
3537         /**\r
3538          * True to animate the scroll (defaults to true)\r
3539          * @type Boolean\r
3540          */\r
3541         animate: true,\r
3542         \r
3543         /**\r
3544          * The animation duration in seconds - \r
3545          * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4)\r
3546          * @type Number\r
3547          */\r
3548         animDuration: .4,\r
3549         \r
3550         /**\r
3551          * Manually trigger a cache refresh.\r
3552          */\r
3553         refreshCache : function(){\r
3554             for(var id in els){\r
3555                 if(typeof els[id] == 'object'){ // for people extending the object prototype\r
3556                     els[id]._region = els[id].getRegion();\r
3557                 }\r
3558             }\r
3559         }\r
3560     };\r
3561 }();/**\r
3562  * @class Ext.dd.Registry\r
3563  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either\r
3564  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.\r
3565  * @singleton\r
3566  */\r
3567 Ext.dd.Registry = function(){\r
3568     var elements = {}; \r
3569     var handles = {}; \r
3570     var autoIdSeed = 0;\r
3571 \r
3572     var getId = function(el, autogen){\r
3573         if(typeof el == "string"){\r
3574             return el;\r
3575         }\r
3576         var id = el.id;\r
3577         if(!id && autogen !== false){\r
3578             id = "extdd-" + (++autoIdSeed);\r
3579             el.id = id;\r
3580         }\r
3581         return id;\r
3582     };\r
3583     \r
3584     return {\r
3585     /**\r
3586      * Resgister a drag drop element\r
3587      * @param {String/HTMLElement) element The id or DOM node to register\r
3588      * @param {Object} data (optional) An custom data object that will be passed between the elements that are involved\r
3589      * in drag drop operations.  You can populate this object with any arbitrary properties that your own code\r
3590      * knows how to interpret, plus there are some specific properties known to the Registry that should be\r
3591      * populated in the data object (if applicable):\r
3592      * <pre>\r
3593 Value      Description<br />\r
3594 ---------  ------------------------------------------<br />\r
3595 handles    Array of DOM nodes that trigger dragging<br />\r
3596            for the element being registered<br />\r
3597 isHandle   True if the element passed in triggers<br />\r
3598            dragging itself, else false\r
3599 </pre>\r
3600      */\r
3601         register : function(el, data){\r
3602             data = data || {};\r
3603             if(typeof el == "string"){\r
3604                 el = document.getElementById(el);\r
3605             }\r
3606             data.ddel = el;\r
3607             elements[getId(el)] = data;\r
3608             if(data.isHandle !== false){\r
3609                 handles[data.ddel.id] = data;\r
3610             }\r
3611             if(data.handles){\r
3612                 var hs = data.handles;\r
3613                 for(var i = 0, len = hs.length; i < len; i++){\r
3614                         handles[getId(hs[i])] = data;\r
3615                 }\r
3616             }\r
3617         },\r
3618 \r
3619     /**\r
3620      * Unregister a drag drop element\r
3621      * @param {String/HTMLElement) element The id or DOM node to unregister\r
3622      */\r
3623         unregister : function(el){\r
3624             var id = getId(el, false);\r
3625             var data = elements[id];\r
3626             if(data){\r
3627                 delete elements[id];\r
3628                 if(data.handles){\r
3629                     var hs = data.handles;\r
3630                     for(var i = 0, len = hs.length; i < len; i++){\r
3631                         delete handles[getId(hs[i], false)];\r
3632                     }\r
3633                 }\r
3634             }\r
3635         },\r
3636 \r
3637     /**\r
3638      * Returns the handle registered for a DOM Node by id\r
3639      * @param {String/HTMLElement} id The DOM node or id to look up\r
3640      * @return {Object} handle The custom handle data\r
3641      */\r
3642         getHandle : function(id){\r
3643             if(typeof id != "string"){ // must be element?\r
3644                 id = id.id;\r
3645             }\r
3646             return handles[id];\r
3647         },\r
3648 \r
3649     /**\r
3650      * Returns the handle that is registered for the DOM node that is the target of the event\r
3651      * @param {Event} e The event\r
3652      * @return {Object} handle The custom handle data\r
3653      */\r
3654         getHandleFromEvent : function(e){\r
3655             var t = Ext.lib.Event.getTarget(e);\r
3656             return t ? handles[t.id] : null;\r
3657         },\r
3658 \r
3659     /**\r
3660      * Returns a custom data object that is registered for a DOM node by id\r
3661      * @param {String/HTMLElement} id The DOM node or id to look up\r
3662      * @return {Object} data The custom data\r
3663      */\r
3664         getTarget : function(id){\r
3665             if(typeof id != "string"){ // must be element?\r
3666                 id = id.id;\r
3667             }\r
3668             return elements[id];\r
3669         },\r
3670 \r
3671     /**\r
3672      * Returns a custom data object that is registered for the DOM node that is the target of the event\r
3673      * @param {Event} e The event\r
3674      * @return {Object} data The custom data\r
3675      */\r
3676         getTargetFromEvent : function(e){\r
3677             var t = Ext.lib.Event.getTarget(e);\r
3678             return t ? elements[t.id] || handles[t.id] : null;\r
3679         }\r
3680     };\r
3681 }();/**\r
3682  * @class Ext.dd.StatusProxy\r
3683  * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair.  This is the\r
3684  * default drag proxy used by all Ext.dd components.\r
3685  * @constructor\r
3686  * @param {Object} config\r
3687  */\r
3688 Ext.dd.StatusProxy = function(config){\r
3689     Ext.apply(this, config);\r
3690     this.id = this.id || Ext.id();\r
3691     this.el = new Ext.Layer({\r
3692         dh: {\r
3693             id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [\r
3694                 {tag: "div", cls: "x-dd-drop-icon"},\r
3695                 {tag: "div", cls: "x-dd-drag-ghost"}\r
3696             ]\r
3697         }, \r
3698         shadow: !config || config.shadow !== false\r
3699     });\r
3700     this.ghost = Ext.get(this.el.dom.childNodes[1]);\r
3701     this.dropStatus = this.dropNotAllowed;\r
3702 };\r
3703 \r
3704 Ext.dd.StatusProxy.prototype = {\r
3705     /**\r
3706      * @cfg {String} dropAllowed\r
3707      * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").\r
3708      */\r
3709     dropAllowed : "x-dd-drop-ok",\r
3710     /**\r
3711      * @cfg {String} dropNotAllowed\r
3712      * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
3713      */\r
3714     dropNotAllowed : "x-dd-drop-nodrop",\r
3715 \r
3716     /**\r
3717      * Updates the proxy's visual element to indicate the status of whether or not drop is allowed\r
3718      * over the current target element.\r
3719      * @param {String} cssClass The css class for the new drop status indicator image\r
3720      */\r
3721     setStatus : function(cssClass){\r
3722         cssClass = cssClass || this.dropNotAllowed;\r
3723         if(this.dropStatus != cssClass){\r
3724             this.el.replaceClass(this.dropStatus, cssClass);\r
3725             this.dropStatus = cssClass;\r
3726         }\r
3727     },\r
3728 \r
3729     /**\r
3730      * Resets the status indicator to the default dropNotAllowed value\r
3731      * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it\r
3732      */\r
3733     reset : function(clearGhost){\r
3734         this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;\r
3735         this.dropStatus = this.dropNotAllowed;\r
3736         if(clearGhost){\r
3737             this.ghost.update("");\r
3738         }\r
3739     },\r
3740 \r
3741     /**\r
3742      * Updates the contents of the ghost element\r
3743      * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a\r
3744      * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).\r
3745      */\r
3746     update : function(html){\r
3747         if(typeof html == "string"){\r
3748             this.ghost.update(html);\r
3749         }else{\r
3750             this.ghost.update("");\r
3751             html.style.margin = "0";\r
3752             this.ghost.dom.appendChild(html);\r
3753         }\r
3754         var el = this.ghost.dom.firstChild; \r
3755         if(el){\r
3756             Ext.fly(el).setStyle('float', 'none');\r
3757         }\r
3758     },\r
3759 \r
3760     /**\r
3761      * Returns the underlying proxy {@link Ext.Layer}\r
3762      * @return {Ext.Layer} el\r
3763     */\r
3764     getEl : function(){\r
3765         return this.el;\r
3766     },\r
3767 \r
3768     /**\r
3769      * Returns the ghost element\r
3770      * @return {Ext.Element} el\r
3771      */\r
3772     getGhost : function(){\r
3773         return this.ghost;\r
3774     },\r
3775 \r
3776     /**\r
3777      * Hides the proxy\r
3778      * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them\r
3779      */\r
3780     hide : function(clear){\r
3781         this.el.hide();\r
3782         if(clear){\r
3783             this.reset(true);\r
3784         }\r
3785     },\r
3786 \r
3787     /**\r
3788      * Stops the repair animation if it's currently running\r
3789      */\r
3790     stop : function(){\r
3791         if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){\r
3792             this.anim.stop();\r
3793         }\r
3794     },\r
3795 \r
3796     /**\r
3797      * Displays this proxy\r
3798      */\r
3799     show : function(){\r
3800         this.el.show();\r
3801     },\r
3802 \r
3803     /**\r
3804      * Force the Layer to sync its shadow and shim positions to the element\r
3805      */\r
3806     sync : function(){\r
3807         this.el.sync();\r
3808     },\r
3809 \r
3810     /**\r
3811      * Causes the proxy to return to its position of origin via an animation.  Should be called after an\r
3812      * invalid drop operation by the item being dragged.\r
3813      * @param {Array} xy The XY position of the element ([x, y])\r
3814      * @param {Function} callback The function to call after the repair is complete.\r
3815      * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.\r
3816      */\r
3817     repair : function(xy, callback, scope){\r
3818         this.callback = callback;\r
3819         this.scope = scope;\r
3820         if(xy && this.animRepair !== false){\r
3821             this.el.addClass("x-dd-drag-repair");\r
3822             this.el.hideUnders(true);\r
3823             this.anim = this.el.shift({\r
3824                 duration: this.repairDuration || .5,\r
3825                 easing: 'easeOut',\r
3826                 xy: xy,\r
3827                 stopFx: true,\r
3828                 callback: this.afterRepair,\r
3829                 scope: this\r
3830             });\r
3831         }else{\r
3832             this.afterRepair();\r
3833         }\r
3834     },\r
3835 \r
3836     // private\r
3837     afterRepair : function(){\r
3838         this.hide(true);\r
3839         if(typeof this.callback == "function"){\r
3840             this.callback.call(this.scope || this);\r
3841         }\r
3842         this.callback = null;\r
3843         this.scope = null;\r
3844     },\r
3845     \r
3846     destroy: function(){\r
3847         Ext.destroy(this.ghost, this.el);    \r
3848     }\r
3849 };/**\r
3850  * @class Ext.dd.DragSource\r
3851  * @extends Ext.dd.DDProxy\r
3852  * A simple class that provides the basic implementation needed to make any element draggable.\r
3853  * @constructor\r
3854  * @param {Mixed} el The container element\r
3855  * @param {Object} config\r
3856  */\r
3857 Ext.dd.DragSource = function(el, config){\r
3858     this.el = Ext.get(el);\r
3859     if(!this.dragData){\r
3860         this.dragData = {};\r
3861     }\r
3862     \r
3863     Ext.apply(this, config);\r
3864     \r
3865     if(!this.proxy){\r
3866         this.proxy = new Ext.dd.StatusProxy();\r
3867     }\r
3868     Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, \r
3869           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});\r
3870     \r
3871     this.dragging = false;\r
3872 };\r
3873 \r
3874 Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {\r
3875     /**\r
3876      * @cfg {String} ddGroup\r
3877      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only\r
3878      * interact with other drag drop objects in the same group (defaults to undefined).\r
3879      */\r
3880     /**\r
3881      * @cfg {String} dropAllowed\r
3882      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").\r
3883      */\r
3884     dropAllowed : "x-dd-drop-ok",\r
3885     /**\r
3886      * @cfg {String} dropNotAllowed\r
3887      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
3888      */\r
3889     dropNotAllowed : "x-dd-drop-nodrop",\r
3890 \r
3891     /**\r
3892      * Returns the data object associated with this drag source\r
3893      * @return {Object} data An object containing arbitrary data\r
3894      */\r
3895     getDragData : function(e){\r
3896         return this.dragData;\r
3897     },\r
3898 \r
3899     // private\r
3900     onDragEnter : function(e, id){\r
3901         var target = Ext.dd.DragDropMgr.getDDById(id);\r
3902         this.cachedTarget = target;\r
3903         if(this.beforeDragEnter(target, e, id) !== false){\r
3904             if(target.isNotifyTarget){\r
3905                 var status = target.notifyEnter(this, e, this.dragData);\r
3906                 this.proxy.setStatus(status);\r
3907             }else{\r
3908                 this.proxy.setStatus(this.dropAllowed);\r
3909             }\r
3910             \r
3911             if(this.afterDragEnter){\r
3912                 /**\r
3913                  * An empty function by default, but provided so that you can perform a custom action\r
3914                  * when the dragged item enters the drop target by providing an implementation.\r
3915                  * @param {Ext.dd.DragDrop} target The drop target\r
3916                  * @param {Event} e The event object\r
3917                  * @param {String} id The id of the dragged element\r
3918                  * @method afterDragEnter\r
3919                  */\r
3920                 this.afterDragEnter(target, e, id);\r
3921             }\r
3922         }\r
3923     },\r
3924 \r
3925     /**\r
3926      * An empty function by default, but provided so that you can perform a custom action\r
3927      * before the dragged item enters the drop target and optionally cancel the onDragEnter.\r
3928      * @param {Ext.dd.DragDrop} target The drop target\r
3929      * @param {Event} e The event object\r
3930      * @param {String} id The id of the dragged element\r
3931      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
3932      */\r
3933     beforeDragEnter : function(target, e, id){\r
3934         return true;\r
3935     },\r
3936 \r
3937     // private\r
3938     alignElWithMouse: function() {\r
3939         Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);\r
3940         this.proxy.sync();\r
3941     },\r
3942 \r
3943     // private\r
3944     onDragOver : function(e, id){\r
3945         var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
3946         if(this.beforeDragOver(target, e, id) !== false){\r
3947             if(target.isNotifyTarget){\r
3948                 var status = target.notifyOver(this, e, this.dragData);\r
3949                 this.proxy.setStatus(status);\r
3950             }\r
3951 \r
3952             if(this.afterDragOver){\r
3953                 /**\r
3954                  * An empty function by default, but provided so that you can perform a custom action\r
3955                  * while the dragged item is over the drop target by providing an implementation.\r
3956                  * @param {Ext.dd.DragDrop} target The drop target\r
3957                  * @param {Event} e The event object\r
3958                  * @param {String} id The id of the dragged element\r
3959                  * @method afterDragOver\r
3960                  */\r
3961                 this.afterDragOver(target, e, id);\r
3962             }\r
3963         }\r
3964     },\r
3965 \r
3966     /**\r
3967      * An empty function by default, but provided so that you can perform a custom action\r
3968      * while the dragged item is over the drop target and optionally cancel the onDragOver.\r
3969      * @param {Ext.dd.DragDrop} target The drop target\r
3970      * @param {Event} e The event object\r
3971      * @param {String} id The id of the dragged element\r
3972      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
3973      */\r
3974     beforeDragOver : function(target, e, id){\r
3975         return true;\r
3976     },\r
3977 \r
3978     // private\r
3979     onDragOut : function(e, id){\r
3980         var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
3981         if(this.beforeDragOut(target, e, id) !== false){\r
3982             if(target.isNotifyTarget){\r
3983                 target.notifyOut(this, e, this.dragData);\r
3984             }\r
3985             this.proxy.reset();\r
3986             if(this.afterDragOut){\r
3987                 /**\r
3988                  * An empty function by default, but provided so that you can perform a custom action\r
3989                  * after the dragged item is dragged out of the target without dropping.\r
3990                  * @param {Ext.dd.DragDrop} target The drop target\r
3991                  * @param {Event} e The event object\r
3992                  * @param {String} id The id of the dragged element\r
3993                  * @method afterDragOut\r
3994                  */\r
3995                 this.afterDragOut(target, e, id);\r
3996             }\r
3997         }\r
3998         this.cachedTarget = null;\r
3999     },\r
4000 \r
4001     /**\r
4002      * An empty function by default, but provided so that you can perform a custom action before the dragged\r
4003      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.\r
4004      * @param {Ext.dd.DragDrop} target The drop target\r
4005      * @param {Event} e The event object\r
4006      * @param {String} id The id of the dragged element\r
4007      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
4008      */\r
4009     beforeDragOut : function(target, e, id){\r
4010         return true;\r
4011     },\r
4012     \r
4013     // private\r
4014     onDragDrop : function(e, id){\r
4015         var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
4016         if(this.beforeDragDrop(target, e, id) !== false){\r
4017             if(target.isNotifyTarget){\r
4018                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?\r
4019                     this.onValidDrop(target, e, id);\r
4020                 }else{\r
4021                     this.onInvalidDrop(target, e, id);\r
4022                 }\r
4023             }else{\r
4024                 this.onValidDrop(target, e, id);\r
4025             }\r
4026             \r
4027             if(this.afterDragDrop){\r
4028                 /**\r
4029                  * An empty function by default, but provided so that you can perform a custom action\r
4030                  * after a valid drag drop has occurred by providing an implementation.\r
4031                  * @param {Ext.dd.DragDrop} target The drop target\r
4032                  * @param {Event} e The event object\r
4033                  * @param {String} id The id of the dropped element\r
4034                  * @method afterDragDrop\r
4035                  */\r
4036                 this.afterDragDrop(target, e, id);\r
4037             }\r
4038         }\r
4039         delete this.cachedTarget;\r
4040     },\r
4041 \r
4042     /**\r
4043      * An empty function by default, but provided so that you can perform a custom action before the dragged\r
4044      * item is dropped onto the target and optionally cancel the onDragDrop.\r
4045      * @param {Ext.dd.DragDrop} target The drop target\r
4046      * @param {Event} e The event object\r
4047      * @param {String} id The id of the dragged element\r
4048      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel\r
4049      */\r
4050     beforeDragDrop : function(target, e, id){\r
4051         return true;\r
4052     },\r
4053 \r
4054     // private\r
4055     onValidDrop : function(target, e, id){\r
4056         this.hideProxy();\r
4057         if(this.afterValidDrop){\r
4058             /**\r
4059              * An empty function by default, but provided so that you can perform a custom action\r
4060              * after a valid drop has occurred by providing an implementation.\r
4061              * @param {Object} target The target DD \r
4062              * @param {Event} e The event object\r
4063              * @param {String} id The id of the dropped element\r
4064              * @method afterInvalidDrop\r
4065              */\r
4066             this.afterValidDrop(target, e, id);\r
4067         }\r
4068     },\r
4069 \r
4070     // private\r
4071     getRepairXY : function(e, data){\r
4072         return this.el.getXY();  \r
4073     },\r
4074 \r
4075     // private\r
4076     onInvalidDrop : function(target, e, id){\r
4077         this.beforeInvalidDrop(target, e, id);\r
4078         if(this.cachedTarget){\r
4079             if(this.cachedTarget.isNotifyTarget){\r
4080                 this.cachedTarget.notifyOut(this, e, this.dragData);\r
4081             }\r
4082             this.cacheTarget = null;\r
4083         }\r
4084         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);\r
4085 \r
4086         if(this.afterInvalidDrop){\r
4087             /**\r
4088              * An empty function by default, but provided so that you can perform a custom action\r
4089              * after an invalid drop has occurred by providing an implementation.\r
4090              * @param {Event} e The event object\r
4091              * @param {String} id The id of the dropped element\r
4092              * @method afterInvalidDrop\r
4093              */\r
4094             this.afterInvalidDrop(e, id);\r
4095         }\r
4096     },\r
4097 \r
4098     // private\r
4099     afterRepair : function(){\r
4100         if(Ext.enableFx){\r
4101             this.el.highlight(this.hlColor || "c3daf9");\r
4102         }\r
4103         this.dragging = false;\r
4104     },\r
4105 \r
4106     /**\r
4107      * An empty function by default, but provided so that you can perform a custom action after an invalid\r
4108      * drop has occurred.\r
4109      * @param {Ext.dd.DragDrop} target The drop target\r
4110      * @param {Event} e The event object\r
4111      * @param {String} id The id of the dragged element\r
4112      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel\r
4113      */\r
4114     beforeInvalidDrop : function(target, e, id){\r
4115         return true;\r
4116     },\r
4117 \r
4118     // private\r
4119     handleMouseDown : function(e){\r
4120         if(this.dragging) {\r
4121             return;\r
4122         }\r
4123         var data = this.getDragData(e);\r
4124         if(data && this.onBeforeDrag(data, e) !== false){\r
4125             this.dragData = data;\r
4126             this.proxy.stop();\r
4127             Ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);\r
4128         } \r
4129     },\r
4130 \r
4131     /**\r
4132      * An empty function by default, but provided so that you can perform a custom action before the initial\r
4133      * drag event begins and optionally cancel it.\r
4134      * @param {Object} data An object containing arbitrary data to be shared with drop targets\r
4135      * @param {Event} e The event object\r
4136      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
4137      */\r
4138     onBeforeDrag : function(data, e){\r
4139         return true;\r
4140     },\r
4141 \r
4142     /**\r
4143      * An empty function by default, but provided so that you can perform a custom action once the initial\r
4144      * drag event has begun.  The drag cannot be canceled from this function.\r
4145      * @param {Number} x The x position of the click on the dragged object\r
4146      * @param {Number} y The y position of the click on the dragged object\r
4147      */\r
4148     onStartDrag : Ext.emptyFn,\r
4149 \r
4150     // private override\r
4151     startDrag : function(x, y){\r
4152         this.proxy.reset();\r
4153         this.dragging = true;\r
4154         this.proxy.update("");\r
4155         this.onInitDrag(x, y);\r
4156         this.proxy.show();\r
4157     },\r
4158 \r
4159     // private\r
4160     onInitDrag : function(x, y){\r
4161         var clone = this.el.dom.cloneNode(true);\r
4162         clone.id = Ext.id(); // prevent duplicate ids\r
4163         this.proxy.update(clone);\r
4164         this.onStartDrag(x, y);\r
4165         return true;\r
4166     },\r
4167 \r
4168     /**\r
4169      * Returns the drag source's underlying {@link Ext.dd.StatusProxy}\r
4170      * @return {Ext.dd.StatusProxy} proxy The StatusProxy\r
4171      */\r
4172     getProxy : function(){\r
4173         return this.proxy;  \r
4174     },\r
4175 \r
4176     /**\r
4177      * Hides the drag source's {@link Ext.dd.StatusProxy}\r
4178      */\r
4179     hideProxy : function(){\r
4180         this.proxy.hide();  \r
4181         this.proxy.reset(true);\r
4182         this.dragging = false;\r
4183     },\r
4184 \r
4185     // private\r
4186     triggerCacheRefresh : function(){\r
4187         Ext.dd.DDM.refreshCache(this.groups);\r
4188     },\r
4189 \r
4190     // private - override to prevent hiding\r
4191     b4EndDrag: function(e) {\r
4192     },\r
4193 \r
4194     // private - override to prevent moving\r
4195     endDrag : function(e){\r
4196         this.onEndDrag(this.dragData, e);\r
4197     },\r
4198 \r
4199     // private\r
4200     onEndDrag : function(data, e){\r
4201     },\r
4202     \r
4203     // private - pin to cursor\r
4204     autoOffset : function(x, y) {\r
4205         this.setDelta(-12, -20);\r
4206     },\r
4207     \r
4208     destroy: function(){\r
4209         Ext.dd.DragSource.superclass.destroy.call(this);\r
4210         Ext.destroy(this.proxy);\r
4211     }\r
4212 });/**\r
4213  * @class Ext.dd.DropTarget\r
4214  * @extends Ext.dd.DDTarget\r
4215  * A simple class that provides the basic implementation needed to make any element a drop target that can have\r
4216  * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.\r
4217  * @constructor\r
4218  * @param {Mixed} el The container element\r
4219  * @param {Object} config\r
4220  */\r
4221 Ext.dd.DropTarget = function(el, config){\r
4222     this.el = Ext.get(el);\r
4223     \r
4224     Ext.apply(this, config);\r
4225     \r
4226     if(this.containerScroll){\r
4227         Ext.dd.ScrollManager.register(this.el);\r
4228     }\r
4229     \r
4230     Ext.dd.DropTarget.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, \r
4231           {isTarget: true});\r
4232 \r
4233 };\r
4234 \r
4235 Ext.extend(Ext.dd.DropTarget, Ext.dd.DDTarget, {\r
4236     /**\r
4237      * @cfg {String} ddGroup\r
4238      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only\r
4239      * interact with other drag drop objects in the same group (defaults to undefined).\r
4240      */\r
4241     /**\r
4242      * @cfg {String} overClass\r
4243      * The CSS class applied to the drop target element while the drag source is over it (defaults to "").\r
4244      */\r
4245     /**\r
4246      * @cfg {String} dropAllowed\r
4247      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").\r
4248      */\r
4249     dropAllowed : "x-dd-drop-ok",\r
4250     /**\r
4251      * @cfg {String} dropNotAllowed\r
4252      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
4253      */\r
4254     dropNotAllowed : "x-dd-drop-nodrop",\r
4255 \r
4256     // private\r
4257     isTarget : true,\r
4258 \r
4259     // private\r
4260     isNotifyTarget : true,\r
4261 \r
4262     /**\r
4263      * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source is now over the\r
4264      * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element\r
4265      * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.\r
4266      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
4267      * @param {Event} e The event\r
4268      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4269      * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
4270      * underlying {@link Ext.dd.StatusProxy} can be updated\r
4271      */\r
4272     notifyEnter : function(dd, e, data){\r
4273         if(this.overClass){\r
4274             this.el.addClass(this.overClass);\r
4275         }\r
4276         return this.dropAllowed;\r
4277     },\r
4278 \r
4279     /**\r
4280      * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the target.\r
4281      * This method will be called on every mouse movement while the drag source is over the drop target.\r
4282      * This default implementation simply returns the dropAllowed config value.\r
4283      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
4284      * @param {Event} e The event\r
4285      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4286      * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
4287      * underlying {@link Ext.dd.StatusProxy} can be updated\r
4288      */\r
4289     notifyOver : function(dd, e, data){\r
4290         return this.dropAllowed;\r
4291     },\r
4292 \r
4293     /**\r
4294      * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the source has been dragged\r
4295      * out of the target without dropping.  This default implementation simply removes the CSS class specified by\r
4296      * overClass (if any) from the drop element.\r
4297      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
4298      * @param {Event} e The event\r
4299      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4300      */\r
4301     notifyOut : function(dd, e, data){\r
4302         if(this.overClass){\r
4303             this.el.removeClass(this.overClass);\r
4304         }\r
4305     },\r
4306 \r
4307     /**\r
4308      * The function a {@link Ext.dd.DragSource} calls once to notify this drop target that the dragged item has\r
4309      * been dropped on it.  This method has no default implementation and returns false, so you must provide an\r
4310      * implementation that does something to process the drop event and returns true so that the drag source's\r
4311      * repair action does not run.\r
4312      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
4313      * @param {Event} e The event\r
4314      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4315      * @return {Boolean} True if the drop was valid, else false\r
4316      */\r
4317     notifyDrop : function(dd, e, data){\r
4318         return false;\r
4319     }\r
4320 });/**\r
4321  * @class Ext.dd.DragZone\r
4322  * @extends Ext.dd.DragSource\r
4323  * <p>This class provides a container DD instance that allows dragging of multiple child source nodes.</p>\r
4324  * <p>This class does not move the drag target nodes, but a proxy element which may contain\r
4325  * any DOM structure you wish. The DOM element to show in the proxy is provided by either a\r
4326  * provided implementation of {@link #getDragData}, or by registered draggables registered with {@link Ext.dd.Registry}</p>\r
4327  * <p>If you wish to provide draggability for an arbitrary number of DOM nodes, each of which represent some\r
4328  * application object (For example nodes in a {@link Ext.DataView DataView}) then use of this class\r
4329  * is the most efficient way to "activate" those nodes.</p>\r
4330  * <p>By default, this class requires that draggable child nodes are registered with {@link Ext.dd.Registry}.\r
4331  * However a simpler way to allow a DragZone to manage any number of draggable elements is to configure\r
4332  * the DragZone with  an implementation of the {@link #getDragData} method which interrogates the passed\r
4333  * mouse event to see if it has taken place within an element, or class of elements. This is easily done\r
4334  * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a\r
4335  * {@link Ext.DomQuery} selector. For example, to make the nodes of a DataView draggable, use the following\r
4336  * technique. Knowledge of the use of the DataView is required:</p><pre><code>\r
4337 myDataView.on('render', function(v) {\r
4338     myDataView.dragZone = new Ext.dd.DragZone(v.getEl(), {\r
4339 \r
4340 //      On receipt of a mousedown event, see if it is within a DataView node.\r
4341 //      Return a drag data object if so.\r
4342         getDragData: function(e) {\r
4343 \r
4344 //          Use the DataView's own itemSelector (a mandatory property) to\r
4345 //          test if the mousedown is within one of the DataView's nodes.\r
4346             var sourceEl = e.getTarget(v.itemSelector, 10);\r
4347 \r
4348 //          If the mousedown is within a DataView node, clone the node to produce\r
4349 //          a ddel element for use by the drag proxy. Also add application data\r
4350 //          to the returned data object.\r
4351             if (sourceEl) {\r
4352                 d = sourceEl.cloneNode(true);\r
4353                 d.id = Ext.id();\r
4354                 return {\r
4355                     ddel: d,\r
4356                     sourceEl: sourceEl,\r
4357                     repairXY: Ext.fly(sourceEl).getXY(),\r
4358                     sourceStore: v.store,\r
4359                     draggedRecord: v.{@link Ext.DataView#getRecord getRecord}(sourceEl)\r
4360                 }\r
4361             }\r
4362         },\r
4363 \r
4364 //      Provide coordinates for the proxy to slide back to on failed drag.\r
4365 //      This is the original XY coordinates of the draggable element captured\r
4366 //      in the getDragData method.\r
4367         getRepairXY: function() {\r
4368             return this.dragData.repairXY;\r
4369         }\r
4370     });\r
4371 });</code></pre>\r
4372  * See the {@link Ext.dd.DropZone DropZone} documentation for details about building a DropZone which\r
4373  * cooperates with this DragZone.\r
4374  * @constructor\r
4375  * @param {Mixed} el The container element\r
4376  * @param {Object} config\r
4377  */\r
4378 Ext.dd.DragZone = function(el, config){\r
4379     Ext.dd.DragZone.superclass.constructor.call(this, el, config);\r
4380     if(this.containerScroll){\r
4381         Ext.dd.ScrollManager.register(this.el);\r
4382     }\r
4383 };\r
4384 \r
4385 Ext.extend(Ext.dd.DragZone, Ext.dd.DragSource, {\r
4386     /**\r
4387      * This property contains the data representing the dragged object. This data is set up by the implementation\r
4388      * of the {@link #getDragData} method. It must contain a <tt>ddel</tt> property, but can contain\r
4389      * any other data according to the application's needs.\r
4390      * @type Object\r
4391      * @property dragData\r
4392      */\r
4393     /**\r
4394      * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager\r
4395      * for auto scrolling during drag operations.\r
4396      */\r
4397     /**\r
4398      * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair\r
4399      * method after a failed drop (defaults to "c3daf9" - light blue)\r
4400      */\r
4401 \r
4402     /**\r
4403      * Called when a mousedown occurs in this container. Looks in {@link Ext.dd.Registry}\r
4404      * for a valid target to drag based on the mouse down. Override this method\r
4405      * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned\r
4406      * object has a "ddel" attribute (with an HTML Element) for other functions to work.\r
4407      * @param {EventObject} e The mouse down event\r
4408      * @return {Object} The dragData\r
4409      */\r
4410     getDragData : function(e){\r
4411         return Ext.dd.Registry.getHandleFromEvent(e);\r
4412     },\r
4413     \r
4414     /**\r
4415      * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the\r
4416      * this.dragData.ddel\r
4417      * @param {Number} x The x position of the click on the dragged object\r
4418      * @param {Number} y The y position of the click on the dragged object\r
4419      * @return {Boolean} true to continue the drag, false to cancel\r
4420      */\r
4421     onInitDrag : function(x, y){\r
4422         this.proxy.update(this.dragData.ddel.cloneNode(true));\r
4423         this.onStartDrag(x, y);\r
4424         return true;\r
4425     },\r
4426     \r
4427     /**\r
4428      * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel \r
4429      */\r
4430     afterRepair : function(){\r
4431         if(Ext.enableFx){\r
4432             Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");\r
4433         }\r
4434         this.dragging = false;\r
4435     },\r
4436 \r
4437     /**\r
4438      * Called before a repair of an invalid drop to get the XY to animate to. By default returns\r
4439      * the XY of this.dragData.ddel\r
4440      * @param {EventObject} e The mouse up event\r
4441      * @return {Array} The xy location (e.g. [100, 200])\r
4442      */\r
4443     getRepairXY : function(e){\r
4444         return Ext.Element.fly(this.dragData.ddel).getXY();  \r
4445     }\r
4446 });/**\r
4447  * @class Ext.dd.DropZone\r
4448  * @extends Ext.dd.DropTarget\r
4449  * <p>This class provides a container DD instance that allows dropping on multiple child target nodes.</p>\r
4450  * <p>By default, this class requires that child nodes accepting drop are registered with {@link Ext.dd.Registry}.\r
4451  * However a simpler way to allow a DropZone to manage any number of target elements is to configure the\r
4452  * DropZone with an implementation of {@link #getTargetFromEvent} which interrogates the passed\r
4453  * mouse event to see if it has taken place within an element, or class of elements. This is easily done\r
4454  * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a\r
4455  * {@link Ext.DomQuery} selector.</p>\r
4456  * <p>Once the DropZone has detected through calling getTargetFromEvent, that the mouse is over\r
4457  * a drop target, that target is passed as the first parameter to {@link #onNodeEnter}, {@link #onNodeOver},\r
4458  * {@link #onNodeOut}, {@link #onNodeDrop}. You may configure the instance of DropZone with implementations\r
4459  * of these methods to provide application-specific behaviour for these events to update both\r
4460  * application state, and UI state.</p>\r
4461  * <p>For example to make a GridPanel a cooperating target with the example illustrated in\r
4462  * {@link Ext.dd.DragZone DragZone}, the following technique might be used:</p><pre><code>\r
4463 myGridPanel.on('render', function() {\r
4464     myGridPanel.dropZone = new Ext.dd.DropZone(myGridPanel.getView().scroller, {\r
4465 \r
4466 //      If the mouse is over a grid row, return that node. This is\r
4467 //      provided as the "target" parameter in all "onNodeXXXX" node event handling functions\r
4468         getTargetFromEvent: function(e) {\r
4469             return e.getTarget(myGridPanel.getView().rowSelector);\r
4470         },\r
4471 \r
4472 //      On entry into a target node, highlight that node.\r
4473         onNodeEnter : function(target, dd, e, data){ \r
4474             Ext.fly(target).addClass('my-row-highlight-class');\r
4475         },\r
4476 \r
4477 //      On exit from a target node, unhighlight that node.\r
4478         onNodeOut : function(target, dd, e, data){ \r
4479             Ext.fly(target).removeClass('my-row-highlight-class');\r
4480         },\r
4481 \r
4482 //      While over a target node, return the default drop allowed class which\r
4483 //      places a "tick" icon into the drag proxy.\r
4484         onNodeOver : function(target, dd, e, data){ \r
4485             return Ext.dd.DropZone.prototype.dropAllowed;\r
4486         },\r
4487 \r
4488 //      On node drop we can interrogate the target to find the underlying\r
4489 //      application object that is the real target of the dragged data.\r
4490 //      In this case, it is a Record in the GridPanel's Store.\r
4491 //      We can use the data set up by the DragZone's getDragData method to read\r
4492 //      any data we decided to attach in the DragZone's getDragData method.\r
4493         onNodeDrop : function(target, dd, e, data){\r
4494             var rowIndex = myGridPanel.getView().findRowIndex(target);\r
4495             var r = myGridPanel.getStore().getAt(rowIndex);\r
4496             Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +\r
4497                 ' on Record id ' + r.id);\r
4498             return true;\r
4499         }\r
4500     });\r
4501 }\r
4502 </code></pre>\r
4503  * See the {@link Ext.dd.DragZone DragZone} documentation for details about building a DragZone which\r
4504  * cooperates with this DropZone.\r
4505  * @constructor\r
4506  * @param {Mixed} el The container element\r
4507  * @param {Object} config\r
4508  */\r
4509 Ext.dd.DropZone = function(el, config){\r
4510     Ext.dd.DropZone.superclass.constructor.call(this, el, config);\r
4511 };\r
4512 \r
4513 Ext.extend(Ext.dd.DropZone, Ext.dd.DropTarget, {\r
4514     /**\r
4515      * Returns a custom data object associated with the DOM node that is the target of the event.  By default\r
4516      * this looks up the event target in the {@link Ext.dd.Registry}, although you can override this method to\r
4517      * provide your own custom lookup.\r
4518      * @param {Event} e The event\r
4519      * @return {Object} data The custom data\r
4520      */\r
4521     getTargetFromEvent : function(e){\r
4522         return Ext.dd.Registry.getTargetFromEvent(e);\r
4523     },\r
4524 \r
4525     /**\r
4526      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has entered a drop node\r
4527      * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.\r
4528      * This method has no default implementation and should be overridden to provide\r
4529      * node-specific processing if necessary.\r
4530      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from \r
4531      * {@link #getTargetFromEvent} for this node)\r
4532      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4533      * @param {Event} e The event\r
4534      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4535      */\r
4536     onNodeEnter : function(n, dd, e, data){\r
4537         \r
4538     },\r
4539 \r
4540     /**\r
4541      * Called while the DropZone determines that a {@link Ext.dd.DragSource} is over a drop node\r
4542      * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.\r
4543      * The default implementation returns this.dropNotAllowed, so it should be\r
4544      * overridden to provide the proper feedback.\r
4545      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from\r
4546      * {@link #getTargetFromEvent} for this node)\r
4547      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4548      * @param {Event} e The event\r
4549      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4550      * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
4551      * underlying {@link Ext.dd.StatusProxy} can be updated\r
4552      */\r
4553     onNodeOver : function(n, dd, e, data){\r
4554         return this.dropAllowed;\r
4555     },\r
4556 \r
4557     /**\r
4558      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dragged out of\r
4559      * the drop node without dropping.  This method has no default implementation and should be overridden to provide\r
4560      * node-specific processing if necessary.\r
4561      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from\r
4562      * {@link #getTargetFromEvent} for this node)\r
4563      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4564      * @param {Event} e The event\r
4565      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4566      */\r
4567     onNodeOut : function(n, dd, e, data){\r
4568         \r
4569     },\r
4570 \r
4571     /**\r
4572      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped onto\r
4573      * the drop node.  The default implementation returns false, so it should be overridden to provide the\r
4574      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.\r
4575      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from\r
4576      * {@link #getTargetFromEvent} for this node)\r
4577      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4578      * @param {Event} e The event\r
4579      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4580      * @return {Boolean} True if the drop was valid, else false\r
4581      */\r
4582     onNodeDrop : function(n, dd, e, data){\r
4583         return false;\r
4584     },\r
4585 \r
4586     /**\r
4587      * Called while the DropZone determines that a {@link Ext.dd.DragSource} is being dragged over it,\r
4588      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so\r
4589      * it should be overridden to provide the proper feedback if necessary.\r
4590      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4591      * @param {Event} e The event\r
4592      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4593      * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
4594      * underlying {@link Ext.dd.StatusProxy} can be updated\r
4595      */\r
4596     onContainerOver : function(dd, e, data){\r
4597         return this.dropNotAllowed;\r
4598     },\r
4599 \r
4600     /**\r
4601      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped on it,\r
4602      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be\r
4603      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to\r
4604      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.\r
4605      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4606      * @param {Event} e The event\r
4607      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4608      * @return {Boolean} True if the drop was valid, else false\r
4609      */\r
4610     onContainerDrop : function(dd, e, data){\r
4611         return false;\r
4612     },\r
4613 \r
4614     /**\r
4615      * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source is now over\r
4616      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop\r
4617      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops\r
4618      * you should override this method and provide a custom implementation.\r
4619      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4620      * @param {Event} e The event\r
4621      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4622      * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
4623      * underlying {@link Ext.dd.StatusProxy} can be updated\r
4624      */\r
4625     notifyEnter : function(dd, e, data){\r
4626         return this.dropNotAllowed;\r
4627     },\r
4628 \r
4629     /**\r
4630      * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the drop zone.\r
4631      * This method will be called on every mouse movement while the drag source is over the drop zone.\r
4632      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically\r
4633      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits\r
4634      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a\r
4635      * registered node, it will call {@link #onContainerOver}.\r
4636      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4637      * @param {Event} e The event\r
4638      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4639      * @return {String} status The CSS class that communicates the drop status back to the source so that the\r
4640      * underlying {@link Ext.dd.StatusProxy} can be updated\r
4641      */\r
4642     notifyOver : function(dd, e, data){\r
4643         var n = this.getTargetFromEvent(e);\r
4644         if(!n){ // not over valid drop target\r
4645             if(this.lastOverNode){\r
4646                 this.onNodeOut(this.lastOverNode, dd, e, data);\r
4647                 this.lastOverNode = null;\r
4648             }\r
4649             return this.onContainerOver(dd, e, data);\r
4650         }\r
4651         if(this.lastOverNode != n){\r
4652             if(this.lastOverNode){\r
4653                 this.onNodeOut(this.lastOverNode, dd, e, data);\r
4654             }\r
4655             this.onNodeEnter(n, dd, e, data);\r
4656             this.lastOverNode = n;\r
4657         }\r
4658         return this.onNodeOver(n, dd, e, data);\r
4659     },\r
4660 \r
4661     /**\r
4662      * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source has been dragged\r
4663      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification\r
4664      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.\r
4665      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target\r
4666      * @param {Event} e The event\r
4667      * @param {Object} data An object containing arbitrary data supplied by the drag zone\r
4668      */\r
4669     notifyOut : function(dd, e, data){\r
4670         if(this.lastOverNode){\r
4671             this.onNodeOut(this.lastOverNode, dd, e, data);\r
4672             this.lastOverNode = null;\r
4673         }\r
4674     },\r
4675 \r
4676     /**\r
4677      * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the dragged item has\r
4678      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there\r
4679      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,\r
4680      * otherwise it will call {@link #onContainerDrop}.\r
4681      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone\r
4682      * @param {Event} e The event\r
4683      * @param {Object} data An object containing arbitrary data supplied by the drag source\r
4684      * @return {Boolean} True if the drop was valid, else false\r
4685      */\r
4686     notifyDrop : function(dd, e, data){\r
4687         if(this.lastOverNode){\r
4688             this.onNodeOut(this.lastOverNode, dd, e, data);\r
4689             this.lastOverNode = null;\r
4690         }\r
4691         var n = this.getTargetFromEvent(e);\r
4692         return n ?\r
4693             this.onNodeDrop(n, dd, e, data) :\r
4694             this.onContainerDrop(dd, e, data);\r
4695     },\r
4696 \r
4697     // private\r
4698     triggerCacheRefresh : function(){\r
4699         Ext.dd.DDM.refreshCache(this.groups);\r
4700     }  \r
4701 });/**\r
4702  * @class Ext.Element\r
4703  */\r
4704 Ext.Element.addMethods({\r
4705     /**\r
4706      * Initializes a {@link Ext.dd.DD} drag drop object for this element.\r
4707      * @param {String} group The group the DD object is member of\r
4708      * @param {Object} config The DD config object\r
4709      * @param {Object} overrides An object containing methods to override/implement on the DD object\r
4710      * @return {Ext.dd.DD} The DD object\r
4711      */\r
4712     initDD : function(group, config, overrides){\r
4713         var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);\r
4714         return Ext.apply(dd, overrides);\r
4715     },\r
4716 \r
4717     /**\r
4718      * Initializes a {@link Ext.dd.DDProxy} object for this element.\r
4719      * @param {String} group The group the DDProxy object is member of\r
4720      * @param {Object} config The DDProxy config object\r
4721      * @param {Object} overrides An object containing methods to override/implement on the DDProxy object\r
4722      * @return {Ext.dd.DDProxy} The DDProxy object\r
4723      */\r
4724     initDDProxy : function(group, config, overrides){\r
4725         var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);\r
4726         return Ext.apply(dd, overrides);\r
4727     },\r
4728 \r
4729     /**\r
4730      * Initializes a {@link Ext.dd.DDTarget} object for this element.\r
4731      * @param {String} group The group the DDTarget object is member of\r
4732      * @param {Object} config The DDTarget config object\r
4733      * @param {Object} overrides An object containing methods to override/implement on the DDTarget object\r
4734      * @return {Ext.dd.DDTarget} The DDTarget object\r
4735      */\r
4736     initDDTarget : function(group, config, overrides){\r
4737         var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);\r
4738         return Ext.apply(dd, overrides);\r
4739     }\r
4740 });