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