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