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