Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / DragDropManager.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js">/*
19  * This is a derivative of the similarly named class in the YUI Library.
20  * The original license:
21  * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
22  * Code licensed under the BSD License:
23  * http://developer.yahoo.net/yui/license.txt
24  */
25
26
27 <span id='Ext-dd-DragDropManager'>/**
28 </span> * @class Ext.dd.DragDropManager
29  * DragDropManager is a singleton that tracks the element interaction for
30  * all DragDrop items in the window.  Generally, you will not call
31  * this class directly, but it does have helper methods that could
32  * be useful in your DragDrop implementations.
33  * @singleton
34  */
35 Ext.define('Ext.dd.DragDropManager', {
36     singleton: true,
37
38     requires: ['Ext.util.Region'],
39
40     uses: ['Ext.tip.QuickTipManager'],
41
42     // shorter ClassName, to save bytes and use internally
43     alternateClassName: ['Ext.dd.DragDropMgr', 'Ext.dd.DDM'],
44     
45 <span id='Ext-dd-DragDropManager-property-ids'>    /**
46 </span>     * Two dimensional Array of registered DragDrop objects.  The first
47      * dimension is the DragDrop item group, the second the DragDrop
48      * object.
49      * @property ids
50      * @type String[]
51      * @private
52      * @static
53      */
54     ids: {},
55
56 <span id='Ext-dd-DragDropManager-property-handleIds'>    /**
57 </span>     * Array of element ids defined as drag handles.  Used to determine
58      * if the element that generated the mousedown event is actually the
59      * handle and not the html element itself.
60      * @property handleIds
61      * @type String[]
62      * @private
63      * @static
64      */
65     handleIds: {},
66
67 <span id='Ext-dd-DragDropManager-property-dragCurrent'>    /**
68 </span>     * the DragDrop object that is currently being dragged
69      * @property dragCurrent
70      * @type DragDrop
71      * @private
72      * @static
73      **/
74     dragCurrent: null,
75
76 <span id='Ext-dd-DragDropManager-property-dragOvers'>    /**
77 </span>     * the DragDrop object(s) that are being hovered over
78      * @property dragOvers
79      * @type Array
80      * @private
81      * @static
82      */
83     dragOvers: {},
84
85 <span id='Ext-dd-DragDropManager-property-deltaX'>    /**
86 </span>     * the X distance between the cursor and the object being dragged
87      * @property deltaX
88      * @type int
89      * @private
90      * @static
91      */
92     deltaX: 0,
93
94 <span id='Ext-dd-DragDropManager-property-deltaY'>    /**
95 </span>     * the Y distance between the cursor and the object being dragged
96      * @property deltaY
97      * @type int
98      * @private
99      * @static
100      */
101     deltaY: 0,
102
103 <span id='Ext-dd-DragDropManager-property-preventDefault'>    /**
104 </span>     * Flag to determine if we should prevent the default behavior of the
105      * events we define. By default this is true, but this can be set to
106      * false if you need the default behavior (not recommended)
107      * @property preventDefault
108      * @type boolean
109      * @static
110      */
111     preventDefault: true,
112
113 <span id='Ext-dd-DragDropManager-property-stopPropagation'>    /**
114 </span>     * Flag to determine if we should stop the propagation of the events
115      * we generate. This is true by default but you may want to set it to
116      * false if the html element contains other features that require the
117      * mouse click.
118      * @property stopPropagation
119      * @type boolean
120      * @static
121      */
122     stopPropagation: true,
123
124 <span id='Ext-dd-DragDropManager-property-initialized'>    /**
125 </span>     * Internal flag that is set to true when drag and drop has been
126      * intialized
127      * @property initialized
128      * @private
129      * @static
130      */
131     initialized: false,
132
133 <span id='Ext-dd-DragDropManager-property-locked'>    /**
134 </span>     * All drag and drop can be disabled.
135      * @property locked
136      * @private
137      * @static
138      */
139     locked: false,
140
141 <span id='Ext-dd-DragDropManager-method-init'>    /**
142 </span>     * Called the first time an element is registered.
143      * @method init
144      * @private
145      * @static
146      */
147     init: function() {
148         this.initialized = true;
149     },
150
151 <span id='Ext-dd-DragDropManager-property-POINT'>    /**
152 </span>     * In point mode, drag and drop interaction is defined by the
153      * location of the cursor during the drag/drop
154      * @property POINT
155      * @type int
156      * @static
157      */
158     POINT: 0,
159
160 <span id='Ext-dd-DragDropManager-property-INTERSECT'>    /**
161 </span>     * In intersect mode, drag and drop interaction is defined by the
162      * overlap of two or more drag and drop objects.
163      * @property INTERSECT
164      * @type int
165      * @static
166      */
167     INTERSECT: 1,
168
169 <span id='Ext-dd-DragDropManager-property-mode'>    /**
170 </span>     * The current drag and drop mode.  Default: POINT
171      * @property mode
172      * @type int
173      * @static
174      */
175     mode: 0,
176
177 <span id='Ext-dd-DragDropManager-method-_execOnAll'>    /**
178 </span>     * Runs method on all drag and drop objects
179      * @method _execOnAll
180      * @private
181      * @static
182      */
183     _execOnAll: function(sMethod, args) {
184         for (var i in this.ids) {
185             for (var j in this.ids[i]) {
186                 var oDD = this.ids[i][j];
187                 if (! this.isTypeOfDD(oDD)) {
188                     continue;
189                 }
190                 oDD[sMethod].apply(oDD, args);
191             }
192         }
193     },
194
195 <span id='Ext-dd-DragDropManager-method-_onLoad'>    /**
196 </span>     * Drag and drop initialization.  Sets up the global event handlers
197      * @method _onLoad
198      * @private
199      * @static
200      */
201     _onLoad: function() {
202
203         this.init();
204
205         var Event = Ext.EventManager;
206         Event.on(document, &quot;mouseup&quot;,   this.handleMouseUp, this, true);
207         Event.on(document, &quot;mousemove&quot;, this.handleMouseMove, this, true);
208         Event.on(window,   &quot;unload&quot;,    this._onUnload, this, true);
209         Event.on(window,   &quot;resize&quot;,    this._onResize, this, true);
210         // Event.on(window,   &quot;mouseout&quot;,    this._test);
211
212     },
213
214 <span id='Ext-dd-DragDropManager-method-_onResize'>    /**
215 </span>     * Reset constraints on all drag and drop objs
216      * @method _onResize
217      * @private
218      * @static
219      */
220     _onResize: function(e) {
221         this._execOnAll(&quot;resetConstraints&quot;, []);
222     },
223
224 <span id='Ext-dd-DragDropManager-method-lock'>    /**
225 </span>     * Lock all drag and drop functionality
226      * @method lock
227      * @static
228      */
229     lock: function() { this.locked = true; },
230
231 <span id='Ext-dd-DragDropManager-method-unlock'>    /**
232 </span>     * Unlock all drag and drop functionality
233      * @method unlock
234      * @static
235      */
236     unlock: function() { this.locked = false; },
237
238 <span id='Ext-dd-DragDropManager-method-isLocked'>    /**
239 </span>     * Is drag and drop locked?
240      * @method isLocked
241      * @return {boolean} True if drag and drop is locked, false otherwise.
242      * @static
243      */
244     isLocked: function() { return this.locked; },
245
246 <span id='Ext-dd-DragDropManager-property-locationCache'>    /**
247 </span>     * Location cache that is set for all drag drop objects when a drag is
248      * initiated, cleared when the drag is finished.
249      * @property locationCache
250      * @private
251      * @static
252      */
253     locationCache: {},
254
255 <span id='Ext-dd-DragDropManager-property-useCache'>    /**
256 </span>     * Set useCache to false if you want to force object the lookup of each
257      * drag and drop linked element constantly during a drag.
258      * @property useCache
259      * @type boolean
260      * @static
261      */
262     useCache: true,
263
264 <span id='Ext-dd-DragDropManager-property-clickPixelThresh'>    /**
265 </span>     * The number of pixels that the mouse needs to move after the
266      * mousedown before the drag is initiated.  Default=3;
267      * @property clickPixelThresh
268      * @type int
269      * @static
270      */
271     clickPixelThresh: 3,
272
273 <span id='Ext-dd-DragDropManager-property-clickTimeThresh'>    /**
274 </span>     * The number of milliseconds after the mousedown event to initiate the
275      * drag if we don't get a mouseup event. Default=350
276      * @property clickTimeThresh
277      * @type int
278      * @static
279      */
280     clickTimeThresh: 350,
281
282 <span id='Ext-dd-DragDropManager-property-dragThreshMet'>    /**
283 </span>     * Flag that indicates that either the drag pixel threshold or the
284      * mousdown time threshold has been met
285      * @property dragThreshMet
286      * @type boolean
287      * @private
288      * @static
289      */
290     dragThreshMet: false,
291
292 <span id='Ext-dd-DragDropManager-property-clickTimeout'>    /**
293 </span>     * Timeout used for the click time threshold
294      * @property clickTimeout
295      * @type Object
296      * @private
297      * @static
298      */
299     clickTimeout: null,
300
301 <span id='Ext-dd-DragDropManager-property-startX'>    /**
302 </span>     * The X position of the mousedown event stored for later use when a
303      * drag threshold is met.
304      * @property startX
305      * @type int
306      * @private
307      * @static
308      */
309     startX: 0,
310
311 <span id='Ext-dd-DragDropManager-property-startY'>    /**
312 </span>     * The Y position of the mousedown event stored for later use when a
313      * drag threshold is met.
314      * @property startY
315      * @type int
316      * @private
317      * @static
318      */
319     startY: 0,
320
321 <span id='Ext-dd-DragDropManager-method-regDragDrop'>    /**
322 </span>     * Each DragDrop instance must be registered with the DragDropManager.
323      * This is executed in DragDrop.init()
324      * @method regDragDrop
325      * @param {DragDrop} oDD the DragDrop object to register
326      * @param {String} sGroup the name of the group this element belongs to
327      * @static
328      */
329     regDragDrop: function(oDD, sGroup) {
330         if (!this.initialized) { this.init(); }
331
332         if (!this.ids[sGroup]) {
333             this.ids[sGroup] = {};
334         }
335         this.ids[sGroup][oDD.id] = oDD;
336     },
337
338 <span id='Ext-dd-DragDropManager-method-removeDDFromGroup'>    /**
339 </span>     * Removes the supplied dd instance from the supplied group. Executed
340      * by DragDrop.removeFromGroup, so don't call this function directly.
341      * @method removeDDFromGroup
342      * @private
343      * @static
344      */
345     removeDDFromGroup: function(oDD, sGroup) {
346         if (!this.ids[sGroup]) {
347             this.ids[sGroup] = {};
348         }
349
350         var obj = this.ids[sGroup];
351         if (obj &amp;&amp; obj[oDD.id]) {
352             delete obj[oDD.id];
353         }
354     },
355
356 <span id='Ext-dd-DragDropManager-method-_remove'>    /**
357 </span>     * Unregisters a drag and drop item.  This is executed in
358      * DragDrop.unreg, use that method instead of calling this directly.
359      * @method _remove
360      * @private
361      * @static
362      */
363     _remove: function(oDD) {
364         for (var g in oDD.groups) {
365             if (g &amp;&amp; this.ids[g] &amp;&amp; this.ids[g][oDD.id]) {
366                 delete this.ids[g][oDD.id];
367             }
368         }
369         delete this.handleIds[oDD.id];
370     },
371
372 <span id='Ext-dd-DragDropManager-method-regHandle'>    /**
373 </span>     * Each DragDrop handle element must be registered.  This is done
374      * automatically when executing DragDrop.setHandleElId()
375      * @method regHandle
376      * @param {String} sDDId the DragDrop id this element is a handle for
377      * @param {String} sHandleId the id of the element that is the drag
378      * handle
379      * @static
380      */
381     regHandle: function(sDDId, sHandleId) {
382         if (!this.handleIds[sDDId]) {
383             this.handleIds[sDDId] = {};
384         }
385         this.handleIds[sDDId][sHandleId] = sHandleId;
386     },
387
388 <span id='Ext-dd-DragDropManager-method-isDragDrop'>    /**
389 </span>     * Utility function to determine if a given element has been
390      * registered as a drag drop item.
391      * @method isDragDrop
392      * @param {String} id the element id to check
393      * @return {boolean} true if this element is a DragDrop item,
394      * false otherwise
395      * @static
396      */
397     isDragDrop: function(id) {
398         return ( this.getDDById(id) ) ? true : false;
399     },
400
401 <span id='Ext-dd-DragDropManager-method-getRelated'>    /**
402 </span>     * Returns the drag and drop instances that are in all groups the
403      * passed in instance belongs to.
404      * @method getRelated
405      * @param {DragDrop} p_oDD the obj to get related data for
406      * @param {boolean} bTargetsOnly if true, only return targetable objs
407      * @return {DragDrop[]} the related instances
408      * @static
409      */
410     getRelated: function(p_oDD, bTargetsOnly) {
411         var oDDs = [];
412         for (var i in p_oDD.groups) {
413             for (var j in this.ids[i]) {
414                 var dd = this.ids[i][j];
415                 if (! this.isTypeOfDD(dd)) {
416                     continue;
417                 }
418                 if (!bTargetsOnly || dd.isTarget) {
419                     oDDs[oDDs.length] = dd;
420                 }
421             }
422         }
423
424         return oDDs;
425     },
426
427 <span id='Ext-dd-DragDropManager-method-isLegalTarget'>    /**
428 </span>     * Returns true if the specified dd target is a legal target for
429      * the specifice drag obj
430      * @method isLegalTarget
431      * @param {DragDrop} oDD the drag obj
432      * @param {DragDrop} oTargetDD the target
433      * @return {boolean} true if the target is a legal target for the
434      * dd obj
435      * @static
436      */
437     isLegalTarget: function (oDD, oTargetDD) {
438         var targets = this.getRelated(oDD, true);
439         for (var i=0, len=targets.length;i&lt;len;++i) {
440             if (targets[i].id == oTargetDD.id) {
441                 return true;
442             }
443         }
444
445         return false;
446     },
447
448 <span id='Ext-dd-DragDropManager-method-isTypeOfDD'>    /**
449 </span>     * My goal is to be able to transparently determine if an object is
450      * typeof DragDrop, and the exact subclass of DragDrop.  typeof
451      * returns &quot;object&quot;, oDD.constructor.toString() always returns
452      * &quot;DragDrop&quot; and not the name of the subclass.  So for now it just
453      * evaluates a well-known variable in DragDrop.
454      * @method isTypeOfDD
455      * @param {Object} the object to evaluate
456      * @return {boolean} true if typeof oDD = DragDrop
457      * @static
458      */
459     isTypeOfDD: function (oDD) {
460         return (oDD &amp;&amp; oDD.__ygDragDrop);
461     },
462
463 <span id='Ext-dd-DragDropManager-method-isHandle'>    /**
464 </span>     * Utility function to determine if a given element has been
465      * registered as a drag drop handle for the given Drag Drop object.
466      * @method isHandle
467      * @param {String} id the element id to check
468      * @return {boolean} true if this element is a DragDrop handle, false
469      * otherwise
470      * @static
471      */
472     isHandle: function(sDDId, sHandleId) {
473         return ( this.handleIds[sDDId] &amp;&amp;
474                         this.handleIds[sDDId][sHandleId] );
475     },
476
477 <span id='Ext-dd-DragDropManager-method-getDDById'>    /**
478 </span>     * Returns the DragDrop instance for a given id
479      * @method getDDById
480      * @param {String} id the id of the DragDrop object
481      * @return {DragDrop} the drag drop object, null if it is not found
482      * @static
483      */
484     getDDById: function(id) {
485         for (var i in this.ids) {
486             if (this.ids[i][id]) {
487                 return this.ids[i][id];
488             }
489         }
490         return null;
491     },
492
493 <span id='Ext-dd-DragDropManager-method-handleMouseDown'>    /**
494 </span>     * Fired after a registered DragDrop object gets the mousedown event.
495      * Sets up the events required to track the object being dragged
496      * @method handleMouseDown
497      * @param {Event} e the event
498      * @param oDD the DragDrop object being dragged
499      * @private
500      * @static
501      */
502     handleMouseDown: function(e, oDD) {
503         if(Ext.tip.QuickTipManager){
504             Ext.tip.QuickTipManager.ddDisable();
505         }
506         if(this.dragCurrent){
507             // the original browser mouseup wasn't handled (e.g. outside FF browser window)
508             // so clean up first to avoid breaking the next drag
509             this.handleMouseUp(e);
510         }
511         
512         this.currentTarget = e.getTarget();
513         this.dragCurrent = oDD;
514
515         var el = oDD.getEl();
516
517         // track start position
518         this.startX = e.getPageX();
519         this.startY = e.getPageY();
520
521         this.deltaX = this.startX - el.offsetLeft;
522         this.deltaY = this.startY - el.offsetTop;
523
524         this.dragThreshMet = false;
525
526         this.clickTimeout = setTimeout(
527                 function() {
528                     var DDM = Ext.dd.DragDropManager;
529                     DDM.startDrag(DDM.startX, DDM.startY);
530                 },
531                 this.clickTimeThresh );
532     },
533
534 <span id='Ext-dd-DragDropManager-method-startDrag'>    /**
535 </span>     * Fired when either the drag pixel threshol or the mousedown hold
536      * time threshold has been met.
537      * @method startDrag
538      * @param x {int} the X position of the original mousedown
539      * @param y {int} the Y position of the original mousedown
540      * @static
541      */
542     startDrag: function(x, y) {
543         clearTimeout(this.clickTimeout);
544         if (this.dragCurrent) {
545             this.dragCurrent.b4StartDrag(x, y);
546             this.dragCurrent.startDrag(x, y);
547         }
548         this.dragThreshMet = true;
549     },
550
551 <span id='Ext-dd-DragDropManager-method-handleMouseUp'>    /**
552 </span>     * Internal function to handle the mouseup event.  Will be invoked
553      * from the context of the document.
554      * @method handleMouseUp
555      * @param {Event} e the event
556      * @private
557      * @static
558      */
559     handleMouseUp: function(e) {
560
561         if(Ext.tip.QuickTipManager){
562             Ext.tip.QuickTipManager.ddEnable();
563         }
564         if (! this.dragCurrent) {
565             return;
566         }
567
568         clearTimeout(this.clickTimeout);
569
570         if (this.dragThreshMet) {
571             this.fireEvents(e, true);
572         } else {
573         }
574
575         this.stopDrag(e);
576
577         this.stopEvent(e);
578     },
579
580 <span id='Ext-dd-DragDropManager-method-stopEvent'>    /**
581 </span>     * Utility to stop event propagation and event default, if these
582      * features are turned on.
583      * @method stopEvent
584      * @param {Event} e the event as returned by this.getEvent()
585      * @static
586      */
587     stopEvent: function(e){
588         if(this.stopPropagation) {
589             e.stopPropagation();
590         }
591
592         if (this.preventDefault) {
593             e.preventDefault();
594         }
595     },
596
597 <span id='Ext-dd-DragDropManager-method-stopDrag'>    /**
598 </span>     * Internal function to clean up event handlers after the drag
599      * operation is complete
600      * @method stopDrag
601      * @param {Event} e the event
602      * @private
603      * @static
604      */
605     stopDrag: function(e) {
606         // Fire the drag end event for the item that was dragged
607         if (this.dragCurrent) {
608             if (this.dragThreshMet) {
609                 this.dragCurrent.b4EndDrag(e);
610                 this.dragCurrent.endDrag(e);
611             }
612
613             this.dragCurrent.onMouseUp(e);
614         }
615
616         this.dragCurrent = null;
617         this.dragOvers = {};
618     },
619
620 <span id='Ext-dd-DragDropManager-method-handleMouseMove'>    /**
621 </span>     * Internal function to handle the mousemove event.  Will be invoked
622      * from the context of the html element.
623      *
624      * @TODO figure out what we can do about mouse events lost when the
625      * user drags objects beyond the window boundary.  Currently we can
626      * detect this in internet explorer by verifying that the mouse is
627      * down during the mousemove event.  Firefox doesn't give us the
628      * button state on the mousemove event.
629      * @method handleMouseMove
630      * @param {Event} e the event
631      * @private
632      * @static
633      */
634     handleMouseMove: function(e) {
635         if (! this.dragCurrent) {
636             return true;
637         }
638         // var button = e.which || e.button;
639
640         // check for IE mouseup outside of page boundary
641         if (Ext.isIE &amp;&amp; (e.button !== 0 &amp;&amp; e.button !== 1 &amp;&amp; e.button !== 2)) {
642             this.stopEvent(e);
643             return this.handleMouseUp(e);
644         }
645
646         if (!this.dragThreshMet) {
647             var diffX = Math.abs(this.startX - e.getPageX());
648             var diffY = Math.abs(this.startY - e.getPageY());
649             if (diffX &gt; this.clickPixelThresh ||
650                         diffY &gt; this.clickPixelThresh) {
651                 this.startDrag(this.startX, this.startY);
652             }
653         }
654
655         if (this.dragThreshMet) {
656             this.dragCurrent.b4Drag(e);
657             this.dragCurrent.onDrag(e);
658             if(!this.dragCurrent.moveOnly){
659                 this.fireEvents(e, false);
660             }
661         }
662
663         this.stopEvent(e);
664
665         return true;
666     },
667
668 <span id='Ext-dd-DragDropManager-method-fireEvents'>    /**
669 </span>     * Iterates over all of the DragDrop elements to find ones we are
670      * hovering over or dropping on
671      * @method fireEvents
672      * @param {Event} e the event
673      * @param {boolean} isDrop is this a drop op or a mouseover op?
674      * @private
675      * @static
676      */
677     fireEvents: function(e, isDrop) {
678         var dc = this.dragCurrent;
679
680         // If the user did the mouse up outside of the window, we could
681         // get here even though we have ended the drag.
682         if (!dc || dc.isLocked()) {
683             return;
684         }
685
686         var pt = e.getPoint();
687
688         // cache the previous dragOver array
689         var oldOvers = [];
690
691         var outEvts   = [];
692         var overEvts  = [];
693         var dropEvts  = [];
694         var enterEvts = [];
695
696         // Check to see if the object(s) we were hovering over is no longer
697         // being hovered over so we can fire the onDragOut event
698         for (var i in this.dragOvers) {
699
700             var ddo = this.dragOvers[i];
701
702             if (! this.isTypeOfDD(ddo)) {
703                 continue;
704             }
705
706             if (! this.isOverTarget(pt, ddo, this.mode)) {
707                 outEvts.push( ddo );
708             }
709
710             oldOvers[i] = true;
711             delete this.dragOvers[i];
712         }
713
714         for (var sGroup in dc.groups) {
715
716             if (&quot;string&quot; != typeof sGroup) {
717                 continue;
718             }
719
720             for (i in this.ids[sGroup]) {
721                 var oDD = this.ids[sGroup][i];
722                 if (! this.isTypeOfDD(oDD)) {
723                     continue;
724                 }
725
726                 if (oDD.isTarget &amp;&amp; !oDD.isLocked() &amp;&amp; ((oDD != dc) || (dc.ignoreSelf === false))) {
727                     if (this.isOverTarget(pt, oDD, this.mode)) {
728                         // look for drop interactions
729                         if (isDrop) {
730                             dropEvts.push( oDD );
731                         // look for drag enter and drag over interactions
732                         } else {
733
734                             // initial drag over: dragEnter fires
735                             if (!oldOvers[oDD.id]) {
736                                 enterEvts.push( oDD );
737                             // subsequent drag overs: dragOver fires
738                             } else {
739                                 overEvts.push( oDD );
740                             }
741
742                             this.dragOvers[oDD.id] = oDD;
743                         }
744                     }
745                 }
746             }
747         }
748
749         if (this.mode) {
750             if (outEvts.length) {
751                 dc.b4DragOut(e, outEvts);
752                 dc.onDragOut(e, outEvts);
753             }
754
755             if (enterEvts.length) {
756                 dc.onDragEnter(e, enterEvts);
757             }
758
759             if (overEvts.length) {
760                 dc.b4DragOver(e, overEvts);
761                 dc.onDragOver(e, overEvts);
762             }
763
764             if (dropEvts.length) {
765                 dc.b4DragDrop(e, dropEvts);
766                 dc.onDragDrop(e, dropEvts);
767             }
768
769         } else {
770             // fire dragout events
771             var len = 0;
772             for (i=0, len=outEvts.length; i&lt;len; ++i) {
773                 dc.b4DragOut(e, outEvts[i].id);
774                 dc.onDragOut(e, outEvts[i].id);
775             }
776
777             // fire enter events
778             for (i=0,len=enterEvts.length; i&lt;len; ++i) {
779                 // dc.b4DragEnter(e, oDD.id);
780                 dc.onDragEnter(e, enterEvts[i].id);
781             }
782
783             // fire over events
784             for (i=0,len=overEvts.length; i&lt;len; ++i) {
785                 dc.b4DragOver(e, overEvts[i].id);
786                 dc.onDragOver(e, overEvts[i].id);
787             }
788
789             // fire drop events
790             for (i=0, len=dropEvts.length; i&lt;len; ++i) {
791                 dc.b4DragDrop(e, dropEvts[i].id);
792                 dc.onDragDrop(e, dropEvts[i].id);
793             }
794
795         }
796
797         // notify about a drop that did not find a target
798         if (isDrop &amp;&amp; !dropEvts.length) {
799             dc.onInvalidDrop(e);
800         }
801
802     },
803
804 <span id='Ext-dd-DragDropManager-method-getBestMatch'>    /**
805 </span>     * Helper function for getting the best match from the list of drag
806      * and drop objects returned by the drag and drop events when we are
807      * in INTERSECT mode.  It returns either the first object that the
808      * cursor is over, or the object that has the greatest overlap with
809      * the dragged element.
810      * @method getBestMatch
811      * @param  {DragDrop[]} dds The array of drag and drop objects
812      * targeted
813      * @return {DragDrop}       The best single match
814      * @static
815      */
816     getBestMatch: function(dds) {
817         var winner = null;
818         // Return null if the input is not what we expect
819         //if (!dds || !dds.length || dds.length == 0) {
820            // winner = null;
821         // If there is only one item, it wins
822         //} else if (dds.length == 1) {
823
824         var len = dds.length;
825
826         if (len == 1) {
827             winner = dds[0];
828         } else {
829             // Loop through the targeted items
830             for (var i=0; i&lt;len; ++i) {
831                 var dd = dds[i];
832                 // If the cursor is over the object, it wins.  If the
833                 // cursor is over multiple matches, the first one we come
834                 // to wins.
835                 if (dd.cursorIsOver) {
836                     winner = dd;
837                     break;
838                 // Otherwise the object with the most overlap wins
839                 } else {
840                     if (!winner ||
841                         winner.overlap.getArea() &lt; dd.overlap.getArea()) {
842                         winner = dd;
843                     }
844                 }
845             }
846         }
847
848         return winner;
849     },
850
851 <span id='Ext-dd-DragDropManager-method-refreshCache'>    /**
852 </span>     * Refreshes the cache of the top-left and bottom-right points of the
853      * drag and drop objects in the specified group(s).  This is in the
854      * format that is stored in the drag and drop instance, so typical
855      * usage is:
856      * &lt;code&gt;
857      * Ext.dd.DragDropManager.refreshCache(ddinstance.groups);
858      * &lt;/code&gt;
859      * Alternatively:
860      * &lt;code&gt;
861      * Ext.dd.DragDropManager.refreshCache({group1:true, group2:true});
862      * &lt;/code&gt;
863      * @TODO this really should be an indexed array.  Alternatively this
864      * method could accept both.
865      * @method refreshCache
866      * @param {Object} groups an associative array of groups to refresh
867      * @static
868      */
869     refreshCache: function(groups) {
870         for (var sGroup in groups) {
871             if (&quot;string&quot; != typeof sGroup) {
872                 continue;
873             }
874             for (var i in this.ids[sGroup]) {
875                 var oDD = this.ids[sGroup][i];
876
877                 if (this.isTypeOfDD(oDD)) {
878                 // if (this.isTypeOfDD(oDD) &amp;&amp; oDD.isTarget) {
879                     var loc = this.getLocation(oDD);
880                     if (loc) {
881                         this.locationCache[oDD.id] = loc;
882                     } else {
883                         delete this.locationCache[oDD.id];
884                         // this will unregister the drag and drop object if
885                         // the element is not in a usable state
886                         // oDD.unreg();
887                     }
888                 }
889             }
890         }
891     },
892
893 <span id='Ext-dd-DragDropManager-method-verifyEl'>    /**
894 </span>     * This checks to make sure an element exists and is in the DOM.  The
895      * main purpose is to handle cases where innerHTML is used to remove
896      * drag and drop objects from the DOM.  IE provides an 'unspecified
897      * error' when trying to access the offsetParent of such an element
898      * @method verifyEl
899      * @param {HTMLElement} el the element to check
900      * @return {boolean} true if the element looks usable
901      * @static
902      */
903     verifyEl: function(el) {
904         if (el) {
905             var parent;
906             if(Ext.isIE){
907                 try{
908                     parent = el.offsetParent;
909                 }catch(e){}
910             }else{
911                 parent = el.offsetParent;
912             }
913             if (parent) {
914                 return true;
915             }
916         }
917
918         return false;
919     },
920
921 <span id='Ext-dd-DragDropManager-method-getLocation'>    /**
922 </span>     * Returns a Region object containing the drag and drop element's position
923      * and size, including the padding configured for it
924      * @method getLocation
925      * @param {DragDrop} oDD the drag and drop object to get the
926      *                       location for
927      * @return {Ext.util.Region} a Region object representing the total area
928      *                             the element occupies, including any padding
929      *                             the instance is configured for.
930      * @static
931      */
932     getLocation: function(oDD) {
933         if (! this.isTypeOfDD(oDD)) {
934             return null;
935         }
936
937         //delegate getLocation method to the
938         //drag and drop target.
939         if (oDD.getRegion) {
940             return oDD.getRegion();
941         }
942
943         var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
944
945         try {
946             pos= Ext.core.Element.getXY(el);
947         } catch (e) { }
948
949         if (!pos) {
950             return null;
951         }
952
953         x1 = pos[0];
954         x2 = x1 + el.offsetWidth;
955         y1 = pos[1];
956         y2 = y1 + el.offsetHeight;
957
958         t = y1 - oDD.padding[0];
959         r = x2 + oDD.padding[1];
960         b = y2 + oDD.padding[2];
961         l = x1 - oDD.padding[3];
962
963         return Ext.create('Ext.util.Region', t, r, b, l);
964     },
965
966 <span id='Ext-dd-DragDropManager-method-isOverTarget'>    /**
967 </span>     * Checks the cursor location to see if it over the target
968      * @method isOverTarget
969      * @param {Ext.util.Point} pt The point to evaluate
970      * @param {DragDrop} oTarget the DragDrop object we are inspecting
971      * @return {boolean} true if the mouse is over the target
972      * @private
973      * @static
974      */
975     isOverTarget: function(pt, oTarget, intersect) {
976         // use cache if available
977         var loc = this.locationCache[oTarget.id];
978         if (!loc || !this.useCache) {
979             loc = this.getLocation(oTarget);
980             this.locationCache[oTarget.id] = loc;
981
982         }
983
984         if (!loc) {
985             return false;
986         }
987
988         oTarget.cursorIsOver = loc.contains( pt );
989
990         // DragDrop is using this as a sanity check for the initial mousedown
991         // in this case we are done.  In POINT mode, if the drag obj has no
992         // contraints, we are also done. Otherwise we need to evaluate the
993         // location of the target as related to the actual location of the
994         // dragged element.
995         var dc = this.dragCurrent;
996         if (!dc || !dc.getTargetCoord ||
997                 (!intersect &amp;&amp; !dc.constrainX &amp;&amp; !dc.constrainY)) {
998             return oTarget.cursorIsOver;
999         }
1000
1001         oTarget.overlap = null;
1002
1003         // Get the current location of the drag element, this is the
1004         // location of the mouse event less the delta that represents
1005         // where the original mousedown happened on the element.  We
1006         // need to consider constraints and ticks as well.
1007         var pos = dc.getTargetCoord(pt.x, pt.y);
1008
1009         var el = dc.getDragEl();
1010         var curRegion = Ext.create('Ext.util.Region', pos.y,
1011                                                pos.x + el.offsetWidth,
1012                                                pos.y + el.offsetHeight,
1013                                                pos.x );
1014
1015         var overlap = curRegion.intersect(loc);
1016
1017         if (overlap) {
1018             oTarget.overlap = overlap;
1019             return (intersect) ? true : oTarget.cursorIsOver;
1020         } else {
1021             return false;
1022         }
1023     },
1024
1025 <span id='Ext-dd-DragDropManager-method-_onUnload'>    /**
1026 </span>     * unload event handler
1027      * @method _onUnload
1028      * @private
1029      * @static
1030      */
1031     _onUnload: function(e, me) {
1032         Ext.dd.DragDropManager.unregAll();
1033     },
1034
1035 <span id='Ext-dd-DragDropManager-method-unregAll'>    /**
1036 </span>     * Cleans up the drag and drop events and objects.
1037      * @method unregAll
1038      * @private
1039      * @static
1040      */
1041     unregAll: function() {
1042
1043         if (this.dragCurrent) {
1044             this.stopDrag();
1045             this.dragCurrent = null;
1046         }
1047
1048         this._execOnAll(&quot;unreg&quot;, []);
1049
1050         for (var i in this.elementCache) {
1051             delete this.elementCache[i];
1052         }
1053
1054         this.elementCache = {};
1055         this.ids = {};
1056     },
1057
1058 <span id='Ext-dd-DragDropManager-property-elementCache'>    /**
1059 </span>     * A cache of DOM elements
1060      * @property elementCache
1061      * @private
1062      * @static
1063      */
1064     elementCache: {},
1065
1066 <span id='Ext-dd-DragDropManager-method-getElWrapper'>    /**
1067 </span>     * Get the wrapper for the DOM element specified
1068      * @method getElWrapper
1069      * @param {String} id the id of the element to get
1070      * @return {Ext.dd.DDM.ElementWrapper} the wrapped element
1071      * @private
1072      * @deprecated This wrapper isn't that useful
1073      * @static
1074      */
1075     getElWrapper: function(id) {
1076         var oWrapper = this.elementCache[id];
1077         if (!oWrapper || !oWrapper.el) {
1078             oWrapper = this.elementCache[id] =
1079                 new this.ElementWrapper(Ext.getDom(id));
1080         }
1081         return oWrapper;
1082     },
1083
1084 <span id='Ext-dd-DragDropManager-method-getElement'>    /**
1085 </span>     * Returns the actual DOM element
1086      * @method getElement
1087      * @param {String} id the id of the elment to get
1088      * @return {Object} The element
1089      * @deprecated use Ext.lib.Ext.getDom instead
1090      * @static
1091      */
1092     getElement: function(id) {
1093         return Ext.getDom(id);
1094     },
1095
1096 <span id='Ext-dd-DragDropManager-method-getCss'>    /**
1097 </span>     * Returns the style property for the DOM element (i.e.,
1098      * document.getElById(id).style)
1099      * @method getCss
1100      * @param {String} id the id of the elment to get
1101      * @return {Object} The style property of the element
1102      * @static
1103      */
1104     getCss: function(id) {
1105         var el = Ext.getDom(id);
1106         return (el) ? el.style : null;
1107     },
1108
1109 <span id='Ext-dd-DragDropManager-ElementWrapper'>    /**
1110 </span>     * Inner class for cached elements
1111      * @class Ext.dd.DragDropManager.ElementWrapper
1112      * @for DragDropManager
1113      * @private
1114      * @deprecated
1115      */
1116     ElementWrapper: function(el) {
1117 <span id='Ext-dd-DragDropManager-ElementWrapper-property-el'>            /**
1118 </span>             * The element
1119              * @property el
1120              */
1121             this.el = el || null;
1122 <span id='Ext-dd-DragDropManager-ElementWrapper-property-id'>            /**
1123 </span>             * The element id
1124              * @property id
1125              */
1126             this.id = this.el &amp;&amp; el.id;
1127 <span id='Ext-dd-DragDropManager-ElementWrapper-property-css'>            /**
1128 </span>             * A reference to the style property
1129              * @property css
1130              */
1131             this.css = this.el &amp;&amp; el.style;
1132         },
1133
1134 <span id='Ext-dd-DragDropManager-ElementWrapper-method-getPosX'>    /**
1135 </span>     * Returns the X position of an html element
1136      * @method getPosX
1137      * @param el the element for which to get the position
1138      * @return {int} the X coordinate
1139      * @for DragDropManager
1140      * @static
1141      */
1142     getPosX: function(el) {
1143         return Ext.core.Element.getX(el);
1144     },
1145
1146 <span id='Ext-dd-DragDropManager-ElementWrapper-method-getPosY'>    /**
1147 </span>     * Returns the Y position of an html element
1148      * @method getPosY
1149      * @param el the element for which to get the position
1150      * @return {int} the Y coordinate
1151      * @static
1152      */
1153     getPosY: function(el) {
1154         return Ext.core.Element.getY(el);
1155     },
1156
1157 <span id='Ext-dd-DragDropManager-ElementWrapper-method-swapNode'>    /**
1158 </span>     * Swap two nodes.  In IE, we use the native method, for others we
1159      * emulate the IE behavior
1160      * @method swapNode
1161      * @param n1 the first node to swap
1162      * @param n2 the other node to swap
1163      * @static
1164      */
1165     swapNode: function(n1, n2) {
1166         if (n1.swapNode) {
1167             n1.swapNode(n2);
1168         } else {
1169             var p = n2.parentNode;
1170             var s = n2.nextSibling;
1171
1172             if (s == n1) {
1173                 p.insertBefore(n1, n2);
1174             } else if (n2 == n1.nextSibling) {
1175                 p.insertBefore(n2, n1);
1176             } else {
1177                 n1.parentNode.replaceChild(n2, n1);
1178                 p.insertBefore(n1, s);
1179             }
1180         }
1181     },
1182
1183 <span id='Ext-dd-DragDropManager-ElementWrapper-method-getScroll'>    /**
1184 </span>     * Returns the current scroll position
1185      * @method getScroll
1186      * @private
1187      * @static
1188      */
1189     getScroll: function () {
1190         var doc   = window.document,
1191             docEl = doc.documentElement,
1192             body  = doc.body,
1193             top   = 0,
1194             left  = 0;
1195             
1196         if (Ext.isGecko4) {
1197             top  = window.scrollYOffset;
1198             left = window.scrollXOffset;
1199         } else {
1200             if (docEl &amp;&amp; (docEl.scrollTop || docEl.scrollLeft)) {
1201                 top  = docEl.scrollTop;
1202                 left = docEl.scrollLeft;
1203             } else if (body) {
1204                 top  = body.scrollTop;
1205                 left = body.scrollLeft;
1206             } 
1207         }
1208         return {
1209             top: top,
1210             left: left
1211         };
1212     },
1213
1214 <span id='Ext-dd-DragDropManager-ElementWrapper-method-getStyle'>    /**
1215 </span>     * Returns the specified element style property
1216      * @method getStyle
1217      * @param {HTMLElement} el          the element
1218      * @param {string}      styleProp   the style property
1219      * @return {string} The value of the style property
1220      * @static
1221      */
1222     getStyle: function(el, styleProp) {
1223         return Ext.fly(el).getStyle(styleProp);
1224     },
1225
1226 <span id='Ext-dd-DragDropManager-ElementWrapper-method-getScrollTop'>    /**
1227 </span>     * Gets the scrollTop
1228      * @method getScrollTop
1229      * @return {int} the document's scrollTop
1230      * @static
1231      */
1232     getScrollTop: function () {
1233         return this.getScroll().top;
1234     },
1235
1236 <span id='Ext-dd-DragDropManager-ElementWrapper-method-getScrollLeft'>    /**
1237 </span>     * Gets the scrollLeft
1238      * @method getScrollLeft
1239      * @return {int} the document's scrollTop
1240      * @static
1241      */
1242     getScrollLeft: function () {
1243         return this.getScroll().left;
1244     },
1245
1246 <span id='Ext-dd-DragDropManager-ElementWrapper-method-moveToEl'>    /**
1247 </span>     * Sets the x/y position of an element to the location of the
1248      * target element.
1249      * @method moveToEl
1250      * @param {HTMLElement} moveEl      The element to move
1251      * @param {HTMLElement} targetEl    The position reference element
1252      * @static
1253      */
1254     moveToEl: function (moveEl, targetEl) {
1255         var aCoord = Ext.core.Element.getXY(targetEl);
1256         Ext.core.Element.setXY(moveEl, aCoord);
1257     },
1258
1259 <span id='Ext-dd-DragDropManager-ElementWrapper-method-numericSort'>    /**
1260 </span>     * Numeric array sort function
1261      * @method numericSort
1262      * @static
1263      */
1264     numericSort: function(a, b) {
1265         return (a - b);
1266     },
1267
1268 <span id='Ext-dd-DragDropManager-ElementWrapper-property-_timeoutCount'>    /**
1269 </span>     * Internal counter
1270      * @property _timeoutCount
1271      * @private
1272      * @static
1273      */
1274     _timeoutCount: 0,
1275
1276 <span id='Ext-dd-DragDropManager-ElementWrapper-method-_addListeners'>    /**
1277 </span>     * Trying to make the load order less important.  Without this we get
1278      * an error if this file is loaded before the Event Utility.
1279      * @method _addListeners
1280      * @private
1281      * @static
1282      */
1283     _addListeners: function() {
1284         if ( document ) {
1285             this._onLoad();
1286         } else {
1287             if (this._timeoutCount &gt; 2000) {
1288             } else {
1289                 setTimeout(this._addListeners, 10);
1290                 if (document &amp;&amp; document.body) {
1291                     this._timeoutCount += 1;
1292                 }
1293             }
1294         }
1295     },
1296
1297 <span id='Ext-dd-DragDropManager-ElementWrapper-method-handleWasClicked'>    /**
1298 </span>     * Recursively searches the immediate parent and all child nodes for
1299      * the handle element in order to determine wheter or not it was
1300      * clicked.
1301      * @method handleWasClicked
1302      * @param node the html element to inspect
1303      * @static
1304      */
1305     handleWasClicked: function(node, id) {
1306         if (this.isHandle(id, node.id)) {
1307             return true;
1308         } else {
1309             // check to see if this is a text node child of the one we want
1310             var p = node.parentNode;
1311
1312             while (p) {
1313                 if (this.isHandle(id, p.id)) {
1314                     return true;
1315                 } else {
1316                     p = p.parentNode;
1317                 }
1318             }
1319         }
1320
1321         return false;
1322     }
1323 }, function() {
1324     this._addListeners();
1325 });
1326 </pre>
1327 </body>
1328 </html>