author | Giulio Cesare Solaroli <giulio.cesare@solaroli.it> | 2011-10-03 16:04:12 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@solaroli.it> | 2011-10-03 16:04:12 (UTC) |
commit | 541bb378ddece2eab135a8066a16994e94436dea (patch) (unidiff) | |
tree | ff160ea3e26f7fe07fcfd401387c5a0232ca715e /frontend/beta/js/YUI/dragdrop.js | |
parent | 1bf431fd3d45cbdf4afa3e12afefe5d24f4d3bc7 (diff) | |
parent | ecad5e895831337216544e81f1a467e0c68c4a6a (diff) | |
download | clipperz-541bb378ddece2eab135a8066a16994e94436dea.zip clipperz-541bb378ddece2eab135a8066a16994e94436dea.tar.gz clipperz-541bb378ddece2eab135a8066a16994e94436dea.tar.bz2 |
Merge pull request #1 from gcsolaroli/master
First version of the restructured repository
Diffstat (limited to 'frontend/beta/js/YUI/dragdrop.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/beta/js/YUI/dragdrop.js | 2940 |
1 files changed, 2940 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI/dragdrop.js b/frontend/beta/js/YUI/dragdrop.js new file mode 100644 index 0000000..43a0f61 --- a/dev/null +++ b/frontend/beta/js/YUI/dragdrop.js | |||
@@ -0,0 +1,2940 @@ | |||
1 | /* | ||
2 | Copyright (c) 2006, Yahoo! Inc. All rights reserved. | ||
3 | Code licensed under the BSD License: | ||
4 | http://developer.yahoo.net/yui/license.txt | ||
5 | version: 0.12.0 | ||
6 | */ | ||
7 | |||
8 | (function() { | ||
9 | |||
10 | var Event=YAHOO.util.Event; | ||
11 | var Dom=YAHOO.util.Dom; | ||
12 | |||
13 | /** | ||
14 | * Defines the interface and base operation of items that that can be | ||
15 | * dragged or can be drop targets. It was designed to be extended, overriding | ||
16 | * the event handlers for startDrag, onDrag, onDragOver, onDragOut. | ||
17 | * Up to three html elements can be associated with a DragDrop instance: | ||
18 | * <ul> | ||
19 | * <li>linked element: the element that is passed into the constructor. | ||
20 | * This is the element which defines the boundaries for interaction with | ||
21 | * other DragDrop objects.</li> | ||
22 | * <li>handle element(s): The drag operation only occurs if the element that | ||
23 | * was clicked matches a handle element. By default this is the linked | ||
24 | * element, but there are times that you will want only a portion of the | ||
25 | * linked element to initiate the drag operation, and the setHandleElId() | ||
26 | * method provides a way to define this.</li> | ||
27 | * <li>drag element: this represents an the element that would be moved along | ||
28 | * with the cursor during a drag operation. By default, this is the linked | ||
29 | * element itself as in {@link YAHOO.util.DD}. setDragElId() lets you define | ||
30 | * a separate element that would be moved, as in {@link YAHOO.util.DDProxy} | ||
31 | * </li> | ||
32 | * </ul> | ||
33 | * This class should not be instantiated until the onload event to ensure that | ||
34 | * the associated elements are available. | ||
35 | * The following would define a DragDrop obj that would interact with any | ||
36 | * other DragDrop obj in the "group1" group: | ||
37 | * <pre> | ||
38 | * dd = new YAHOO.util.DragDrop("div1", "group1"); | ||
39 | * </pre> | ||
40 | * Since none of the event handlers have been implemented, nothing would | ||
41 | * actually happen if you were to run the code above. Normally you would | ||
42 | * override this class or one of the default implementations, but you can | ||
43 | * also override the methods you want on an instance of the class... | ||
44 | * <pre> | ||
45 | * dd.onDragDrop = function(e, id) { | ||
46 | * alert("dd was dropped on " + id); | ||
47 | * } | ||
48 | * </pre> | ||
49 | * @namespace YAHOO.util | ||
50 | * @class DragDrop | ||
51 | * @constructor | ||
52 | * @param {String} id of the element that is linked to this instance | ||
53 | * @param {String} sGroup the group of related DragDrop objects | ||
54 | * @param {object} config an object containing configurable attributes | ||
55 | * Valid properties for DragDrop: | ||
56 | * padding, isTarget, maintainOffset, primaryButtonOnly | ||
57 | */ | ||
58 | YAHOO.util.DragDrop = function(id, sGroup, config) { | ||
59 | if (id) { | ||
60 | this.init(id, sGroup, config); | ||
61 | } | ||
62 | }; | ||
63 | |||
64 | YAHOO.util.DragDrop.prototype = { | ||
65 | |||
66 | /** | ||
67 | * The id of the element associated with this object. This is what we | ||
68 | * refer to as the "linked element" because the size and position of | ||
69 | * this element is used to determine when the drag and drop objects have | ||
70 | * interacted. | ||
71 | * @property id | ||
72 | * @type String | ||
73 | */ | ||
74 | id: null, | ||
75 | |||
76 | /** | ||
77 | * Configuration attributes passed into the constructor | ||
78 | * @property config | ||
79 | * @type object | ||
80 | */ | ||
81 | config: null, | ||
82 | |||
83 | /** | ||
84 | * The id of the element that will be dragged. By default this is same | ||
85 | * as the linked element , but could be changed to another element. Ex: | ||
86 | * YAHOO.util.DDProxy | ||
87 | * @property dragElId | ||
88 | * @type String | ||
89 | * @private | ||
90 | */ | ||
91 | dragElId: null, | ||
92 | |||
93 | /** | ||
94 | * the id of the element that initiates the drag operation. By default | ||
95 | * this is the linked element, but could be changed to be a child of this | ||
96 | * element. This lets us do things like only starting the drag when the | ||
97 | * header element within the linked html element is clicked. | ||
98 | * @property handleElId | ||
99 | * @type String | ||
100 | * @private | ||
101 | */ | ||
102 | handleElId: null, | ||
103 | |||
104 | /** | ||
105 | * An associative array of HTML tags that will be ignored if clicked. | ||
106 | * @property invalidHandleTypes | ||
107 | * @type {string: string} | ||
108 | */ | ||
109 | invalidHandleTypes: null, | ||
110 | |||
111 | /** | ||
112 | * An associative array of ids for elements that will be ignored if clicked | ||
113 | * @property invalidHandleIds | ||
114 | * @type {string: string} | ||
115 | */ | ||
116 | invalidHandleIds: null, | ||
117 | |||
118 | /** | ||
119 | * An indexted array of css class names for elements that will be ignored | ||
120 | * if clicked. | ||
121 | * @property invalidHandleClasses | ||
122 | * @type string[] | ||
123 | */ | ||
124 | invalidHandleClasses: null, | ||
125 | |||
126 | /** | ||
127 | * The linked element's absolute X position at the time the drag was | ||
128 | * started | ||
129 | * @property startPageX | ||
130 | * @type int | ||
131 | * @private | ||
132 | */ | ||
133 | startPageX: 0, | ||
134 | |||
135 | /** | ||
136 | * The linked element's absolute X position at the time the drag was | ||
137 | * started | ||
138 | * @property startPageY | ||
139 | * @type int | ||
140 | * @private | ||
141 | */ | ||
142 | startPageY: 0, | ||
143 | |||
144 | /** | ||
145 | * The group defines a logical collection of DragDrop objects that are | ||
146 | * related. Instances only get events when interacting with other | ||
147 | * DragDrop object in the same group. This lets us define multiple | ||
148 | * groups using a single DragDrop subclass if we want. | ||
149 | * @property groups | ||
150 | * @type {string: string} | ||
151 | */ | ||
152 | groups: null, | ||
153 | |||
154 | /** | ||
155 | * Individual drag/drop instances can be locked. This will prevent | ||
156 | * onmousedown start drag. | ||
157 | * @property locked | ||
158 | * @type boolean | ||
159 | * @private | ||
160 | */ | ||
161 | locked: false, | ||
162 | |||
163 | /** | ||
164 | * Lock this instance | ||
165 | * @method lock | ||
166 | */ | ||
167 | lock: function() { this.locked = true; }, | ||
168 | |||
169 | /** | ||
170 | * Unlock this instace | ||
171 | * @method unlock | ||
172 | */ | ||
173 | unlock: function() { this.locked = false; }, | ||
174 | |||
175 | /** | ||
176 | * By default, all insances can be a drop target. This can be disabled by | ||
177 | * setting isTarget to false. | ||
178 | * @method isTarget | ||
179 | * @type boolean | ||
180 | */ | ||
181 | isTarget: true, | ||
182 | |||
183 | /** | ||
184 | * The padding configured for this drag and drop object for calculating | ||
185 | * the drop zone intersection with this object. | ||
186 | * @method padding | ||
187 | * @type int[] | ||
188 | */ | ||
189 | padding: null, | ||
190 | |||
191 | /** | ||
192 | * Cached reference to the linked element | ||
193 | * @property _domRef | ||
194 | * @private | ||
195 | */ | ||
196 | _domRef: null, | ||
197 | |||
198 | /** | ||
199 | * Internal typeof flag | ||
200 | * @property __ygDragDrop | ||
201 | * @private | ||
202 | */ | ||
203 | __ygDragDrop: true, | ||
204 | |||
205 | /** | ||
206 | * Set to true when horizontal contraints are applied | ||
207 | * @property constrainX | ||
208 | * @type boolean | ||
209 | * @private | ||
210 | */ | ||
211 | constrainX: false, | ||
212 | |||
213 | /** | ||
214 | * Set to true when vertical contraints are applied | ||
215 | * @property constrainY | ||
216 | * @type boolean | ||
217 | * @private | ||
218 | */ | ||
219 | constrainY: false, | ||
220 | |||
221 | /** | ||
222 | * The left constraint | ||
223 | * @property minX | ||
224 | * @type int | ||
225 | * @private | ||
226 | */ | ||
227 | minX: 0, | ||
228 | |||
229 | /** | ||
230 | * The right constraint | ||
231 | * @property maxX | ||
232 | * @type int | ||
233 | * @private | ||
234 | */ | ||
235 | maxX: 0, | ||
236 | |||
237 | /** | ||
238 | * The up constraint | ||
239 | * @property minY | ||
240 | * @type int | ||
241 | * @type int | ||
242 | * @private | ||
243 | */ | ||
244 | minY: 0, | ||
245 | |||
246 | /** | ||
247 | * The down constraint | ||
248 | * @property maxY | ||
249 | * @type int | ||
250 | * @private | ||
251 | */ | ||
252 | maxY: 0, | ||
253 | |||
254 | /** | ||
255 | * Maintain offsets when we resetconstraints. Set to true when you want | ||
256 | * the position of the element relative to its parent to stay the same | ||
257 | * when the page changes | ||
258 | * | ||
259 | * @property maintainOffset | ||
260 | * @type boolean | ||
261 | */ | ||
262 | maintainOffset: false, | ||
263 | |||
264 | /** | ||
265 | * Array of pixel locations the element will snap to if we specified a | ||
266 | * horizontal graduation/interval. This array is generated automatically | ||
267 | * when you define a tick interval. | ||
268 | * @property xTicks | ||
269 | * @type int[] | ||
270 | */ | ||
271 | xTicks: null, | ||
272 | |||
273 | /** | ||
274 | * Array of pixel locations the element will snap to if we specified a | ||
275 | * vertical graduation/interval. This array is generated automatically | ||
276 | * when you define a tick interval. | ||
277 | * @property yTicks | ||
278 | * @type int[] | ||
279 | */ | ||
280 | yTicks: null, | ||
281 | |||
282 | /** | ||
283 | * By default the drag and drop instance will only respond to the primary | ||
284 | * button click (left button for a right-handed mouse). Set to true to | ||
285 | * allow drag and drop to start with any mouse click that is propogated | ||
286 | * by the browser | ||
287 | * @property primaryButtonOnly | ||
288 | * @type boolean | ||
289 | */ | ||
290 | primaryButtonOnly: true, | ||
291 | |||
292 | /** | ||
293 | * The availabe property is false until the linked dom element is accessible. | ||
294 | * @property available | ||
295 | * @type boolean | ||
296 | */ | ||
297 | available: false, | ||
298 | |||
299 | /** | ||
300 | * By default, drags can only be initiated if the mousedown occurs in the | ||
301 | * region the linked element is. This is done in part to work around a | ||
302 | * bug in some browsers that mis-report the mousedown if the previous | ||
303 | * mouseup happened outside of the window. This property is set to true | ||
304 | * if outer handles are defined. | ||
305 | * | ||
306 | * @property hasOuterHandles | ||
307 | * @type boolean | ||
308 | * @default false | ||
309 | */ | ||
310 | hasOuterHandles: false, | ||
311 | |||
312 | /** | ||
313 | * Code that executes immediately before the startDrag event | ||
314 | * @method b4StartDrag | ||
315 | * @private | ||
316 | */ | ||
317 | b4StartDrag: function(x, y) { }, | ||
318 | |||
319 | /** | ||
320 | * Abstract method called after a drag/drop object is clicked | ||
321 | * and the drag or mousedown time thresholds have beeen met. | ||
322 | * @method startDrag | ||
323 | * @param {int} X click location | ||
324 | * @param {int} Y click location | ||
325 | */ | ||
326 | startDrag: function(x, y) { /* override this */ }, | ||
327 | |||
328 | /** | ||
329 | * Code that executes immediately before the onDrag event | ||
330 | * @method b4Drag | ||
331 | * @private | ||
332 | */ | ||
333 | b4Drag: function(e) { }, | ||
334 | |||
335 | /** | ||
336 | * Abstract method called during the onMouseMove event while dragging an | ||
337 | * object. | ||
338 | * @method onDrag | ||
339 | * @param {Event} e the mousemove event | ||
340 | */ | ||
341 | onDrag: function(e) { /* override this */ }, | ||
342 | |||
343 | /** | ||
344 | * Abstract method called when this element fist begins hovering over | ||
345 | * another DragDrop obj | ||
346 | * @method onDragEnter | ||
347 | * @param {Event} e the mousemove event | ||
348 | * @param {String|DragDrop[]} id In POINT mode, the element | ||
349 | * id this is hovering over. In INTERSECT mode, an array of one or more | ||
350 | * dragdrop items being hovered over. | ||
351 | */ | ||
352 | onDragEnter: function(e, id) { /* override this */ }, | ||
353 | |||
354 | /** | ||
355 | * Code that executes immediately before the onDragOver event | ||
356 | * @method b4DragOver | ||
357 | * @private | ||
358 | */ | ||
359 | b4DragOver: function(e) { }, | ||
360 | |||
361 | /** | ||
362 | * Abstract method called when this element is hovering over another | ||
363 | * DragDrop obj | ||
364 | * @method onDragOver | ||
365 | * @param {Event} e the mousemove event | ||
366 | * @param {String|DragDrop[]} id In POINT mode, the element | ||
367 | * id this is hovering over. In INTERSECT mode, an array of dd items | ||
368 | * being hovered over. | ||
369 | */ | ||
370 | onDragOver: function(e, id) { /* override this */ }, | ||
371 | |||
372 | /** | ||
373 | * Code that executes immediately before the onDragOut event | ||
374 | * @method b4DragOut | ||
375 | * @private | ||
376 | */ | ||
377 | b4DragOut: function(e) { }, | ||
378 | |||
379 | /** | ||
380 | * Abstract method called when we are no longer hovering over an element | ||
381 | * @method onDragOut | ||
382 | * @param {Event} e the mousemove event | ||
383 | * @param {String|DragDrop[]} id In POINT mode, the element | ||
384 | * id this was hovering over. In INTERSECT mode, an array of dd items | ||
385 | * that the mouse is no longer over. | ||
386 | */ | ||
387 | onDragOut: function(e, id) { /* override this */ }, | ||
388 | |||
389 | /** | ||
390 | * Code that executes immediately before the onDragDrop event | ||
391 | * @method b4DragDrop | ||
392 | * @private | ||
393 | */ | ||
394 | b4DragDrop: function(e) { }, | ||
395 | |||
396 | /** | ||
397 | * Abstract method called when this item is dropped on another DragDrop | ||
398 | * obj | ||
399 | * @method onDragDrop | ||
400 | * @param {Event} e the mouseup event | ||
401 | * @param {String|DragDrop[]} id In POINT mode, the element | ||
402 | * id this was dropped on. In INTERSECT mode, an array of dd items this | ||
403 | * was dropped on. | ||
404 | */ | ||
405 | onDragDrop: function(e, id) { /* override this */ }, | ||
406 | |||
407 | /** | ||
408 | * Abstract method called when this item is dropped on an area with no | ||
409 | * drop target | ||
410 | * @method onInvalidDrop | ||
411 | * @param {Event} e the mouseup event | ||
412 | */ | ||
413 | onInvalidDrop: function(e) { /* override this */ }, | ||
414 | |||
415 | /** | ||
416 | * Code that executes immediately before the endDrag event | ||
417 | * @method b4EndDrag | ||
418 | * @private | ||
419 | */ | ||
420 | b4EndDrag: function(e) { }, | ||
421 | |||
422 | /** | ||
423 | * Fired when we are done dragging the object | ||
424 | * @method endDrag | ||
425 | * @param {Event} e the mouseup event | ||
426 | */ | ||
427 | endDrag: function(e) { /* override this */ }, | ||
428 | |||
429 | /** | ||
430 | * Code executed immediately before the onMouseDown event | ||
431 | * @method b4MouseDown | ||
432 | * @param {Event} e the mousedown event | ||
433 | * @private | ||
434 | */ | ||
435 | b4MouseDown: function(e) { }, | ||
436 | |||
437 | /** | ||
438 | * Event handler that fires when a drag/drop obj gets a mousedown | ||
439 | * @method onMouseDown | ||
440 | * @param {Event} e the mousedown event | ||
441 | */ | ||
442 | onMouseDown: function(e) { /* override this */ }, | ||
443 | |||
444 | /** | ||
445 | * Event handler that fires when a drag/drop obj gets a mouseup | ||
446 | * @method onMouseUp | ||
447 | * @param {Event} e the mouseup event | ||
448 | */ | ||
449 | onMouseUp: function(e) { /* override this */ }, | ||
450 | |||
451 | /** | ||
452 | * Override the onAvailable method to do what is needed after the initial | ||
453 | * position was determined. | ||
454 | * @method onAvailable | ||
455 | */ | ||
456 | onAvailable: function () { | ||
457 | }, | ||
458 | |||
459 | /** | ||
460 | * Returns a reference to the linked element | ||
461 | * @method getEl | ||
462 | * @return {HTMLElement} the html element | ||
463 | */ | ||
464 | getEl: function() { | ||
465 | if (!this._domRef) { | ||
466 | this._domRef = Dom.get(this.id); | ||
467 | } | ||
468 | |||
469 | return this._domRef; | ||
470 | }, | ||
471 | |||
472 | /** | ||
473 | * Returns a reference to the actual element to drag. By default this is | ||
474 | * the same as the html element, but it can be assigned to another | ||
475 | * element. An example of this can be found in YAHOO.util.DDProxy | ||
476 | * @method getDragEl | ||
477 | * @return {HTMLElement} the html element | ||
478 | */ | ||
479 | getDragEl: function() { | ||
480 | return Dom.get(this.dragElId); | ||
481 | }, | ||
482 | |||
483 | /** | ||
484 | * Sets up the DragDrop object. Must be called in the constructor of any | ||
485 | * YAHOO.util.DragDrop subclass | ||
486 | * @method init | ||
487 | * @param id the id of the linked element | ||
488 | * @param {String} sGroup the group of related items | ||
489 | * @param {object} config configuration attributes | ||
490 | */ | ||
491 | init: function(id, sGroup, config) { | ||
492 | this.initTarget(id, sGroup, config); | ||
493 | Event.on(this.id, "mousedown", this.handleMouseDown, this, true); | ||
494 | // Event.on(this.id, "selectstart", Event.preventDefault); | ||
495 | }, | ||
496 | |||
497 | /** | ||
498 | * Initializes Targeting functionality only... the object does not | ||
499 | * get a mousedown handler. | ||
500 | * @method initTarget | ||
501 | * @param id the id of the linked element | ||
502 | * @param {String} sGroup the group of related items | ||
503 | * @param {object} config configuration attributes | ||
504 | */ | ||
505 | initTarget: function(id, sGroup, config) { | ||
506 | |||
507 | // configuration attributes | ||
508 | this.config = config || {}; | ||
509 | |||
510 | // create a local reference to the drag and drop manager | ||
511 | this.DDM = YAHOO.util.DDM; | ||
512 | // initialize the groups array | ||
513 | this.groups = {}; | ||
514 | |||
515 | // assume that we have an element reference instead of an id if the | ||
516 | // parameter is not a string | ||
517 | if (typeof id !== "string") { | ||
518 | YAHOO.log("id is not a string, assuming it is an HTMLElement"); | ||
519 | id = Dom.generateId(id); | ||
520 | } | ||
521 | |||
522 | // set the id | ||
523 | this.id = id; | ||
524 | |||
525 | // add to an interaction group | ||
526 | this.addToGroup((sGroup) ? sGroup : "default"); | ||
527 | |||
528 | // We don't want to register this as the handle with the manager | ||
529 | // so we just set the id rather than calling the setter. | ||
530 | this.handleElId = id; | ||
531 | |||
532 | Event.onAvailable(id, this.handleOnAvailable, this, true); | ||
533 | |||
534 | |||
535 | // the linked element is the element that gets dragged by default | ||
536 | this.setDragElId(id); | ||
537 | |||
538 | // by default, clicked anchors will not start drag operations. | ||
539 | // @TODO what else should be here? Probably form fields. | ||
540 | this.invalidHandleTypes = { A: "A" }; | ||
541 | this.invalidHandleIds = {}; | ||
542 | this.invalidHandleClasses = []; | ||
543 | |||
544 | this.applyConfig(); | ||
545 | }, | ||
546 | |||
547 | /** | ||
548 | * Applies the configuration parameters that were passed into the constructor. | ||
549 | * This is supposed to happen at each level through the inheritance chain. So | ||
550 | * a DDProxy implentation will execute apply config on DDProxy, DD, and | ||
551 | * DragDrop in order to get all of the parameters that are available in | ||
552 | * each object. | ||
553 | * @method applyConfig | ||
554 | */ | ||
555 | applyConfig: function() { | ||
556 | |||
557 | // configurable properties: | ||
558 | // padding, isTarget, maintainOffset, primaryButtonOnly | ||
559 | this.padding = this.config.padding || [0, 0, 0, 0]; | ||
560 | this.isTarget = (this.config.isTarget !== false); | ||
561 | this.maintainOffset = (this.config.maintainOffset); | ||
562 | this.primaryButtonOnly = (this.config.primaryButtonOnly !== false); | ||
563 | |||
564 | }, | ||
565 | |||
566 | /** | ||
567 | * Executed when the linked element is available | ||
568 | * @method handleOnAvailable | ||
569 | * @private | ||
570 | */ | ||
571 | handleOnAvailable: function() { | ||
572 | this.available = true; | ||
573 | this.resetConstraints(); | ||
574 | this.onAvailable(); | ||
575 | }, | ||
576 | |||
577 | /** | ||
578 | * Configures the padding for the target zone in px. Effectively expands | ||
579 | * (or reduces) the virtual object size for targeting calculations. | ||
580 | * Supports css-style shorthand; if only one parameter is passed, all sides | ||
581 | * will have that padding, and if only two are passed, the top and bottom | ||
582 | * will have the first param, the left and right the second. | ||
583 | * @method setPadding | ||
584 | * @param {int} iTop Top pad | ||
585 | * @param {int} iRight Right pad | ||
586 | * @param {int} iBot Bot pad | ||
587 | * @param {int} iLeft Left pad | ||
588 | */ | ||
589 | setPadding: function(iTop, iRight, iBot, iLeft) { | ||
590 | // this.padding = [iLeft, iRight, iTop, iBot]; | ||
591 | if (!iRight && 0 !== iRight) { | ||
592 | this.padding = [iTop, iTop, iTop, iTop]; | ||
593 | } else if (!iBot && 0 !== iBot) { | ||
594 | this.padding = [iTop, iRight, iTop, iRight]; | ||
595 | } else { | ||
596 | this.padding = [iTop, iRight, iBot, iLeft]; | ||
597 | } | ||
598 | }, | ||
599 | |||
600 | /** | ||
601 | * Stores the initial placement of the linked element. | ||
602 | * @method setInitialPosition | ||
603 | * @param {int} diffX the X offset, default 0 | ||
604 | * @param {int} diffY the Y offset, default 0 | ||
605 | */ | ||
606 | setInitPosition: function(diffX, diffY) { | ||
607 | var el = this.getEl(); | ||
608 | |||
609 | if (!this.DDM.verifyEl(el)) { | ||
610 | return; | ||
611 | } | ||
612 | |||
613 | var dx = diffX || 0; | ||
614 | var dy = diffY || 0; | ||
615 | |||
616 | var p = Dom.getXY( el ); | ||
617 | |||
618 | this.initPageX = p[0] - dx; | ||
619 | this.initPageY = p[1] - dy; | ||
620 | |||
621 | this.lastPageX = p[0]; | ||
622 | this.lastPageY = p[1]; | ||
623 | |||
624 | |||
625 | this.setStartPosition(p); | ||
626 | }, | ||
627 | |||
628 | /** | ||
629 | * Sets the start position of the element. This is set when the obj | ||
630 | * is initialized, the reset when a drag is started. | ||
631 | * @method setStartPosition | ||
632 | * @param pos current position (from previous lookup) | ||
633 | * @private | ||
634 | */ | ||
635 | setStartPosition: function(pos) { | ||
636 | var p = pos || Dom.getXY( this.getEl() ); | ||
637 | this.deltaSetXY = null; | ||
638 | |||
639 | this.startPageX = p[0]; | ||
640 | this.startPageY = p[1]; | ||
641 | }, | ||
642 | |||
643 | /** | ||
644 | * Add this instance to a group of related drag/drop objects. All | ||
645 | * instances belong to at least one group, and can belong to as many | ||
646 | * groups as needed. | ||
647 | * @method addToGroup | ||
648 | * @param sGroup {string} the name of the group | ||
649 | */ | ||
650 | addToGroup: function(sGroup) { | ||
651 | this.groups[sGroup] = true; | ||
652 | this.DDM.regDragDrop(this, sGroup); | ||
653 | }, | ||
654 | |||
655 | /** | ||
656 | * Remove's this instance from the supplied interaction group | ||
657 | * @method removeFromGroup | ||
658 | * @param {string} sGroup The group to drop | ||
659 | */ | ||
660 | removeFromGroup: function(sGroup) { | ||
661 | if (this.groups[sGroup]) { | ||
662 | delete this.groups[sGroup]; | ||
663 | } | ||
664 | |||
665 | this.DDM.removeDDFromGroup(this, sGroup); | ||
666 | }, | ||
667 | |||
668 | /** | ||
669 | * Allows you to specify that an element other than the linked element | ||
670 | * will be moved with the cursor during a drag | ||
671 | * @method setDragElId | ||
672 | * @param id {string} the id of the element that will be used to initiate the drag | ||
673 | */ | ||
674 | setDragElId: function(id) { | ||
675 | this.dragElId = id; | ||
676 | }, | ||
677 | |||
678 | /** | ||
679 | * Allows you to specify a child of the linked element that should be | ||
680 | * used to initiate the drag operation. An example of this would be if | ||
681 | * you have a content div with text and links. Clicking anywhere in the | ||
682 | * content area would normally start the drag operation. Use this method | ||
683 | * to specify that an element inside of the content div is the element | ||
684 | * that starts the drag operation. | ||
685 | * @method setHandleElId | ||
686 | * @param id {string} the id of the element that will be used to | ||
687 | * initiate the drag. | ||
688 | */ | ||
689 | setHandleElId: function(id) { | ||
690 | if (typeof id !== "string") { | ||
691 | YAHOO.log("id is not a string, assuming it is an HTMLElement"); | ||
692 | id = Dom.generateId(id); | ||
693 | } | ||
694 | this.handleElId = id; | ||
695 | this.DDM.regHandle(this.id, id); | ||
696 | }, | ||
697 | |||
698 | /** | ||
699 | * Allows you to set an element outside of the linked element as a drag | ||
700 | * handle | ||
701 | * @method setOuterHandleElId | ||
702 | * @param id the id of the element that will be used to initiate the drag | ||
703 | */ | ||
704 | setOuterHandleElId: function(id) { | ||
705 | if (typeof id !== "string") { | ||
706 | YAHOO.log("id is not a string, assuming it is an HTMLElement"); | ||
707 | id = Dom.generateId(id); | ||
708 | } | ||
709 | Event.on(id, "mousedown", | ||
710 | this.handleMouseDown, this, true); | ||
711 | this.setHandleElId(id); | ||
712 | |||
713 | this.hasOuterHandles = true; | ||
714 | }, | ||
715 | |||
716 | /** | ||
717 | * Remove all drag and drop hooks for this element | ||
718 | * @method unreg | ||
719 | */ | ||
720 | unreg: function() { | ||
721 | Event.removeListener(this.id, "mousedown", | ||
722 | this.handleMouseDown); | ||
723 | this._domRef = null; | ||
724 | this.DDM._remove(this); | ||
725 | }, | ||
726 | |||
727 | /** | ||
728 | * Returns true if this instance is locked, or the drag drop mgr is locked | ||
729 | * (meaning that all drag/drop is disabled on the page.) | ||
730 | * @method isLocked | ||
731 | * @return {boolean} true if this obj or all drag/drop is locked, else | ||
732 | * false | ||
733 | */ | ||
734 | isLocked: function() { | ||
735 | return (this.DDM.isLocked() || this.locked); | ||
736 | }, | ||
737 | |||
738 | /** | ||
739 | * Fired when this object is clicked | ||
740 | * @method handleMouseDown | ||
741 | * @param {Event} e | ||
742 | * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj) | ||
743 | * @private | ||
744 | */ | ||
745 | handleMouseDown: function(e, oDD) { | ||
746 | |||
747 | var button = e.which || e.button; | ||
748 | |||
749 | if (this.primaryButtonOnly && button > 1) { | ||
750 | return; | ||
751 | } | ||
752 | |||
753 | if (this.isLocked()) { | ||
754 | return; | ||
755 | } | ||
756 | |||
757 | this.DDM.refreshCache(this.groups); | ||
758 | // var self = this; | ||
759 | // setTimeout( function() { self.DDM.refreshCache(self.groups); }, 0); | ||
760 | |||
761 | // Only process the event if we really clicked within the linked | ||
762 | // element. The reason we make this check is that in the case that | ||
763 | // another element was moved between the clicked element and the | ||
764 | // cursor in the time between the mousedown and mouseup events. When | ||
765 | // this happens, the element gets the next mousedown event | ||
766 | // regardless of where on the screen it happened. | ||
767 | var pt = new YAHOO.util.Point(Event.getPageX(e), Event.getPageY(e)); | ||
768 | if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) { | ||
769 | } else { | ||
770 | if (this.clickValidator(e)) { | ||
771 | |||
772 | |||
773 | // set the initial element position | ||
774 | this.setStartPosition(); | ||
775 | |||
776 | |||
777 | this.b4MouseDown(e); | ||
778 | this.onMouseDown(e); | ||
779 | this.DDM.handleMouseDown(e, this); | ||
780 | |||
781 | this.DDM.stopEvent(e); | ||
782 | } else { | ||
783 | |||
784 | |||
785 | } | ||
786 | } | ||
787 | }, | ||
788 | |||
789 | clickValidator: function(e) { | ||
790 | var target = Event.getTarget(e); | ||
791 | return ( this.isValidHandleChild(target) && | ||
792 | (this.id == this.handleElId || | ||
793 | this.DDM.handleWasClicked(target, this.id)) ); | ||
794 | }, | ||
795 | |||
796 | /** | ||
797 | * Allows you to specify a tag name that should not start a drag operation | ||
798 | * when clicked. This is designed to facilitate embedding links within a | ||
799 | * drag handle that do something other than start the drag. | ||
800 | * @method addInvalidHandleType | ||
801 | * @param {string} tagName the type of element to exclude | ||
802 | */ | ||
803 | addInvalidHandleType: function(tagName) { | ||
804 | var type = tagName.toUpperCase(); | ||
805 | this.invalidHandleTypes[type] = type; | ||
806 | }, | ||
807 | |||
808 | /** | ||
809 | * Lets you to specify an element id for a child of a drag handle | ||
810 | * that should not initiate a drag | ||
811 | * @method addInvalidHandleId | ||
812 | * @param {string} id the element id of the element you wish to ignore | ||
813 | */ | ||
814 | addInvalidHandleId: function(id) { | ||
815 | if (typeof id !== "string") { | ||
816 | YAHOO.log("id is not a string, assuming it is an HTMLElement"); | ||
817 | id = Dom.generateId(id); | ||
818 | } | ||
819 | this.invalidHandleIds[id] = id; | ||
820 | }, | ||
821 | |||
822 | /** | ||
823 | * Lets you specify a css class of elements that will not initiate a drag | ||
824 | * @method addInvalidHandleClass | ||
825 | * @param {string} cssClass the class of the elements you wish to ignore | ||
826 | */ | ||
827 | addInvalidHandleClass: function(cssClass) { | ||
828 | this.invalidHandleClasses.push(cssClass); | ||
829 | }, | ||
830 | |||
831 | /** | ||
832 | * Unsets an excluded tag name set by addInvalidHandleType | ||
833 | * @method removeInvalidHandleType | ||
834 | * @param {string} tagName the type of element to unexclude | ||
835 | */ | ||
836 | removeInvalidHandleType: function(tagName) { | ||
837 | var type = tagName.toUpperCase(); | ||
838 | // this.invalidHandleTypes[type] = null; | ||
839 | delete this.invalidHandleTypes[type]; | ||
840 | }, | ||
841 | |||
842 | /** | ||
843 | * Unsets an invalid handle id | ||
844 | * @method removeInvalidHandleId | ||
845 | * @param {string} id the id of the element to re-enable | ||
846 | */ | ||
847 | removeInvalidHandleId: function(id) { | ||
848 | if (typeof id !== "string") { | ||
849 | YAHOO.log("id is not a string, assuming it is an HTMLElement"); | ||
850 | id = Dom.generateId(id); | ||
851 | } | ||
852 | delete this.invalidHandleIds[id]; | ||
853 | }, | ||
854 | |||
855 | /** | ||
856 | * Unsets an invalid css class | ||
857 | * @method removeInvalidHandleClass | ||
858 | * @param {string} cssClass the class of the element(s) you wish to | ||
859 | * re-enable | ||
860 | */ | ||
861 | removeInvalidHandleClass: function(cssClass) { | ||
862 | for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) { | ||
863 | if (this.invalidHandleClasses[i] == cssClass) { | ||
864 | delete this.invalidHandleClasses[i]; | ||
865 | } | ||
866 | } | ||
867 | }, | ||
868 | |||
869 | /** | ||
870 | * Checks the tag exclusion list to see if this click should be ignored | ||
871 | * @method isValidHandleChild | ||
872 | * @param {HTMLElement} node the HTMLElement to evaluate | ||
873 | * @return {boolean} true if this is a valid tag type, false if not | ||
874 | */ | ||
875 | isValidHandleChild: function(node) { | ||
876 | |||
877 | var valid = true; | ||
878 | // var n = (node.nodeName == "#text") ? node.parentNode : node; | ||
879 | var nodeName; | ||
880 | try { | ||
881 | nodeName = node.nodeName.toUpperCase(); | ||
882 | } catch(e) { | ||
883 | nodeName = node.nodeName; | ||
884 | } | ||
885 | valid = valid && !this.invalidHandleTypes[nodeName]; | ||
886 | valid = valid && !this.invalidHandleIds[node.id]; | ||
887 | |||
888 | for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) { | ||
889 | valid = !Dom.hasClass(node, this.invalidHandleClasses[i]); | ||
890 | } | ||
891 | |||
892 | |||
893 | return valid; | ||
894 | |||
895 | }, | ||
896 | |||
897 | /** | ||
898 | * Create the array of horizontal tick marks if an interval was specified | ||
899 | * in setXConstraint(). | ||
900 | * @method setXTicks | ||
901 | * @private | ||
902 | */ | ||
903 | setXTicks: function(iStartX, iTickSize) { | ||
904 | this.xTicks = []; | ||
905 | this.xTickSize = iTickSize; | ||
906 | |||
907 | var tickMap = {}; | ||
908 | |||
909 | for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) { | ||
910 | if (!tickMap[i]) { | ||
911 | this.xTicks[this.xTicks.length] = i; | ||
912 | tickMap[i] = true; | ||
913 | } | ||
914 | } | ||
915 | |||
916 | for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) { | ||
917 | if (!tickMap[i]) { | ||
918 | this.xTicks[this.xTicks.length] = i; | ||
919 | tickMap[i] = true; | ||
920 | } | ||
921 | } | ||
922 | |||
923 | this.xTicks.sort(this.DDM.numericSort) ; | ||
924 | }, | ||
925 | |||
926 | /** | ||
927 | * Create the array of vertical tick marks if an interval was specified in | ||
928 | * setYConstraint(). | ||
929 | * @method setYTicks | ||
930 | * @private | ||
931 | */ | ||
932 | setYTicks: function(iStartY, iTickSize) { | ||
933 | this.yTicks = []; | ||
934 | this.yTickSize = iTickSize; | ||
935 | |||
936 | var tickMap = {}; | ||
937 | |||
938 | for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) { | ||
939 | if (!tickMap[i]) { | ||
940 | this.yTicks[this.yTicks.length] = i; | ||
941 | tickMap[i] = true; | ||
942 | } | ||
943 | } | ||
944 | |||
945 | for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) { | ||
946 | if (!tickMap[i]) { | ||
947 | this.yTicks[this.yTicks.length] = i; | ||
948 | tickMap[i] = true; | ||
949 | } | ||
950 | } | ||
951 | |||
952 | this.yTicks.sort(this.DDM.numericSort) ; | ||
953 | }, | ||
954 | |||
955 | /** | ||
956 | * By default, the element can be dragged any place on the screen. Use | ||
957 | * this method to limit the horizontal travel of the element. Pass in | ||
958 | * 0,0 for the parameters if you want to lock the drag to the y axis. | ||
959 | * @method setXConstraint | ||
960 | * @param {int} iLeft the number of pixels the element can move to the left | ||
961 | * @param {int} iRight the number of pixels the element can move to the | ||
962 | * right | ||
963 | * @param {int} iTickSize optional parameter for specifying that the | ||
964 | * element | ||
965 | * should move iTickSize pixels at a time. | ||
966 | */ | ||
967 | setXConstraint: function(iLeft, iRight, iTickSize) { | ||
968 | this.leftConstraint = iLeft; | ||
969 | this.rightConstraint = iRight; | ||
970 | |||
971 | this.minX = this.initPageX - iLeft; | ||
972 | this.maxX = this.initPageX + iRight; | ||
973 | if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); } | ||
974 | |||
975 | this.constrainX = true; | ||
976 | }, | ||
977 | |||
978 | /** | ||
979 | * Clears any constraints applied to this instance. Also clears ticks | ||
980 | * since they can't exist independent of a constraint at this time. | ||
981 | * @method clearConstraints | ||
982 | */ | ||
983 | clearConstraints: function() { | ||
984 | this.constrainX = false; | ||
985 | this.constrainY = false; | ||
986 | this.clearTicks(); | ||
987 | }, | ||
988 | |||
989 | /** | ||
990 | * Clears any tick interval defined for this instance | ||
991 | * @method clearTicks | ||
992 | */ | ||
993 | clearTicks: function() { | ||
994 | this.xTicks = null; | ||
995 | this.yTicks = null; | ||
996 | this.xTickSize = 0; | ||
997 | this.yTickSize = 0; | ||
998 | }, | ||
999 | |||
1000 | /** | ||
1001 | * By default, the element can be dragged any place on the screen. Set | ||
1002 | * this to limit the vertical travel of the element. Pass in 0,0 for the | ||
1003 | * parameters if you want to lock the drag to the x axis. | ||
1004 | * @method setYConstraint | ||
1005 | * @param {int} iUp the number of pixels the element can move up | ||
1006 | * @param {int} iDown the number of pixels the element can move down | ||
1007 | * @param {int} iTickSize optional parameter for specifying that the | ||
1008 | * element should move iTickSize pixels at a time. | ||
1009 | */ | ||
1010 | setYConstraint: function(iUp, iDown, iTickSize) { | ||
1011 | this.topConstraint = iUp; | ||
1012 | this.bottomConstraint = iDown; | ||
1013 | |||
1014 | this.minY = this.initPageY - iUp; | ||
1015 | this.maxY = this.initPageY + iDown; | ||
1016 | if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); } | ||
1017 | |||
1018 | this.constrainY = true; | ||
1019 | |||
1020 | }, | ||
1021 | |||
1022 | /** | ||
1023 | * resetConstraints must be called if you manually reposition a dd element. | ||
1024 | * @method resetConstraints | ||
1025 | * @param {boolean} maintainOffset | ||
1026 | */ | ||
1027 | resetConstraints: function() { | ||
1028 | |||
1029 | |||
1030 | // Maintain offsets if necessary | ||
1031 | if (this.initPageX || this.initPageX === 0) { | ||
1032 | // figure out how much this thing has moved | ||
1033 | var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0; | ||
1034 | var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0; | ||
1035 | |||
1036 | this.setInitPosition(dx, dy); | ||
1037 | |||
1038 | // This is the first time we have detected the element's position | ||
1039 | } else { | ||
1040 | this.setInitPosition(); | ||
1041 | } | ||
1042 | |||
1043 | if (this.constrainX) { | ||
1044 | this.setXConstraint( this.leftConstraint, | ||
1045 | this.rightConstraint, | ||
1046 | this.xTickSize ); | ||
1047 | } | ||
1048 | |||
1049 | if (this.constrainY) { | ||
1050 | this.setYConstraint( this.topConstraint, | ||
1051 | this.bottomConstraint, | ||
1052 | this.yTickSize ); | ||
1053 | } | ||
1054 | }, | ||
1055 | |||
1056 | /** | ||
1057 | * Normally the drag element is moved pixel by pixel, but we can specify | ||
1058 | * that it move a number of pixels at a time. This method resolves the | ||
1059 | * location when we have it set up like this. | ||
1060 | * @method getTick | ||
1061 | * @param {int} val where we want to place the object | ||
1062 | * @param {int[]} tickArray sorted array of valid points | ||
1063 | * @return {int} the closest tick | ||
1064 | * @private | ||
1065 | */ | ||
1066 | getTick: function(val, tickArray) { | ||
1067 | |||
1068 | if (!tickArray) { | ||
1069 | // If tick interval is not defined, it is effectively 1 pixel, | ||
1070 | // so we return the value passed to us. | ||
1071 | return val; | ||
1072 | } else if (tickArray[0] >= val) { | ||
1073 | // The value is lower than the first tick, so we return the first | ||
1074 | // tick. | ||
1075 | return tickArray[0]; | ||
1076 | } else { | ||
1077 | for (var i=0, len=tickArray.length; i<len; ++i) { | ||
1078 | var next = i + 1; | ||
1079 | if (tickArray[next] && tickArray[next] >= val) { | ||
1080 | var diff1 = val - tickArray[i]; | ||
1081 | var diff2 = tickArray[next] - val; | ||
1082 | return (diff2 > diff1) ? tickArray[i] : tickArray[next]; | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | // The value is larger than the last tick, so we return the last | ||
1087 | // tick. | ||
1088 | return tickArray[tickArray.length - 1]; | ||
1089 | } | ||
1090 | }, | ||
1091 | |||
1092 | /** | ||
1093 | * toString method | ||
1094 | * @method toString | ||
1095 | * @return {string} string representation of the dd obj | ||
1096 | */ | ||
1097 | toString: function() { | ||
1098 | return ("DragDrop " + this.id); | ||
1099 | } | ||
1100 | |||
1101 | }; | ||
1102 | |||
1103 | })(); | ||
1104 | /** | ||
1105 | * The drag and drop utility provides a framework for building drag and drop | ||
1106 | * applications. In addition to enabling drag and drop for specific elements, | ||
1107 | * the drag and drop elements are tracked by the manager class, and the | ||
1108 | * interactions between the various elements are tracked during the drag and | ||
1109 | * the implementing code is notified about these important moments. | ||
1110 | * @module dragdrop | ||
1111 | * @title Drag and Drop | ||
1112 | * @requires yahoo,dom,event | ||
1113 | * @namespace YAHOO.util | ||
1114 | */ | ||
1115 | |||
1116 | // Only load the library once. Rewriting the manager class would orphan | ||
1117 | // existing drag and drop instances. | ||
1118 | if (!YAHOO.util.DragDropMgr) { | ||
1119 | |||
1120 | /** | ||
1121 | * DragDropMgr is a singleton that tracks the element interaction for | ||
1122 | * all DragDrop items in the window. Generally, you will not call | ||
1123 | * this class directly, but it does have helper methods that could | ||
1124 | * be useful in your DragDrop implementations. | ||
1125 | * @class DragDropMgr | ||
1126 | * @static | ||
1127 | */ | ||
1128 | YAHOO.util.DragDropMgr = function() { | ||
1129 | |||
1130 | var Event = YAHOO.util.Event; | ||
1131 | |||
1132 | return { | ||
1133 | |||
1134 | /** | ||
1135 | * Two dimensional Array of registered DragDrop objects. The first | ||
1136 | * dimension is the DragDrop item group, the second the DragDrop | ||
1137 | * object. | ||
1138 | * @property ids | ||
1139 | * @type {string: string} | ||
1140 | * @private | ||
1141 | * @static | ||
1142 | */ | ||
1143 | ids: {}, | ||
1144 | |||
1145 | /** | ||
1146 | * Array of element ids defined as drag handles. Used to determine | ||
1147 | * if the element that generated the mousedown event is actually the | ||
1148 | * handle and not the html element itself. | ||
1149 | * @property handleIds | ||
1150 | * @type {string: string} | ||
1151 | * @private | ||
1152 | * @static | ||
1153 | */ | ||
1154 | handleIds: {}, | ||
1155 | |||
1156 | /** | ||
1157 | * the DragDrop object that is currently being dragged | ||
1158 | * @property dragCurrent | ||
1159 | * @type DragDrop | ||
1160 | * @private | ||
1161 | * @static | ||
1162 | **/ | ||
1163 | dragCurrent: null, | ||
1164 | |||
1165 | /** | ||
1166 | * the DragDrop object(s) that are being hovered over | ||
1167 | * @property dragOvers | ||
1168 | * @type Array | ||
1169 | * @private | ||
1170 | * @static | ||
1171 | */ | ||
1172 | dragOvers: {}, | ||
1173 | |||
1174 | /** | ||
1175 | * the X distance between the cursor and the object being dragged | ||
1176 | * @property deltaX | ||
1177 | * @type int | ||
1178 | * @private | ||
1179 | * @static | ||
1180 | */ | ||
1181 | deltaX: 0, | ||
1182 | |||
1183 | /** | ||
1184 | * the Y distance between the cursor and the object being dragged | ||
1185 | * @property deltaY | ||
1186 | * @type int | ||
1187 | * @private | ||
1188 | * @static | ||
1189 | */ | ||
1190 | deltaY: 0, | ||
1191 | |||
1192 | /** | ||
1193 | * Flag to determine if we should prevent the default behavior of the | ||
1194 | * events we define. By default this is true, but this can be set to | ||
1195 | * false if you need the default behavior (not recommended) | ||
1196 | * @property preventDefault | ||
1197 | * @type boolean | ||
1198 | * @static | ||
1199 | */ | ||
1200 | preventDefault: true, | ||
1201 | |||
1202 | /** | ||
1203 | * Flag to determine if we should stop the propagation of the events | ||
1204 | * we generate. This is true by default but you may want to set it to | ||
1205 | * false if the html element contains other features that require the | ||
1206 | * mouse click. | ||
1207 | * @property stopPropagation | ||
1208 | * @type boolean | ||
1209 | * @static | ||
1210 | */ | ||
1211 | stopPropagation: true, | ||
1212 | |||
1213 | /** | ||
1214 | * Internal flag that is set to true when drag and drop has been | ||
1215 | * intialized | ||
1216 | * @property initialized | ||
1217 | * @private | ||
1218 | * @static | ||
1219 | */ | ||
1220 | initalized: false, | ||
1221 | |||
1222 | /** | ||
1223 | * All drag and drop can be disabled. | ||
1224 | * @property locked | ||
1225 | * @private | ||
1226 | * @static | ||
1227 | */ | ||
1228 | locked: false, | ||
1229 | |||
1230 | /** | ||
1231 | * Called the first time an element is registered. | ||
1232 | * @method init | ||
1233 | * @private | ||
1234 | * @static | ||
1235 | */ | ||
1236 | init: function() { | ||
1237 | this.initialized = true; | ||
1238 | }, | ||
1239 | |||
1240 | /** | ||
1241 | * In point mode, drag and drop interaction is defined by the | ||
1242 | * location of the cursor during the drag/drop | ||
1243 | * @property POINT | ||
1244 | * @type int | ||
1245 | * @static | ||
1246 | */ | ||
1247 | POINT: 0, | ||
1248 | |||
1249 | /** | ||
1250 | * In intersect mode, drag and drop interactio nis defined by the | ||
1251 | * overlap of two or more drag and drop objects. | ||
1252 | * @property INTERSECT | ||
1253 | * @type int | ||
1254 | * @static | ||
1255 | */ | ||
1256 | INTERSECT: 1, | ||
1257 | |||
1258 | /** | ||
1259 | * The current drag and drop mode. Default: POINT | ||
1260 | * @property mode | ||
1261 | * @type int | ||
1262 | * @static | ||
1263 | */ | ||
1264 | mode: 0, | ||
1265 | |||
1266 | /** | ||
1267 | * Runs method on all drag and drop objects | ||
1268 | * @method _execOnAll | ||
1269 | * @private | ||
1270 | * @static | ||
1271 | */ | ||
1272 | _execOnAll: function(sMethod, args) { | ||
1273 | for (var i in this.ids) { | ||
1274 | for (var j in this.ids[i]) { | ||
1275 | var oDD = this.ids[i][j]; | ||
1276 | if (! this.isTypeOfDD(oDD)) { | ||
1277 | continue; | ||
1278 | } | ||
1279 | oDD[sMethod].apply(oDD, args); | ||
1280 | } | ||
1281 | } | ||
1282 | }, | ||
1283 | |||
1284 | /** | ||
1285 | * Drag and drop initialization. Sets up the global event handlers | ||
1286 | * @method _onLoad | ||
1287 | * @private | ||
1288 | * @static | ||
1289 | */ | ||
1290 | _onLoad: function() { | ||
1291 | |||
1292 | this.init(); | ||
1293 | |||
1294 | |||
1295 | Event.on(document, "mouseup", this.handleMouseUp, this, true); | ||
1296 | Event.on(document, "mousemove", this.handleMouseMove, this, true); | ||
1297 | Event.on(window, "unload", this._onUnload, this, true); | ||
1298 | Event.on(window, "resize", this._onResize, this, true); | ||
1299 | // Event.on(window, "mouseout", this._test); | ||
1300 | |||
1301 | }, | ||
1302 | |||
1303 | /** | ||
1304 | * Reset constraints on all drag and drop objs | ||
1305 | * @method _onResize | ||
1306 | * @private | ||
1307 | * @static | ||
1308 | */ | ||
1309 | _onResize: function(e) { | ||
1310 | this._execOnAll("resetConstraints", []); | ||
1311 | }, | ||
1312 | |||
1313 | /** | ||
1314 | * Lock all drag and drop functionality | ||
1315 | * @method lock | ||
1316 | * @static | ||
1317 | */ | ||
1318 | lock: function() { this.locked = true; }, | ||
1319 | |||
1320 | /** | ||
1321 | * Unlock all drag and drop functionality | ||
1322 | * @method unlock | ||
1323 | * @static | ||
1324 | */ | ||
1325 | unlock: function() { this.locked = false; }, | ||
1326 | |||
1327 | /** | ||
1328 | * Is drag and drop locked? | ||
1329 | * @method isLocked | ||
1330 | * @return {boolean} True if drag and drop is locked, false otherwise. | ||
1331 | * @static | ||
1332 | */ | ||
1333 | isLocked: function() { return this.locked; }, | ||
1334 | |||
1335 | /** | ||
1336 | * Location cache that is set for all drag drop objects when a drag is | ||
1337 | * initiated, cleared when the drag is finished. | ||
1338 | * @property locationCache | ||
1339 | * @private | ||
1340 | * @static | ||
1341 | */ | ||
1342 | locationCache: {}, | ||
1343 | |||
1344 | /** | ||
1345 | * Set useCache to false if you want to force object the lookup of each | ||
1346 | * drag and drop linked element constantly during a drag. | ||
1347 | * @property useCache | ||
1348 | * @type boolean | ||
1349 | * @static | ||
1350 | */ | ||
1351 | useCache: true, | ||
1352 | |||
1353 | /** | ||
1354 | * The number of pixels that the mouse needs to move after the | ||
1355 | * mousedown before the drag is initiated. Default=3; | ||
1356 | * @property clickPixelThresh | ||
1357 | * @type int | ||
1358 | * @static | ||
1359 | */ | ||
1360 | clickPixelThresh: 3, | ||
1361 | |||
1362 | /** | ||
1363 | * The number of milliseconds after the mousedown event to initiate the | ||
1364 | * drag if we don't get a mouseup event. Default=1000 | ||
1365 | * @property clickTimeThresh | ||
1366 | * @type int | ||
1367 | * @static | ||
1368 | */ | ||
1369 | clickTimeThresh: 1000, | ||
1370 | |||
1371 | /** | ||
1372 | * Flag that indicates that either the drag pixel threshold or the | ||
1373 | * mousdown time threshold has been met | ||
1374 | * @property dragThreshMet | ||
1375 | * @type boolean | ||
1376 | * @private | ||
1377 | * @static | ||
1378 | */ | ||
1379 | dragThreshMet: false, | ||
1380 | |||
1381 | /** | ||
1382 | * Timeout used for the click time threshold | ||
1383 | * @property clickTimeout | ||
1384 | * @type Object | ||
1385 | * @private | ||
1386 | * @static | ||
1387 | */ | ||
1388 | clickTimeout: null, | ||
1389 | |||
1390 | /** | ||
1391 | * The X position of the mousedown event stored for later use when a | ||
1392 | * drag threshold is met. | ||
1393 | * @property startX | ||
1394 | * @type int | ||
1395 | * @private | ||
1396 | * @static | ||
1397 | */ | ||
1398 | startX: 0, | ||
1399 | |||
1400 | /** | ||
1401 | * The Y position of the mousedown event stored for later use when a | ||
1402 | * drag threshold is met. | ||
1403 | * @property startY | ||
1404 | * @type int | ||
1405 | * @private | ||
1406 | * @static | ||
1407 | */ | ||
1408 | startY: 0, | ||
1409 | |||
1410 | /** | ||
1411 | * Each DragDrop instance must be registered with the DragDropMgr. | ||
1412 | * This is executed in DragDrop.init() | ||
1413 | * @method regDragDrop | ||
1414 | * @param {DragDrop} oDD the DragDrop object to register | ||
1415 | * @param {String} sGroup the name of the group this element belongs to | ||
1416 | * @static | ||
1417 | */ | ||
1418 | regDragDrop: function(oDD, sGroup) { | ||
1419 | if (!this.initialized) { this.init(); } | ||
1420 | |||
1421 | if (!this.ids[sGroup]) { | ||
1422 | this.ids[sGroup] = {}; | ||
1423 | } | ||
1424 | this.ids[sGroup][oDD.id] = oDD; | ||
1425 | }, | ||
1426 | |||
1427 | /** | ||
1428 | * Removes the supplied dd instance from the supplied group. Executed | ||
1429 | * by DragDrop.removeFromGroup, so don't call this function directly. | ||
1430 | * @method removeDDFromGroup | ||
1431 | * @private | ||
1432 | * @static | ||
1433 | */ | ||
1434 | removeDDFromGroup: function(oDD, sGroup) { | ||
1435 | if (!this.ids[sGroup]) { | ||
1436 | this.ids[sGroup] = {}; | ||
1437 | } | ||
1438 | |||
1439 | var obj = this.ids[sGroup]; | ||
1440 | if (obj && obj[oDD.id]) { | ||
1441 | delete obj[oDD.id]; | ||
1442 | } | ||
1443 | }, | ||
1444 | |||
1445 | /** | ||
1446 | * Unregisters a drag and drop item. This is executed in | ||
1447 | * DragDrop.unreg, use that method instead of calling this directly. | ||
1448 | * @method _remove | ||
1449 | * @private | ||
1450 | * @static | ||
1451 | */ | ||
1452 | _remove: function(oDD) { | ||
1453 | for (var g in oDD.groups) { | ||
1454 | if (g && this.ids[g][oDD.id]) { | ||
1455 | delete this.ids[g][oDD.id]; | ||
1456 | } | ||
1457 | } | ||
1458 | delete this.handleIds[oDD.id]; | ||
1459 | }, | ||
1460 | |||
1461 | /** | ||
1462 | * Each DragDrop handle element must be registered. This is done | ||
1463 | * automatically when executing DragDrop.setHandleElId() | ||
1464 | * @method regHandle | ||
1465 | * @param {String} sDDId the DragDrop id this element is a handle for | ||
1466 | * @param {String} sHandleId the id of the element that is the drag | ||
1467 | * handle | ||
1468 | * @static | ||
1469 | */ | ||
1470 | regHandle: function(sDDId, sHandleId) { | ||
1471 | if (!this.handleIds[sDDId]) { | ||
1472 | this.handleIds[sDDId] = {}; | ||
1473 | } | ||
1474 | this.handleIds[sDDId][sHandleId] = sHandleId; | ||
1475 | }, | ||
1476 | |||
1477 | /** | ||
1478 | * Utility function to determine if a given element has been | ||
1479 | * registered as a drag drop item. | ||
1480 | * @method isDragDrop | ||
1481 | * @param {String} id the element id to check | ||
1482 | * @return {boolean} true if this element is a DragDrop item, | ||
1483 | * false otherwise | ||
1484 | * @static | ||
1485 | */ | ||
1486 | isDragDrop: function(id) { | ||
1487 | return ( this.getDDById(id) ) ? true : false; | ||
1488 | }, | ||
1489 | |||
1490 | /** | ||
1491 | * Returns the drag and drop instances that are in all groups the | ||
1492 | * passed in instance belongs to. | ||
1493 | * @method getRelated | ||
1494 | * @param {DragDrop} p_oDD the obj to get related data for | ||
1495 | * @param {boolean} bTargetsOnly if true, only return targetable objs | ||
1496 | * @return {DragDrop[]} the related instances | ||
1497 | * @static | ||
1498 | */ | ||
1499 | getRelated: function(p_oDD, bTargetsOnly) { | ||
1500 | var oDDs = []; | ||
1501 | for (var i in p_oDD.groups) { | ||
1502 | for (j in this.ids[i]) { | ||
1503 | var dd = this.ids[i][j]; | ||
1504 | if (! this.isTypeOfDD(dd)) { | ||
1505 | continue; | ||
1506 | } | ||
1507 | if (!bTargetsOnly || dd.isTarget) { | ||
1508 | oDDs[oDDs.length] = dd; | ||
1509 | } | ||
1510 | } | ||
1511 | } | ||
1512 | |||
1513 | return oDDs; | ||
1514 | }, | ||
1515 | |||
1516 | /** | ||
1517 | * Returns true if the specified dd target is a legal target for | ||
1518 | * the specifice drag obj | ||
1519 | * @method isLegalTarget | ||
1520 | * @param {DragDrop} the drag obj | ||
1521 | * @param {DragDrop} the target | ||
1522 | * @return {boolean} true if the target is a legal target for the | ||
1523 | * dd obj | ||
1524 | * @static | ||
1525 | */ | ||
1526 | isLegalTarget: function (oDD, oTargetDD) { | ||
1527 | var targets = this.getRelated(oDD, true); | ||
1528 | for (var i=0, len=targets.length;i<len;++i) { | ||
1529 | if (targets[i].id == oTargetDD.id) { | ||
1530 | return true; | ||
1531 | } | ||
1532 | } | ||
1533 | |||
1534 | return false; | ||
1535 | }, | ||
1536 | |||
1537 | /** | ||
1538 | * My goal is to be able to transparently determine if an object is | ||
1539 | * typeof DragDrop, and the exact subclass of DragDrop. typeof | ||
1540 | * returns "object", oDD.constructor.toString() always returns | ||
1541 | * "DragDrop" and not the name of the subclass. So for now it just | ||
1542 | * evaluates a well-known variable in DragDrop. | ||
1543 | * @method isTypeOfDD | ||
1544 | * @param {Object} the object to evaluate | ||
1545 | * @return {boolean} true if typeof oDD = DragDrop | ||
1546 | * @static | ||
1547 | */ | ||
1548 | isTypeOfDD: function (oDD) { | ||
1549 | return (oDD && oDD.__ygDragDrop); | ||
1550 | }, | ||
1551 | |||
1552 | /** | ||
1553 | * Utility function to determine if a given element has been | ||
1554 | * registered as a drag drop handle for the given Drag Drop object. | ||
1555 | * @method isHandle | ||
1556 | * @param {String} id the element id to check | ||
1557 | * @return {boolean} true if this element is a DragDrop handle, false | ||
1558 | * otherwise | ||
1559 | * @static | ||
1560 | */ | ||
1561 | isHandle: function(sDDId, sHandleId) { | ||
1562 | return ( this.handleIds[sDDId] && | ||
1563 | this.handleIds[sDDId][sHandleId] ); | ||
1564 | }, | ||
1565 | |||
1566 | /** | ||
1567 | * Returns the DragDrop instance for a given id | ||
1568 | * @method getDDById | ||
1569 | * @param {String} id the id of the DragDrop object | ||
1570 | * @return {DragDrop} the drag drop object, null if it is not found | ||
1571 | * @static | ||
1572 | */ | ||
1573 | getDDById: function(id) { | ||
1574 | for (var i in this.ids) { | ||
1575 | if (this.ids[i][id]) { | ||
1576 | return this.ids[i][id]; | ||
1577 | } | ||
1578 | } | ||
1579 | return null; | ||
1580 | }, | ||
1581 | |||
1582 | /** | ||
1583 | * Fired after a registered DragDrop object gets the mousedown event. | ||
1584 | * Sets up the events required to track the object being dragged | ||
1585 | * @method handleMouseDown | ||
1586 | * @param {Event} e the event | ||
1587 | * @param oDD the DragDrop object being dragged | ||
1588 | * @private | ||
1589 | * @static | ||
1590 | */ | ||
1591 | handleMouseDown: function(e, oDD) { | ||
1592 | |||
1593 | this.currentTarget = YAHOO.util.Event.getTarget(e); | ||
1594 | |||
1595 | this.dragCurrent = oDD; | ||
1596 | |||
1597 | var el = oDD.getEl(); | ||
1598 | |||
1599 | // track start position | ||
1600 | this.startX = YAHOO.util.Event.getPageX(e); | ||
1601 | this.startY = YAHOO.util.Event.getPageY(e); | ||
1602 | |||
1603 | this.deltaX = this.startX - el.offsetLeft; | ||
1604 | this.deltaY = this.startY - el.offsetTop; | ||
1605 | |||
1606 | this.dragThreshMet = false; | ||
1607 | |||
1608 | this.clickTimeout = setTimeout( | ||
1609 | function() { | ||
1610 | var DDM = YAHOO.util.DDM; | ||
1611 | DDM.startDrag(DDM.startX, DDM.startY); | ||
1612 | }, | ||
1613 | this.clickTimeThresh ); | ||
1614 | }, | ||
1615 | |||
1616 | /** | ||
1617 | * Fired when either the drag pixel threshol or the mousedown hold | ||
1618 | * time threshold has been met. | ||
1619 | * @method startDrag | ||
1620 | * @param x {int} the X position of the original mousedown | ||
1621 | * @param y {int} the Y position of the original mousedown | ||
1622 | * @static | ||
1623 | */ | ||
1624 | startDrag: function(x, y) { | ||
1625 | clearTimeout(this.clickTimeout); | ||
1626 | if (this.dragCurrent) { | ||
1627 | this.dragCurrent.b4StartDrag(x, y); | ||
1628 | this.dragCurrent.startDrag(x, y); | ||
1629 | } | ||
1630 | this.dragThreshMet = true; | ||
1631 | }, | ||
1632 | |||
1633 | /** | ||
1634 | * Internal function to handle the mouseup event. Will be invoked | ||
1635 | * from the context of the document. | ||
1636 | * @method handleMouseUp | ||
1637 | * @param {Event} e the event | ||
1638 | * @private | ||
1639 | * @static | ||
1640 | */ | ||
1641 | handleMouseUp: function(e) { | ||
1642 | |||
1643 | if (! this.dragCurrent) { | ||
1644 | return; | ||
1645 | } | ||
1646 | |||
1647 | clearTimeout(this.clickTimeout); | ||
1648 | |||
1649 | if (this.dragThreshMet) { | ||
1650 | this.fireEvents(e, true); | ||
1651 | } else { | ||
1652 | } | ||
1653 | |||
1654 | this.stopDrag(e); | ||
1655 | |||
1656 | this.stopEvent(e); | ||
1657 | }, | ||
1658 | |||
1659 | /** | ||
1660 | * Utility to stop event propagation and event default, if these | ||
1661 | * features are turned on. | ||
1662 | * @method stopEvent | ||
1663 | * @param {Event} e the event as returned by this.getEvent() | ||
1664 | * @static | ||
1665 | */ | ||
1666 | stopEvent: function(e) { | ||
1667 | if (this.stopPropagation) { | ||
1668 | YAHOO.util.Event.stopPropagation(e); | ||
1669 | } | ||
1670 | |||
1671 | if (this.preventDefault) { | ||
1672 | YAHOO.util.Event.preventDefault(e); | ||
1673 | } | ||
1674 | }, | ||
1675 | |||
1676 | /** | ||
1677 | * Internal function to clean up event handlers after the drag | ||
1678 | * operation is complete | ||
1679 | * @method stopDrag | ||
1680 | * @param {Event} e the event | ||
1681 | * @private | ||
1682 | * @static | ||
1683 | */ | ||
1684 | stopDrag: function(e) { | ||
1685 | |||
1686 | // Fire the drag end event for the item that was dragged | ||
1687 | if (this.dragCurrent) { | ||
1688 | if (this.dragThreshMet) { | ||
1689 | this.dragCurrent.b4EndDrag(e); | ||
1690 | this.dragCurrent.endDrag(e); | ||
1691 | } | ||
1692 | |||
1693 | this.dragCurrent.onMouseUp(e); | ||
1694 | } | ||
1695 | |||
1696 | this.dragCurrent = null; | ||
1697 | this.dragOvers = {}; | ||
1698 | }, | ||
1699 | |||
1700 | /** | ||
1701 | * Internal function to handle the mousemove event. Will be invoked | ||
1702 | * from the context of the html element. | ||
1703 | * | ||
1704 | * @TODO figure out what we can do about mouse events lost when the | ||
1705 | * user drags objects beyond the window boundary. Currently we can | ||
1706 | * detect this in internet explorer by verifying that the mouse is | ||
1707 | * down during the mousemove event. Firefox doesn't give us the | ||
1708 | * button state on the mousemove event. | ||
1709 | * @method handleMouseMove | ||
1710 | * @param {Event} e the event | ||
1711 | * @private | ||
1712 | * @static | ||
1713 | */ | ||
1714 | handleMouseMove: function(e) { | ||
1715 | if (! this.dragCurrent) { | ||
1716 | return true; | ||
1717 | } | ||
1718 | |||
1719 | // var button = e.which || e.button; | ||
1720 | |||
1721 | // check for IE mouseup outside of page boundary | ||
1722 | if (YAHOO.util.Event.isIE && !e.button) { | ||
1723 | this.stopEvent(e); | ||
1724 | return this.handleMouseUp(e); | ||
1725 | } | ||
1726 | |||
1727 | if (!this.dragThreshMet) { | ||
1728 | var diffX = Math.abs(this.startX - YAHOO.util.Event.getPageX(e)); | ||
1729 | var diffY = Math.abs(this.startY - YAHOO.util.Event.getPageY(e)); | ||
1730 | if (diffX > this.clickPixelThresh || | ||
1731 | diffY > this.clickPixelThresh) { | ||
1732 | this.startDrag(this.startX, this.startY); | ||
1733 | } | ||
1734 | } | ||
1735 | |||
1736 | if (this.dragThreshMet) { | ||
1737 | this.dragCurrent.b4Drag(e); | ||
1738 | this.dragCurrent.onDrag(e); | ||
1739 | this.fireEvents(e, false); | ||
1740 | } | ||
1741 | |||
1742 | this.stopEvent(e); | ||
1743 | |||
1744 | return true; | ||
1745 | }, | ||
1746 | |||
1747 | /** | ||
1748 | * Iterates over all of the DragDrop elements to find ones we are | ||
1749 | * hovering over or dropping on | ||
1750 | * @method fireEvents | ||
1751 | * @param {Event} e the event | ||
1752 | * @param {boolean} isDrop is this a drop op or a mouseover op? | ||
1753 | * @private | ||
1754 | * @static | ||
1755 | */ | ||
1756 | fireEvents: function(e, isDrop) { | ||
1757 | var dc = this.dragCurrent; | ||
1758 | |||
1759 | // If the user did the mouse up outside of the window, we could | ||
1760 | // get here even though we have ended the drag. | ||
1761 | if (!dc || dc.isLocked()) { | ||
1762 | return; | ||
1763 | } | ||
1764 | |||
1765 | var x = YAHOO.util.Event.getPageX(e); | ||
1766 | var y = YAHOO.util.Event.getPageY(e); | ||
1767 | var pt = new YAHOO.util.Point(x,y); | ||
1768 | |||
1769 | // cache the previous dragOver array | ||
1770 | var oldOvers = []; | ||
1771 | |||
1772 | var outEvts = []; | ||
1773 | var overEvts = []; | ||
1774 | var dropEvts = []; | ||
1775 | var enterEvts = []; | ||
1776 | |||
1777 | // Check to see if the object(s) we were hovering over is no longer | ||
1778 | // being hovered over so we can fire the onDragOut event | ||
1779 | for (var i in this.dragOvers) { | ||
1780 | |||
1781 | var ddo = this.dragOvers[i]; | ||
1782 | |||
1783 | if (! this.isTypeOfDD(ddo)) { | ||
1784 | continue; | ||
1785 | } | ||
1786 | |||
1787 | if (! this.isOverTarget(pt, ddo, this.mode)) { | ||
1788 | outEvts.push( ddo ); | ||
1789 | } | ||
1790 | |||
1791 | oldOvers[i] = true; | ||
1792 | delete this.dragOvers[i]; | ||
1793 | } | ||
1794 | |||
1795 | for (var sGroup in dc.groups) { | ||
1796 | |||
1797 | if ("string" != typeof sGroup) { | ||
1798 | continue; | ||
1799 | } | ||
1800 | |||
1801 | for (i in this.ids[sGroup]) { | ||
1802 | var oDD = this.ids[sGroup][i]; | ||
1803 | if (! this.isTypeOfDD(oDD)) { | ||
1804 | continue; | ||
1805 | } | ||
1806 | |||
1807 | if (oDD.isTarget && !oDD.isLocked() && oDD != dc) { | ||
1808 | if (this.isOverTarget(pt, oDD, this.mode)) { | ||
1809 | // look for drop interactions | ||
1810 | if (isDrop) { | ||
1811 | dropEvts.push( oDD ); | ||
1812 | // look for drag enter and drag over interactions | ||
1813 | } else { | ||
1814 | |||
1815 | // initial drag over: dragEnter fires | ||
1816 | if (!oldOvers[oDD.id]) { | ||
1817 | enterEvts.push( oDD ); | ||
1818 | // subsequent drag overs: dragOver fires | ||
1819 | } else { | ||
1820 | overEvts.push( oDD ); | ||
1821 | } | ||
1822 | |||
1823 | this.dragOvers[oDD.id] = oDD; | ||
1824 | } | ||
1825 | } | ||
1826 | } | ||
1827 | } | ||
1828 | } | ||
1829 | |||
1830 | if (this.mode) { | ||
1831 | if (outEvts.length) { | ||
1832 | dc.b4DragOut(e, outEvts); | ||
1833 | dc.onDragOut(e, outEvts); | ||
1834 | } | ||
1835 | |||
1836 | if (enterEvts.length) { | ||
1837 | dc.onDragEnter(e, enterEvts); | ||
1838 | } | ||
1839 | |||
1840 | if (overEvts.length) { | ||
1841 | dc.b4DragOver(e, overEvts); | ||
1842 | dc.onDragOver(e, overEvts); | ||
1843 | } | ||
1844 | |||
1845 | if (dropEvts.length) { | ||
1846 | dc.b4DragDrop(e, dropEvts); | ||
1847 | dc.onDragDrop(e, dropEvts); | ||
1848 | } | ||
1849 | |||
1850 | } else { | ||
1851 | // fire dragout events | ||
1852 | var len = 0; | ||
1853 | for (i=0, len=outEvts.length; i<len; ++i) { | ||
1854 | dc.b4DragOut(e, outEvts[i].id); | ||
1855 | dc.onDragOut(e, outEvts[i].id); | ||
1856 | } | ||
1857 | |||
1858 | // fire enter events | ||
1859 | for (i=0,len=enterEvts.length; i<len; ++i) { | ||
1860 | // dc.b4DragEnter(e, oDD.id); | ||
1861 | dc.onDragEnter(e, enterEvts[i].id); | ||
1862 | } | ||
1863 | |||
1864 | // fire over events | ||
1865 | for (i=0,len=overEvts.length; i<len; ++i) { | ||
1866 | dc.b4DragOver(e, overEvts[i].id); | ||
1867 | dc.onDragOver(e, overEvts[i].id); | ||
1868 | } | ||
1869 | |||
1870 | // fire drop events | ||
1871 | for (i=0, len=dropEvts.length; i<len; ++i) { | ||
1872 | dc.b4DragDrop(e, dropEvts[i].id); | ||
1873 | dc.onDragDrop(e, dropEvts[i].id); | ||
1874 | } | ||
1875 | |||
1876 | } | ||
1877 | |||
1878 | // notify about a drop that did not find a target | ||
1879 | if (isDrop && !dropEvts.length) { | ||
1880 | dc.onInvalidDrop(e); | ||
1881 | } | ||
1882 | |||
1883 | }, | ||
1884 | |||
1885 | /** | ||
1886 | * Helper function for getting the best match from the list of drag | ||
1887 | * and drop objects returned by the drag and drop events when we are | ||
1888 | * in INTERSECT mode. It returns either the first object that the | ||
1889 | * cursor is over, or the object that has the greatest overlap with | ||
1890 | * the dragged element. | ||
1891 | * @method getBestMatch | ||
1892 | * @param {DragDrop[]} dds The array of drag and drop objects | ||
1893 | * targeted | ||
1894 | * @return {DragDrop} The best single match | ||
1895 | * @static | ||
1896 | */ | ||
1897 | getBestMatch: function(dds) { | ||
1898 | var winner = null; | ||
1899 | // Return null if the input is not what we expect | ||
1900 | //if (!dds || !dds.length || dds.length == 0) { | ||
1901 | // winner = null; | ||
1902 | // If there is only one item, it wins | ||
1903 | //} else if (dds.length == 1) { | ||
1904 | |||
1905 | var len = dds.length; | ||
1906 | |||
1907 | if (len == 1) { | ||
1908 | winner = dds[0]; | ||
1909 | } else { | ||
1910 | // Loop through the targeted items | ||
1911 | for (var i=0; i<len; ++i) { | ||
1912 | var dd = dds[i]; | ||
1913 | // If the cursor is over the object, it wins. If the | ||
1914 | // cursor is over multiple matches, the first one we come | ||
1915 | // to wins. | ||
1916 | if (dd.cursorIsOver) { | ||
1917 | winner = dd; | ||
1918 | break; | ||
1919 | // Otherwise the object with the most overlap wins | ||
1920 | } else { | ||
1921 | if (!winner || | ||
1922 | winner.overlap.getArea() < dd.overlap.getArea()) { | ||
1923 | winner = dd; | ||
1924 | } | ||
1925 | } | ||
1926 | } | ||
1927 | } | ||
1928 | |||
1929 | return winner; | ||
1930 | }, | ||
1931 | |||
1932 | /** | ||
1933 | * Refreshes the cache of the top-left and bottom-right points of the | ||
1934 | * drag and drop objects in the specified group(s). This is in the | ||
1935 | * format that is stored in the drag and drop instance, so typical | ||
1936 | * usage is: | ||
1937 | * <code> | ||
1938 | * YAHOO.util.DragDropMgr.refreshCache(ddinstance.groups); | ||
1939 | * </code> | ||
1940 | * Alternatively: | ||
1941 | * <code> | ||
1942 | * YAHOO.util.DragDropMgr.refreshCache({group1:true, group2:true}); | ||
1943 | * </code> | ||
1944 | * @TODO this really should be an indexed array. Alternatively this | ||
1945 | * method could accept both. | ||
1946 | * @method refreshCache | ||
1947 | * @param {Object} groups an associative array of groups to refresh | ||
1948 | * @static | ||
1949 | */ | ||
1950 | refreshCache: function(groups) { | ||
1951 | for (var sGroup in groups) { | ||
1952 | if ("string" != typeof sGroup) { | ||
1953 | continue; | ||
1954 | } | ||
1955 | for (var i in this.ids[sGroup]) { | ||
1956 | var oDD = this.ids[sGroup][i]; | ||
1957 | |||
1958 | if (this.isTypeOfDD(oDD)) { | ||
1959 | // if (this.isTypeOfDD(oDD) && oDD.isTarget) { | ||
1960 | var loc = this.getLocation(oDD); | ||
1961 | if (loc) { | ||
1962 | this.locationCache[oDD.id] = loc; | ||
1963 | } else { | ||
1964 | delete this.locationCache[oDD.id]; | ||
1965 | // this will unregister the drag and drop object if | ||
1966 | // the element is not in a usable state | ||
1967 | // oDD.unreg(); | ||
1968 | } | ||
1969 | } | ||
1970 | } | ||
1971 | } | ||
1972 | }, | ||
1973 | |||
1974 | /** | ||
1975 | * This checks to make sure an element exists and is in the DOM. The | ||
1976 | * main purpose is to handle cases where innerHTML is used to remove | ||
1977 | * drag and drop objects from the DOM. IE provides an 'unspecified | ||
1978 | * error' when trying to access the offsetParent of such an element | ||
1979 | * @method verifyEl | ||
1980 | * @param {HTMLElement} el the element to check | ||
1981 | * @return {boolean} true if the element looks usable | ||
1982 | * @static | ||
1983 | */ | ||
1984 | verifyEl: function(el) { | ||
1985 | try { | ||
1986 | if (el) { | ||
1987 | var parent = el.offsetParent; | ||
1988 | if (parent) { | ||
1989 | return true; | ||
1990 | } | ||
1991 | } | ||
1992 | } catch(e) { | ||
1993 | } | ||
1994 | |||
1995 | return false; | ||
1996 | }, | ||
1997 | |||
1998 | /** | ||
1999 | * Returns a Region object containing the drag and drop element's position | ||
2000 | * and size, including the padding configured for it | ||
2001 | * @method getLocation | ||
2002 | * @param {DragDrop} oDD the drag and drop object to get the | ||
2003 | * location for | ||
2004 | * @return {YAHOO.util.Region} a Region object representing the total area | ||
2005 | * the element occupies, including any padding | ||
2006 | * the instance is configured for. | ||
2007 | * @static | ||
2008 | */ | ||
2009 | getLocation: function(oDD) { | ||
2010 | if (! this.isTypeOfDD(oDD)) { | ||
2011 | return null; | ||
2012 | } | ||
2013 | |||
2014 | var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l; | ||
2015 | |||
2016 | try { | ||
2017 | pos= YAHOO.util.Dom.getXY(el); | ||
2018 | } catch (e) { } | ||
2019 | |||
2020 | if (!pos) { | ||
2021 | return null; | ||
2022 | } | ||
2023 | |||
2024 | x1 = pos[0]; | ||
2025 | x2 = x1 + el.offsetWidth; | ||
2026 | y1 = pos[1]; | ||
2027 | y2 = y1 + el.offsetHeight; | ||
2028 | |||
2029 | t = y1 - oDD.padding[0]; | ||
2030 | r = x2 + oDD.padding[1]; | ||
2031 | b = y2 + oDD.padding[2]; | ||
2032 | l = x1 - oDD.padding[3]; | ||
2033 | |||
2034 | return new YAHOO.util.Region( t, r, b, l ); | ||
2035 | }, | ||
2036 | |||
2037 | /** | ||
2038 | * Checks the cursor location to see if it over the target | ||
2039 | * @method isOverTarget | ||
2040 | * @param {YAHOO.util.Point} pt The point to evaluate | ||
2041 | * @param {DragDrop} oTarget the DragDrop object we are inspecting | ||
2042 | * @return {boolean} true if the mouse is over the target | ||
2043 | * @private | ||
2044 | * @static | ||
2045 | */ | ||
2046 | isOverTarget: function(pt, oTarget, intersect) { | ||
2047 | // use cache if available | ||
2048 | var loc = this.locationCache[oTarget.id]; | ||
2049 | if (!loc || !this.useCache) { | ||
2050 | loc = this.getLocation(oTarget); | ||
2051 | this.locationCache[oTarget.id] = loc; | ||
2052 | |||
2053 | } | ||
2054 | |||
2055 | if (!loc) { | ||
2056 | return false; | ||
2057 | } | ||
2058 | |||
2059 | oTarget.cursorIsOver = loc.contains( pt ); | ||
2060 | |||
2061 | // DragDrop is using this as a sanity check for the initial mousedown | ||
2062 | // in this case we are done. In POINT mode, if the drag obj has no | ||
2063 | // contraints, we are also done. Otherwise we need to evaluate the | ||
2064 | // location of the target as related to the actual location of the | ||
2065 | // dragged element. | ||
2066 | var dc = this.dragCurrent; | ||
2067 | if (!dc || !dc.getTargetCoord || | ||
2068 | (!intersect && !dc.constrainX && !dc.constrainY)) { | ||
2069 | return oTarget.cursorIsOver; | ||
2070 | } | ||
2071 | |||
2072 | oTarget.overlap = null; | ||
2073 | |||
2074 | // Get the current location of the drag element, this is the | ||
2075 | // location of the mouse event less the delta that represents | ||
2076 | // where the original mousedown happened on the element. We | ||
2077 | // need to consider constraints and ticks as well. | ||
2078 | var pos = dc.getTargetCoord(pt.x, pt.y); | ||
2079 | |||
2080 | var el = dc.getDragEl(); | ||
2081 | var curRegion = new YAHOO.util.Region( pos.y, | ||
2082 | pos.x + el.offsetWidth, | ||
2083 | pos.y + el.offsetHeight, | ||
2084 | pos.x ); | ||
2085 | |||
2086 | var overlap = curRegion.intersect(loc); | ||
2087 | |||
2088 | if (overlap) { | ||
2089 | oTarget.overlap = overlap; | ||
2090 | return (intersect) ? true : oTarget.cursorIsOver; | ||
2091 | } else { | ||
2092 | return false; | ||
2093 | } | ||
2094 | }, | ||
2095 | |||
2096 | /** | ||
2097 | * unload event handler | ||
2098 | * @method _onUnload | ||
2099 | * @private | ||
2100 | * @static | ||
2101 | */ | ||
2102 | _onUnload: function(e, me) { | ||
2103 | this.unregAll(); | ||
2104 | }, | ||
2105 | |||
2106 | /** | ||
2107 | * Cleans up the drag and drop events and objects. | ||
2108 | * @method unregAll | ||
2109 | * @private | ||
2110 | * @static | ||
2111 | */ | ||
2112 | unregAll: function() { | ||
2113 | |||
2114 | if (this.dragCurrent) { | ||
2115 | this.stopDrag(); | ||
2116 | this.dragCurrent = null; | ||
2117 | } | ||
2118 | |||
2119 | this._execOnAll("unreg", []); | ||
2120 | |||
2121 | for (i in this.elementCache) { | ||
2122 | delete this.elementCache[i]; | ||
2123 | } | ||
2124 | |||
2125 | this.elementCache = {}; | ||
2126 | this.ids = {}; | ||
2127 | }, | ||
2128 | |||
2129 | /** | ||
2130 | * A cache of DOM elements | ||
2131 | * @property elementCache | ||
2132 | * @private | ||
2133 | * @static | ||
2134 | */ | ||
2135 | elementCache: {}, | ||
2136 | |||
2137 | /** | ||
2138 | * Get the wrapper for the DOM element specified | ||
2139 | * @method getElWrapper | ||
2140 | * @param {String} id the id of the element to get | ||
2141 | * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element | ||
2142 | * @private | ||
2143 | * @deprecated This wrapper isn't that useful | ||
2144 | * @static | ||
2145 | */ | ||
2146 | getElWrapper: function(id) { | ||
2147 | var oWrapper = this.elementCache[id]; | ||
2148 | if (!oWrapper || !oWrapper.el) { | ||
2149 | oWrapper = this.elementCache[id] = | ||
2150 | new this.ElementWrapper(YAHOO.util.Dom.get(id)); | ||
2151 | } | ||
2152 | return oWrapper; | ||
2153 | }, | ||
2154 | |||
2155 | /** | ||
2156 | * Returns the actual DOM element | ||
2157 | * @method getElement | ||
2158 | * @param {String} id the id of the elment to get | ||
2159 | * @return {Object} The element | ||
2160 | * @deprecated use YAHOO.util.Dom.get instead | ||
2161 | * @static | ||
2162 | */ | ||
2163 | getElement: function(id) { | ||
2164 | return YAHOO.util.Dom.get(id); | ||
2165 | }, | ||
2166 | |||
2167 | /** | ||
2168 | * Returns the style property for the DOM element (i.e., | ||
2169 | * document.getElById(id).style) | ||
2170 | * @method getCss | ||
2171 | * @param {String} id the id of the elment to get | ||
2172 | * @return {Object} The style property of the element | ||
2173 | * @deprecated use YAHOO.util.Dom instead | ||
2174 | * @static | ||
2175 | */ | ||
2176 | getCss: function(id) { | ||
2177 | var el = YAHOO.util.Dom.get(id); | ||
2178 | return (el) ? el.style : null; | ||
2179 | }, | ||
2180 | |||
2181 | /** | ||
2182 | * Inner class for cached elements | ||
2183 | * @class DragDropMgr.ElementWrapper | ||
2184 | * @for DragDropMgr | ||
2185 | * @private | ||
2186 | * @deprecated | ||
2187 | */ | ||
2188 | ElementWrapper: function(el) { | ||
2189 | /** | ||
2190 | * The element | ||
2191 | * @property el | ||
2192 | */ | ||
2193 | this.el = el || null; | ||
2194 | /** | ||
2195 | * The element id | ||
2196 | * @property id | ||
2197 | */ | ||
2198 | this.id = this.el && el.id; | ||
2199 | /** | ||
2200 | * A reference to the style property | ||
2201 | * @property css | ||
2202 | */ | ||
2203 | this.css = this.el && el.style; | ||
2204 | }, | ||
2205 | |||
2206 | /** | ||
2207 | * Returns the X position of an html element | ||
2208 | * @method getPosX | ||
2209 | * @param el the element for which to get the position | ||
2210 | * @return {int} the X coordinate | ||
2211 | * @for DragDropMgr | ||
2212 | * @deprecated use YAHOO.util.Dom.getX instead | ||
2213 | * @static | ||
2214 | */ | ||
2215 | getPosX: function(el) { | ||
2216 | return YAHOO.util.Dom.getX(el); | ||
2217 | }, | ||
2218 | |||
2219 | /** | ||
2220 | * Returns the Y position of an html element | ||
2221 | * @method getPosY | ||
2222 | * @param el the element for which to get the position | ||
2223 | * @return {int} the Y coordinate | ||
2224 | * @deprecated use YAHOO.util.Dom.getY instead | ||
2225 | * @static | ||
2226 | */ | ||
2227 | getPosY: function(el) { | ||
2228 | return YAHOO.util.Dom.getY(el); | ||
2229 | }, | ||
2230 | |||
2231 | /** | ||
2232 | * Swap two nodes. In IE, we use the native method, for others we | ||
2233 | * emulate the IE behavior | ||
2234 | * @method swapNode | ||
2235 | * @param n1 the first node to swap | ||
2236 | * @param n2 the other node to swap | ||
2237 | * @static | ||
2238 | */ | ||
2239 | swapNode: function(n1, n2) { | ||
2240 | if (n1.swapNode) { | ||
2241 | n1.swapNode(n2); | ||
2242 | } else { | ||
2243 | var p = n2.parentNode; | ||
2244 | var s = n2.nextSibling; | ||
2245 | |||
2246 | if (s == n1) { | ||
2247 | p.insertBefore(n1, n2); | ||
2248 | } else if (n2 == n1.nextSibling) { | ||
2249 | p.insertBefore(n2, n1); | ||
2250 | } else { | ||
2251 | n1.parentNode.replaceChild(n2, n1); | ||
2252 | p.insertBefore(n1, s); | ||
2253 | } | ||
2254 | } | ||
2255 | }, | ||
2256 | |||
2257 | /** | ||
2258 | * Returns the current scroll position | ||
2259 | * @method getScroll | ||
2260 | * @private | ||
2261 | * @static | ||
2262 | */ | ||
2263 | getScroll: function () { | ||
2264 | var t, l, dde=document.documentElement, db=document.body; | ||
2265 | if (dde && (dde.scrollTop || dde.scrollLeft)) { | ||
2266 | t = dde.scrollTop; | ||
2267 | l = dde.scrollLeft; | ||
2268 | } else if (db) { | ||
2269 | t = db.scrollTop; | ||
2270 | l = db.scrollLeft; | ||
2271 | } else { | ||
2272 | YAHOO.log("could not get scroll property"); | ||
2273 | } | ||
2274 | return { top: t, left: l }; | ||
2275 | }, | ||
2276 | |||
2277 | /** | ||
2278 | * Returns the specified element style property | ||
2279 | * @method getStyle | ||
2280 | * @param {HTMLElement} el the element | ||
2281 | * @param {string} styleProp the style property | ||
2282 | * @return {string} The value of the style property | ||
2283 | * @deprecated use YAHOO.util.Dom.getStyle | ||
2284 | * @static | ||
2285 | */ | ||
2286 | getStyle: function(el, styleProp) { | ||
2287 | return YAHOO.util.Dom.getStyle(el, styleProp); | ||
2288 | }, | ||
2289 | |||
2290 | /** | ||
2291 | * Gets the scrollTop | ||
2292 | * @method getScrollTop | ||
2293 | * @return {int} the document's scrollTop | ||
2294 | * @static | ||
2295 | */ | ||
2296 | getScrollTop: function () { return this.getScroll().top; }, | ||
2297 | |||
2298 | /** | ||
2299 | * Gets the scrollLeft | ||
2300 | * @method getScrollLeft | ||
2301 | * @return {int} the document's scrollTop | ||
2302 | * @static | ||
2303 | */ | ||
2304 | getScrollLeft: function () { return this.getScroll().left; }, | ||
2305 | |||
2306 | /** | ||
2307 | * Sets the x/y position of an element to the location of the | ||
2308 | * target element. | ||
2309 | * @method moveToEl | ||
2310 | * @param {HTMLElement} moveEl The element to move | ||
2311 | * @param {HTMLElement} targetEl The position reference element | ||
2312 | * @static | ||
2313 | */ | ||
2314 | moveToEl: function (moveEl, targetEl) { | ||
2315 | var aCoord = YAHOO.util.Dom.getXY(targetEl); | ||
2316 | YAHOO.util.Dom.setXY(moveEl, aCoord); | ||
2317 | }, | ||
2318 | |||
2319 | /** | ||
2320 | * Gets the client height | ||
2321 | * @method getClientHeight | ||
2322 | * @return {int} client height in px | ||
2323 | * @deprecated use YAHOO.util.Dom.getViewportHeight instead | ||
2324 | * @static | ||
2325 | */ | ||
2326 | getClientHeight: function() { | ||
2327 | return YAHOO.util.Dom.getViewportHeight(); | ||
2328 | }, | ||
2329 | |||
2330 | /** | ||
2331 | * Gets the client width | ||
2332 | * @method getClientWidth | ||
2333 | * @return {int} client width in px | ||
2334 | * @deprecated use YAHOO.util.Dom.getViewportWidth instead | ||
2335 | * @static | ||
2336 | */ | ||
2337 | getClientWidth: function() { | ||
2338 | return YAHOO.util.Dom.getViewportWidth(); | ||
2339 | }, | ||
2340 | |||
2341 | /** | ||
2342 | * Numeric array sort function | ||
2343 | * @method numericSort | ||
2344 | * @static | ||
2345 | */ | ||
2346 | numericSort: function(a, b) { return (a - b); }, | ||
2347 | |||
2348 | /** | ||
2349 | * Internal counter | ||
2350 | * @property _timeoutCount | ||
2351 | * @private | ||
2352 | * @static | ||
2353 | */ | ||
2354 | _timeoutCount: 0, | ||
2355 | |||
2356 | /** | ||
2357 | * Trying to make the load order less important. Without this we get | ||
2358 | * an error if this file is loaded before the Event Utility. | ||
2359 | * @method _addListeners | ||
2360 | * @private | ||
2361 | * @static | ||
2362 | */ | ||
2363 | _addListeners: function() { | ||
2364 | var DDM = YAHOO.util.DDM; | ||
2365 | if ( YAHOO.util.Event && document ) { | ||
2366 | DDM._onLoad(); | ||
2367 | } else { | ||
2368 | if (DDM._timeoutCount > 2000) { | ||
2369 | } else { | ||
2370 | setTimeout(DDM._addListeners, 10); | ||
2371 | if (document && document.body) { | ||
2372 | DDM._timeoutCount += 1; | ||
2373 | } | ||
2374 | } | ||
2375 | } | ||
2376 | }, | ||
2377 | |||
2378 | /** | ||
2379 | * Recursively searches the immediate parent and all child nodes for | ||
2380 | * the handle element in order to determine wheter or not it was | ||
2381 | * clicked. | ||
2382 | * @method handleWasClicked | ||
2383 | * @param node the html element to inspect | ||
2384 | * @static | ||
2385 | */ | ||
2386 | handleWasClicked: function(node, id) { | ||
2387 | if (this.isHandle(id, node.id)) { | ||
2388 | return true; | ||
2389 | } else { | ||
2390 | // check to see if this is a text node child of the one we want | ||
2391 | var p = node.parentNode; | ||
2392 | |||
2393 | while (p) { | ||
2394 | if (this.isHandle(id, p.id)) { | ||
2395 | return true; | ||
2396 | } else { | ||
2397 | p = p.parentNode; | ||
2398 | } | ||
2399 | } | ||
2400 | } | ||
2401 | |||
2402 | return false; | ||
2403 | } | ||
2404 | |||
2405 | }; | ||
2406 | |||
2407 | }(); | ||
2408 | |||
2409 | // shorter alias, save a few bytes | ||
2410 | YAHOO.util.DDM = YAHOO.util.DragDropMgr; | ||
2411 | YAHOO.util.DDM._addListeners(); | ||
2412 | |||
2413 | } | ||
2414 | |||
2415 | /** | ||
2416 | * A DragDrop implementation where the linked element follows the | ||
2417 | * mouse cursor during a drag. | ||
2418 | * @class DD | ||
2419 | * @extends YAHOO.util.DragDrop | ||
2420 | * @constructor | ||
2421 | * @param {String} id the id of the linked element | ||
2422 | * @param {String} sGroup the group of related DragDrop items | ||
2423 | * @param {object} config an object containing configurable attributes | ||
2424 | * Valid properties for DD: | ||
2425 | * scroll | ||
2426 | */ | ||
2427 | YAHOO.util.DD = function(id, sGroup, config) { | ||
2428 | if (id) { | ||
2429 | this.init(id, sGroup, config); | ||
2430 | } | ||
2431 | }; | ||
2432 | |||
2433 | YAHOO.extend(YAHOO.util.DD, YAHOO.util.DragDrop, { | ||
2434 | |||
2435 | /** | ||
2436 | * When set to true, the utility automatically tries to scroll the browser | ||
2437 | * window wehn a drag and drop element is dragged near the viewport boundary. | ||
2438 | * Defaults to true. | ||
2439 | * @property scroll | ||
2440 | * @type boolean | ||
2441 | */ | ||
2442 | scroll: true, | ||
2443 | |||
2444 | /** | ||
2445 | * Sets the pointer offset to the distance between the linked element's top | ||
2446 | * left corner and the location the element was clicked | ||
2447 | * @method autoOffset | ||
2448 | * @param {int} iPageX the X coordinate of the click | ||
2449 | * @param {int} iPageY the Y coordinate of the click | ||
2450 | */ | ||
2451 | autoOffset: function(iPageX, iPageY) { | ||
2452 | var x = iPageX - this.startPageX; | ||
2453 | var y = iPageY - this.startPageY; | ||
2454 | this.setDelta(x, y); | ||
2455 | }, | ||
2456 | |||
2457 | /** | ||
2458 | * Sets the pointer offset. You can call this directly to force the | ||
2459 | * offset to be in a particular location (e.g., pass in 0,0 to set it | ||
2460 | * to the center of the object, as done in YAHOO.widget.Slider) | ||
2461 | * @method setDelta | ||
2462 | * @param {int} iDeltaX the distance from the left | ||
2463 | * @param {int} iDeltaY the distance from the top | ||
2464 | */ | ||
2465 | setDelta: function(iDeltaX, iDeltaY) { | ||
2466 | this.deltaX = iDeltaX; | ||
2467 | this.deltaY = iDeltaY; | ||
2468 | }, | ||
2469 | |||
2470 | /** | ||
2471 | * Sets the drag element to the location of the mousedown or click event, | ||
2472 | * maintaining the cursor location relative to the location on the element | ||
2473 | * that was clicked. Override this if you want to place the element in a | ||
2474 | * location other than where the cursor is. | ||
2475 | * @method setDragElPos | ||
2476 | * @param {int} iPageX the X coordinate of the mousedown or drag event | ||
2477 | * @param {int} iPageY the Y coordinate of the mousedown or drag event | ||
2478 | */ | ||
2479 | setDragElPos: function(iPageX, iPageY) { | ||
2480 | // the first time we do this, we are going to check to make sure | ||
2481 | // the element has css positioning | ||
2482 | |||
2483 | var el = this.getDragEl(); | ||
2484 | this.alignElWithMouse(el, iPageX, iPageY); | ||
2485 | }, | ||
2486 | |||
2487 | /** | ||
2488 | * Sets the element to the location of the mousedown or click event, | ||
2489 | * maintaining the cursor location relative to the location on the element | ||
2490 | * that was clicked. Override this if you want to place the element in a | ||
2491 | * location other than where the cursor is. | ||
2492 | * @method alignElWithMouse | ||
2493 | * @param {HTMLElement} el the element to move | ||
2494 | * @param {int} iPageX the X coordinate of the mousedown or drag event | ||
2495 | * @param {int} iPageY the Y coordinate of the mousedown or drag event | ||
2496 | */ | ||
2497 | alignElWithMouse: function(el, iPageX, iPageY) { | ||
2498 | var oCoord = this.getTargetCoord(iPageX, iPageY); | ||
2499 | |||
2500 | if (!this.deltaSetXY) { | ||
2501 | var aCoord = [oCoord.x, oCoord.y]; | ||
2502 | YAHOO.util.Dom.setXY(el, aCoord); | ||
2503 | var newLeft = parseInt( YAHOO.util.Dom.getStyle(el, "left"), 10 ); | ||
2504 | var newTop = parseInt( YAHOO.util.Dom.getStyle(el, "top" ), 10 ); | ||
2505 | |||
2506 | this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ]; | ||
2507 | } else { | ||
2508 | YAHOO.util.Dom.setStyle(el, "left", (oCoord.x + this.deltaSetXY[0]) + "px"); | ||
2509 | YAHOO.util.Dom.setStyle(el, "top", (oCoord.y + this.deltaSetXY[1]) + "px"); | ||
2510 | } | ||
2511 | |||
2512 | this.cachePosition(oCoord.x, oCoord.y); | ||
2513 | this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth); | ||
2514 | }, | ||
2515 | |||
2516 | /** | ||
2517 | * Saves the most recent position so that we can reset the constraints and | ||
2518 | * tick marks on-demand. We need to know this so that we can calculate the | ||
2519 | * number of pixels the element is offset from its original position. | ||
2520 | * @method cachePosition | ||
2521 | * @param iPageX the current x position (optional, this just makes it so we | ||
2522 | * don't have to look it up again) | ||
2523 | * @param iPageY the current y position (optional, this just makes it so we | ||
2524 | * don't have to look it up again) | ||
2525 | */ | ||
2526 | cachePosition: function(iPageX, iPageY) { | ||
2527 | if (iPageX) { | ||
2528 | this.lastPageX = iPageX; | ||
2529 | this.lastPageY = iPageY; | ||
2530 | } else { | ||
2531 | var aCoord = YAHOO.util.Dom.getXY(this.getEl()); | ||
2532 | this.lastPageX = aCoord[0]; | ||
2533 | this.lastPageY = aCoord[1]; | ||
2534 | } | ||
2535 | }, | ||
2536 | |||
2537 | /** | ||
2538 | * Auto-scroll the window if the dragged object has been moved beyond the | ||
2539 | * visible window boundary. | ||
2540 | * @method autoScroll | ||
2541 | * @param {int} x the drag element's x position | ||
2542 | * @param {int} y the drag element's y position | ||
2543 | * @param {int} h the height of the drag element | ||
2544 | * @param {int} w the width of the drag element | ||
2545 | * @private | ||
2546 | */ | ||
2547 | autoScroll: function(x, y, h, w) { | ||
2548 | |||
2549 | if (this.scroll) { | ||
2550 | // The client height | ||
2551 | var clientH = this.DDM.getClientHeight(); | ||
2552 | |||
2553 | // The client width | ||
2554 | var clientW = this.DDM.getClientWidth(); | ||
2555 | |||
2556 | // The amt scrolled down | ||
2557 | var st = this.DDM.getScrollTop(); | ||
2558 | |||
2559 | // The amt scrolled right | ||
2560 | var sl = this.DDM.getScrollLeft(); | ||
2561 | |||
2562 | // Location of the bottom of the element | ||
2563 | var bot = h + y; | ||
2564 | |||
2565 | // Location of the right of the element | ||
2566 | var right = w + x; | ||
2567 | |||
2568 | // The distance from the cursor to the bottom of the visible area, | ||
2569 | // adjusted so that we don't scroll if the cursor is beyond the | ||
2570 | // element drag constraints | ||
2571 | var toBot = (clientH + st - y - this.deltaY); | ||
2572 | |||
2573 | // The distance from the cursor to the right of the visible area | ||
2574 | var toRight = (clientW + sl - x - this.deltaX); | ||
2575 | |||
2576 | |||
2577 | // How close to the edge the cursor must be before we scroll | ||
2578 | // var thresh = (document.all) ? 100 : 40; | ||
2579 | var thresh = 40; | ||
2580 | |||
2581 | // How many pixels to scroll per autoscroll op. This helps to reduce | ||
2582 | // clunky scrolling. IE is more sensitive about this ... it needs this | ||
2583 | // value to be higher. | ||
2584 | var scrAmt = (document.all) ? 80 : 30; | ||
2585 | |||
2586 | // Scroll down if we are near the bottom of the visible page and the | ||
2587 | // obj extends below the crease | ||
2588 | if ( bot > clientH && toBot < thresh ) { | ||
2589 | window.scrollTo(sl, st + scrAmt); | ||
2590 | } | ||
2591 | |||
2592 | // Scroll up if the window is scrolled down and the top of the object | ||
2593 | // goes above the top border | ||
2594 | if ( y < st && st > 0 && y - st < thresh ) { | ||
2595 | window.scrollTo(sl, st - scrAmt); | ||
2596 | } | ||
2597 | |||
2598 | // Scroll right if the obj is beyond the right border and the cursor is | ||
2599 | // near the border. | ||
2600 | if ( right > clientW && toRight < thresh ) { | ||
2601 | window.scrollTo(sl + scrAmt, st); | ||
2602 | } | ||
2603 | |||
2604 | // Scroll left if the window has been scrolled to the right and the obj | ||
2605 | // extends past the left border | ||
2606 | if ( x < sl && sl > 0 && x - sl < thresh ) { | ||
2607 | window.scrollTo(sl - scrAmt, st); | ||
2608 | } | ||
2609 | } | ||
2610 | }, | ||
2611 | |||
2612 | /** | ||
2613 | * Finds the location the element should be placed if we want to move | ||
2614 | * it to where the mouse location less the click offset would place us. | ||
2615 | * @method getTargetCoord | ||
2616 | * @param {int} iPageX the X coordinate of the click | ||
2617 | * @param {int} iPageY the Y coordinate of the click | ||
2618 | * @return an object that contains the coordinates (Object.x and Object.y) | ||
2619 | * @private | ||
2620 | */ | ||
2621 | getTargetCoord: function(iPageX, iPageY) { | ||
2622 | |||
2623 | |||
2624 | var x = iPageX - this.deltaX; | ||
2625 | var y = iPageY - this.deltaY; | ||
2626 | |||
2627 | if (this.constrainX) { | ||
2628 | if (x < this.minX) { x = this.minX; } | ||
2629 | if (x > this.maxX) { x = this.maxX; } | ||
2630 | } | ||
2631 | |||
2632 | if (this.constrainY) { | ||
2633 | if (y < this.minY) { y = this.minY; } | ||
2634 | if (y > this.maxY) { y = this.maxY; } | ||
2635 | } | ||
2636 | |||
2637 | x = this.getTick(x, this.xTicks); | ||
2638 | y = this.getTick(y, this.yTicks); | ||
2639 | |||
2640 | |||
2641 | return {x:x, y:y}; | ||
2642 | }, | ||
2643 | |||
2644 | /* | ||
2645 | * Sets up config options specific to this class. Overrides | ||
2646 | * YAHOO.util.DragDrop, but all versions of this method through the | ||
2647 | * inheritance chain are called | ||
2648 | */ | ||
2649 | applyConfig: function() { | ||
2650 | YAHOO.util.DD.superclass.applyConfig.call(this); | ||
2651 | this.scroll = (this.config.scroll !== false); | ||
2652 | }, | ||
2653 | |||
2654 | /* | ||
2655 | * Event that fires prior to the onMouseDown event. Overrides | ||
2656 | * YAHOO.util.DragDrop. | ||
2657 | */ | ||
2658 | b4MouseDown: function(e) { | ||
2659 | // this.resetConstraints(); | ||
2660 | this.autoOffset(YAHOO.util.Event.getPageX(e), | ||
2661 | YAHOO.util.Event.getPageY(e)); | ||
2662 | }, | ||
2663 | |||
2664 | /* | ||
2665 | * Event that fires prior to the onDrag event. Overrides | ||
2666 | * YAHOO.util.DragDrop. | ||
2667 | */ | ||
2668 | b4Drag: function(e) { | ||
2669 | this.setDragElPos(YAHOO.util.Event.getPageX(e), | ||
2670 | YAHOO.util.Event.getPageY(e)); | ||
2671 | }, | ||
2672 | |||
2673 | toString: function() { | ||
2674 | return ("DD " + this.id); | ||
2675 | } | ||
2676 | |||
2677 | ////////////////////////////////////////////////////////////////////////// | ||
2678 | // Debugging ygDragDrop events that can be overridden | ||
2679 | ////////////////////////////////////////////////////////////////////////// | ||
2680 | /* | ||
2681 | startDrag: function(x, y) { | ||
2682 | }, | ||
2683 | |||
2684 | onDrag: function(e) { | ||
2685 | }, | ||
2686 | |||
2687 | onDragEnter: function(e, id) { | ||
2688 | }, | ||
2689 | |||
2690 | onDragOver: function(e, id) { | ||
2691 | }, | ||
2692 | |||
2693 | onDragOut: function(e, id) { | ||
2694 | }, | ||
2695 | |||
2696 | onDragDrop: function(e, id) { | ||
2697 | }, | ||
2698 | |||
2699 | endDrag: function(e) { | ||
2700 | } | ||
2701 | |||
2702 | */ | ||
2703 | |||
2704 | }); | ||
2705 | /** | ||
2706 | * A DragDrop implementation that inserts an empty, bordered div into | ||
2707 | * the document that follows the cursor during drag operations. At the time of | ||
2708 | * the click, the frame div is resized to the dimensions of the linked html | ||
2709 | * element, and moved to the exact location of the linked element. | ||
2710 | * | ||
2711 | * References to the "frame" element refer to the single proxy element that | ||
2712 | * was created to be dragged in place of all DDProxy elements on the | ||
2713 | * page. | ||
2714 | * | ||
2715 | * @class DDProxy | ||
2716 | * @extends YAHOO.util.DD | ||
2717 | * @constructor | ||
2718 | * @param {String} id the id of the linked html element | ||
2719 | * @param {String} sGroup the group of related DragDrop objects | ||
2720 | * @param {object} config an object containing configurable attributes | ||
2721 | * Valid properties for DDProxy in addition to those in DragDrop: | ||
2722 | * resizeFrame, centerFrame, dragElId | ||
2723 | */ | ||
2724 | YAHOO.util.DDProxy = function(id, sGroup, config) { | ||
2725 | if (id) { | ||
2726 | this.init(id, sGroup, config); | ||
2727 | this.initFrame(); | ||
2728 | } | ||
2729 | }; | ||
2730 | |||
2731 | /** | ||
2732 | * The default drag frame div id | ||
2733 | * @property YAHOO.util.DDProxy.dragElId | ||
2734 | * @type String | ||
2735 | * @static | ||
2736 | */ | ||
2737 | YAHOO.util.DDProxy.dragElId = "ygddfdiv"; | ||
2738 | |||
2739 | YAHOO.extend(YAHOO.util.DDProxy, YAHOO.util.DD, { | ||
2740 | |||
2741 | /** | ||
2742 | * By default we resize the drag frame to be the same size as the element | ||
2743 | * we want to drag (this is to get the frame effect). We can turn it off | ||
2744 | * if we want a different behavior. | ||
2745 | * @property resizeFrame | ||
2746 | * @type boolean | ||
2747 | */ | ||
2748 | resizeFrame: true, | ||
2749 | |||
2750 | /** | ||
2751 | * By default the frame is positioned exactly where the drag element is, so | ||
2752 | * we use the cursor offset provided by YAHOO.util.DD. Another option that works only if | ||
2753 | * you do not have constraints on the obj is to have the drag frame centered | ||
2754 | * around the cursor. Set centerFrame to true for this effect. | ||
2755 | * @property centerFrame | ||
2756 | * @type boolean | ||
2757 | */ | ||
2758 | centerFrame: false, | ||
2759 | |||
2760 | /** | ||
2761 | * Creates the proxy element if it does not yet exist | ||
2762 | * @method createFrame | ||
2763 | */ | ||
2764 | createFrame: function() { | ||
2765 | var self = this; | ||
2766 | var body = document.body; | ||
2767 | |||
2768 | if (!body || !body.firstChild) { | ||
2769 | setTimeout( function() { self.createFrame(); }, 50 ); | ||
2770 | return; | ||
2771 | } | ||
2772 | |||
2773 | var div = this.getDragEl(); | ||
2774 | |||
2775 | if (!div) { | ||
2776 | div = document.createElement("div"); | ||
2777 | div.id = this.dragElId; | ||
2778 | var s = div.style; | ||
2779 | |||
2780 | s.position = "absolute"; | ||
2781 | s.visibility = "hidden"; | ||
2782 | s.cursor = "move"; | ||
2783 | s.border = "2px solid #aaa"; | ||
2784 | s.zIndex = 999; | ||
2785 | |||
2786 | // appendChild can blow up IE if invoked prior to the window load event | ||
2787 | // while rendering a table. It is possible there are other scenarios | ||
2788 | // that would cause this to happen as well. | ||
2789 | body.insertBefore(div, body.firstChild); | ||
2790 | } | ||
2791 | }, | ||
2792 | |||
2793 | /** | ||
2794 | * Initialization for the drag frame element. Must be called in the | ||
2795 | * constructor of all subclasses | ||
2796 | * @method initFrame | ||
2797 | */ | ||
2798 | initFrame: function() { | ||
2799 | this.createFrame(); | ||
2800 | }, | ||
2801 | |||
2802 | applyConfig: function() { | ||
2803 | YAHOO.util.DDProxy.superclass.applyConfig.call(this); | ||
2804 | |||
2805 | this.resizeFrame = (this.config.resizeFrame !== false); | ||
2806 | this.centerFrame = (this.config.centerFrame); | ||
2807 | this.setDragElId(this.config.dragElId || YAHOO.util.DDProxy.dragElId); | ||
2808 | }, | ||
2809 | |||
2810 | /** | ||
2811 | * Resizes the drag frame to the dimensions of the clicked object, positions | ||
2812 | * it over the object, and finally displays it | ||
2813 | * @method showFrame | ||
2814 | * @param {int} iPageX X click position | ||
2815 | * @param {int} iPageY Y click position | ||
2816 | * @private | ||
2817 | */ | ||
2818 | showFrame: function(iPageX, iPageY) { | ||
2819 | var el = this.getEl(); | ||
2820 | var dragEl = this.getDragEl(); | ||
2821 | var s = dragEl.style; | ||
2822 | |||
2823 | this._resizeProxy(); | ||
2824 | |||
2825 | if (this.centerFrame) { | ||
2826 | this.setDelta( Math.round(parseInt(s.width, 10)/2), | ||
2827 | Math.round(parseInt(s.height, 10)/2) ); | ||
2828 | } | ||
2829 | |||
2830 | this.setDragElPos(iPageX, iPageY); | ||
2831 | |||
2832 | YAHOO.util.Dom.setStyle(dragEl, "visibility", "visible"); | ||
2833 | }, | ||
2834 | |||
2835 | /** | ||
2836 | * The proxy is automatically resized to the dimensions of the linked | ||
2837 | * element when a drag is initiated, unless resizeFrame is set to false | ||
2838 | * @method _resizeProxy | ||
2839 | * @private | ||
2840 | */ | ||
2841 | _resizeProxy: function() { | ||
2842 | if (this.resizeFrame) { | ||
2843 | var DOM = YAHOO.util.Dom; | ||
2844 | var el = this.getEl(); | ||
2845 | var dragEl = this.getDragEl(); | ||
2846 | |||
2847 | var bt = parseInt( DOM.getStyle(dragEl, "borderTopWidth" ), 10); | ||
2848 | var br = parseInt( DOM.getStyle(dragEl, "borderRightWidth" ), 10); | ||
2849 | var bb = parseInt( DOM.getStyle(dragEl, "borderBottomWidth" ), 10); | ||
2850 | var bl = parseInt( DOM.getStyle(dragEl, "borderLeftWidth" ), 10); | ||
2851 | |||
2852 | if (isNaN(bt)) { bt = 0; } | ||
2853 | if (isNaN(br)) { br = 0; } | ||
2854 | if (isNaN(bb)) { bb = 0; } | ||
2855 | if (isNaN(bl)) { bl = 0; } | ||
2856 | |||
2857 | |||
2858 | var newWidth = Math.max(0, el.offsetWidth - br - bl); | ||
2859 | var newHeight = Math.max(0, el.offsetHeight - bt - bb); | ||
2860 | |||
2861 | |||
2862 | DOM.setStyle( dragEl, "width", newWidth + "px" ); | ||
2863 | DOM.setStyle( dragEl, "height", newHeight + "px" ); | ||
2864 | } | ||
2865 | }, | ||
2866 | |||
2867 | // overrides YAHOO.util.DragDrop | ||
2868 | b4MouseDown: function(e) { | ||
2869 | var x = YAHOO.util.Event.getPageX(e); | ||
2870 | var y = YAHOO.util.Event.getPageY(e); | ||
2871 | this.autoOffset(x, y); | ||
2872 | this.setDragElPos(x, y); | ||
2873 | }, | ||
2874 | |||
2875 | // overrides YAHOO.util.DragDrop | ||
2876 | b4StartDrag: function(x, y) { | ||
2877 | // show the drag frame | ||
2878 | this.showFrame(x, y); | ||
2879 | }, | ||
2880 | |||
2881 | // overrides YAHOO.util.DragDrop | ||
2882 | b4EndDrag: function(e) { | ||
2883 | YAHOO.util.Dom.setStyle(this.getDragEl(), "visibility", "hidden"); | ||
2884 | }, | ||
2885 | |||
2886 | // overrides YAHOO.util.DragDrop | ||
2887 | // By default we try to move the element to the last location of the frame. | ||
2888 | // This is so that the default behavior mirrors that of YAHOO.util.DD. | ||
2889 | endDrag: function(e) { | ||
2890 | var DOM = YAHOO.util.Dom; | ||
2891 | var lel = this.getEl(); | ||
2892 | var del = this.getDragEl(); | ||
2893 | |||
2894 | // Show the drag frame briefly so we can get its position | ||
2895 | // del.style.visibility = ""; | ||
2896 | DOM.setStyle(del, "visibility", ""); | ||
2897 | |||
2898 | // Hide the linked element before the move to get around a Safari | ||
2899 | // rendering bug. | ||
2900 | //lel.style.visibility = "hidden"; | ||
2901 | DOM.setStyle(lel, "visibility", "hidden"); | ||
2902 | YAHOO.util.DDM.moveToEl(lel, del); | ||
2903 | //del.style.visibility = "hidden"; | ||
2904 | DOM.setStyle(del, "visibility", "hidden"); | ||
2905 | //lel.style.visibility = ""; | ||
2906 | DOM.setStyle(lel, "visibility", ""); | ||
2907 | }, | ||
2908 | |||
2909 | toString: function() { | ||
2910 | return ("DDProxy " + this.id); | ||
2911 | } | ||
2912 | |||
2913 | }); | ||
2914 | /** | ||
2915 | * A DragDrop implementation that does not move, but can be a drop | ||
2916 | * target. You would get the same result by simply omitting implementation | ||
2917 | * for the event callbacks, but this way we reduce the processing cost of the | ||
2918 | * event listener and the callbacks. | ||
2919 | * @class DDTarget | ||
2920 | * @extends YAHOO.util.DragDrop | ||
2921 | * @constructor | ||
2922 | * @param {String} id the id of the element that is a drop target | ||
2923 | * @param {String} sGroup the group of related DragDrop objects | ||
2924 | * @param {object} config an object containing configurable attributes | ||
2925 | * Valid properties for DDTarget in addition to those in | ||
2926 | * DragDrop: | ||
2927 | * none | ||
2928 | */ | ||
2929 | YAHOO.util.DDTarget = function(id, sGroup, config) { | ||
2930 | if (id) { | ||
2931 | this.initTarget(id, sGroup, config); | ||
2932 | } | ||
2933 | }; | ||
2934 | |||
2935 | // YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop(); | ||
2936 | YAHOO.extend(YAHOO.util.DDTarget, YAHOO.util.DragDrop, { | ||
2937 | toString: function() { | ||
2938 | return ("DDTarget " + this.id); | ||
2939 | } | ||
2940 | }); | ||