Diffstat (limited to 'frontend/gamma/js/MochiKit/DragAndDrop.js') (more/less context) (ignore whitespace changes)
-rw-r--r-- | frontend/gamma/js/MochiKit/DragAndDrop.js | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/frontend/gamma/js/MochiKit/DragAndDrop.js b/frontend/gamma/js/MochiKit/DragAndDrop.js new file mode 100644 index 0000000..62777c5 --- a/dev/null +++ b/frontend/gamma/js/MochiKit/DragAndDrop.js | |||
@@ -0,0 +1,766 @@ | |||
1 | /*** | ||
2 | MochiKit.DragAndDrop 1.5 | ||
3 | |||
4 | See <http://mochikit.com/> for documentation, downloads, license, etc. | ||
5 | |||
6 | Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) | ||
7 | Mochi-ized By Thomas Herve (_firstname_@nimail.org) | ||
8 | |||
9 | ***/ | ||
10 | |||
11 | MochiKit.Base._module('DragAndDrop', '1.5', ['Base', 'Iter', 'DOM', 'Signal', 'Visual', 'Position']); | ||
12 | |||
13 | MochiKit.DragAndDrop.Droppables = { | ||
14 | /*** | ||
15 | |||
16 | Manage all droppables. Shouldn't be used, use the Droppable object instead. | ||
17 | |||
18 | ***/ | ||
19 | drops: [], | ||
20 | |||
21 | remove: function (element) { | ||
22 | this.drops = MochiKit.Base.filter(function (d) { | ||
23 | return d.element != MochiKit.DOM.getElement(element); | ||
24 | }, this.drops); | ||
25 | }, | ||
26 | |||
27 | register: function (drop) { | ||
28 | this.drops.push(drop); | ||
29 | }, | ||
30 | |||
31 | unregister: function (drop) { | ||
32 | this.drops = MochiKit.Base.filter(function (d) { | ||
33 | return d != drop; | ||
34 | }, this.drops); | ||
35 | }, | ||
36 | |||
37 | prepare: function (element) { | ||
38 | MochiKit.Base.map(function (drop) { | ||
39 | if (drop.isAccepted(element)) { | ||
40 | if (drop.options.activeclass) { | ||
41 | MochiKit.DOM.addElementClass(drop.element, | ||
42 | drop.options.activeclass); | ||
43 | } | ||
44 | drop.options.onactive(drop.element, element); | ||
45 | } | ||
46 | }, this.drops); | ||
47 | }, | ||
48 | |||
49 | findDeepestChild: function (drops) { | ||
50 | var deepest = drops[0]; | ||
51 | |||
52 | for (var i = 1; i < drops.length; ++i) { | ||
53 | if (MochiKit.DOM.isChildNode(drops[i].element, deepest.element)) { | ||
54 | deepest = drops[i]; | ||
55 | } | ||
56 | } | ||
57 | return deepest; | ||
58 | }, | ||
59 | |||
60 | show: function (point, element) { | ||
61 | if (!this.drops.length) { | ||
62 | return; | ||
63 | } | ||
64 | var affected = []; | ||
65 | |||
66 | if (this.last_active) { | ||
67 | this.last_active.deactivate(); | ||
68 | } | ||
69 | MochiKit.Iter.forEach(this.drops, function (drop) { | ||
70 | if (drop.isAffected(point, element)) { | ||
71 | affected.push(drop); | ||
72 | } | ||
73 | }); | ||
74 | if (affected.length > 0) { | ||
75 | var drop = this.findDeepestChild(affected); | ||
76 | MochiKit.Position.within(drop.element, point.page.x, point.page.y); | ||
77 | drop.options.onhover(element, drop.element, | ||
78 | MochiKit.Position.overlap(drop.options.overlap, drop.element)); | ||
79 | drop.activate(); | ||
80 | } | ||
81 | }, | ||
82 | |||
83 | fire: function (event, element) { | ||
84 | if (!this.last_active) { | ||
85 | return; | ||
86 | } | ||
87 | MochiKit.Position.prepare(); | ||
88 | |||
89 | if (this.last_active.isAffected(event.mouse(), element)) { | ||
90 | this.last_active.options.ondrop(element, | ||
91 | this.last_active.element, event); | ||
92 | } | ||
93 | }, | ||
94 | |||
95 | reset: function (element) { | ||
96 | MochiKit.Base.map(function (drop) { | ||
97 | if (drop.options.activeclass) { | ||
98 | MochiKit.DOM.removeElementClass(drop.element, | ||
99 | drop.options.activeclass); | ||
100 | } | ||
101 | drop.options.ondesactive(drop.element, element); | ||
102 | }, this.drops); | ||
103 | if (this.last_active) { | ||
104 | this.last_active.deactivate(); | ||
105 | } | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | /** @id MochiKit.DragAndDrop.Droppable */ | ||
110 | MochiKit.DragAndDrop.Droppable = function (element, options) { | ||
111 | var cls = arguments.callee; | ||
112 | if (!(this instanceof cls)) { | ||
113 | return new cls(element, options); | ||
114 | } | ||
115 | this.__init__(element, options); | ||
116 | }; | ||
117 | |||
118 | MochiKit.DragAndDrop.Droppable.prototype = { | ||
119 | /*** | ||
120 | |||
121 | A droppable object. Simple use is to create giving an element: | ||
122 | |||
123 | new MochiKit.DragAndDrop.Droppable('myelement'); | ||
124 | |||
125 | Generally you'll want to define the 'ondrop' function and maybe the | ||
126 | 'accept' option to filter draggables. | ||
127 | |||
128 | ***/ | ||
129 | __class__: MochiKit.DragAndDrop.Droppable, | ||
130 | |||
131 | __init__: function (element, /* optional */options) { | ||
132 | var d = MochiKit.DOM; | ||
133 | var b = MochiKit.Base; | ||
134 | this.element = d.getElement(element); | ||
135 | this.options = b.update({ | ||
136 | |||
137 | /** @id MochiKit.DragAndDrop.greedy */ | ||
138 | greedy: true, | ||
139 | |||
140 | /** @id MochiKit.DragAndDrop.hoverclass */ | ||
141 | hoverclass: null, | ||
142 | |||
143 | /** @id MochiKit.DragAndDrop.activeclass */ | ||
144 | activeclass: null, | ||
145 | |||
146 | /** @id MochiKit.DragAndDrop.hoverfunc */ | ||
147 | hoverfunc: b.noop, | ||
148 | |||
149 | /** @id MochiKit.DragAndDrop.accept */ | ||
150 | accept: null, | ||
151 | |||
152 | /** @id MochiKit.DragAndDrop.onactive */ | ||
153 | onactive: b.noop, | ||
154 | |||
155 | /** @id MochiKit.DragAndDrop.ondesactive */ | ||
156 | ondesactive: b.noop, | ||
157 | |||
158 | /** @id MochiKit.DragAndDrop.onhover */ | ||
159 | onhover: b.noop, | ||
160 | |||
161 | /** @id MochiKit.DragAndDrop.ondrop */ | ||
162 | ondrop: b.noop, | ||
163 | |||
164 | /** @id MochiKit.DragAndDrop.containment */ | ||
165 | containment: [], | ||
166 | tree: false | ||
167 | }, options); | ||
168 | |||
169 | // cache containers | ||
170 | this.options._containers = []; | ||
171 | b.map(MochiKit.Base.bind(function (c) { | ||
172 | this.options._containers.push(d.getElement(c)); | ||
173 | }, this), this.options.containment); | ||
174 | |||
175 | MochiKit.Style.makePositioned(this.element); // fix IE | ||
176 | |||
177 | MochiKit.DragAndDrop.Droppables.register(this); | ||
178 | }, | ||
179 | |||
180 | /** @id MochiKit.DragAndDrop.isContained */ | ||
181 | isContained: function (element) { | ||
182 | if (this.options._containers.length) { | ||
183 | var containmentNode; | ||
184 | if (this.options.tree) { | ||
185 | containmentNode = element.treeNode; | ||
186 | } else { | ||
187 | containmentNode = element.parentNode; | ||
188 | } | ||
189 | return MochiKit.Iter.some(this.options._containers, function (c) { | ||
190 | return containmentNode == c; | ||
191 | }); | ||
192 | } else { | ||
193 | return true; | ||
194 | } | ||
195 | }, | ||
196 | |||
197 | /** @id MochiKit.DragAndDrop.isAccepted */ | ||
198 | isAccepted: function (element) { | ||
199 | return ((!this.options.accept) || MochiKit.Iter.some( | ||
200 | this.options.accept, function (c) { | ||
201 | return MochiKit.DOM.hasElementClass(element, c); | ||
202 | })); | ||
203 | }, | ||
204 | |||
205 | /** @id MochiKit.DragAndDrop.isAffected */ | ||
206 | isAffected: function (point, element) { | ||
207 | return ((this.element != element) && | ||
208 | this.isContained(element) && | ||
209 | this.isAccepted(element) && | ||
210 | MochiKit.Position.within(this.element, point.page.x, | ||
211 | point.page.y)); | ||
212 | }, | ||
213 | |||
214 | /** @id MochiKit.DragAndDrop.deactivate */ | ||
215 | deactivate: function () { | ||
216 | /*** | ||
217 | |||
218 | A droppable is deactivate when a draggable has been over it and left. | ||
219 | |||
220 | ***/ | ||
221 | if (this.options.hoverclass) { | ||
222 | MochiKit.DOM.removeElementClass(this.element, | ||
223 | this.options.hoverclass); | ||
224 | } | ||
225 | this.options.hoverfunc(this.element, false); | ||
226 | MochiKit.DragAndDrop.Droppables.last_active = null; | ||
227 | }, | ||
228 | |||
229 | /** @id MochiKit.DragAndDrop.activate */ | ||
230 | activate: function () { | ||
231 | /*** | ||
232 | |||
233 | A droppable is active when a draggable is over it. | ||
234 | |||
235 | ***/ | ||
236 | if (this.options.hoverclass) { | ||
237 | MochiKit.DOM.addElementClass(this.element, this.options.hoverclass); | ||
238 | } | ||
239 | this.options.hoverfunc(this.element, true); | ||
240 | MochiKit.DragAndDrop.Droppables.last_active = this; | ||
241 | }, | ||
242 | |||
243 | /** @id MochiKit.DragAndDrop.destroy */ | ||
244 | destroy: function () { | ||
245 | /*** | ||
246 | |||
247 | Delete this droppable. | ||
248 | |||
249 | ***/ | ||
250 | MochiKit.DragAndDrop.Droppables.unregister(this); | ||
251 | }, | ||
252 | |||
253 | /** @id MochiKit.DragAndDrop.repr */ | ||
254 | repr: function () { | ||
255 | return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]"; | ||
256 | } | ||
257 | }; | ||
258 | |||
259 | MochiKit.DragAndDrop.Draggables = { | ||
260 | /*** | ||
261 | |||
262 | Manage draggables elements. Not intended to direct use. | ||
263 | |||
264 | ***/ | ||
265 | drags: [], | ||
266 | |||
267 | register: function (draggable) { | ||
268 | if (this.drags.length === 0) { | ||
269 | var conn = MochiKit.Signal.connect; | ||
270 | this.eventMouseUp = conn(document, 'onmouseup', this, this.endDrag); | ||
271 | this.eventMouseMove = conn(document, 'onmousemove', this, | ||
272 | this.updateDrag); | ||
273 | this.eventKeypress = conn(document, 'onkeypress', this, | ||
274 | this.keyPress); | ||
275 | } | ||
276 | this.drags.push(draggable); | ||
277 | }, | ||
278 | |||
279 | unregister: function (draggable) { | ||
280 | this.drags = MochiKit.Base.filter(function (d) { | ||
281 | return d != draggable; | ||
282 | }, this.drags); | ||
283 | if (this.drags.length === 0) { | ||
284 | var disc = MochiKit.Signal.disconnect; | ||
285 | disc(this.eventMouseUp); | ||
286 | disc(this.eventMouseMove); | ||
287 | disc(this.eventKeypress); | ||
288 | } | ||
289 | }, | ||
290 | |||
291 | activate: function (draggable) { | ||
292 | // allows keypress events if window is not currently focused | ||
293 | // fails for Safari | ||
294 | window.focus(); | ||
295 | this.activeDraggable = draggable; | ||
296 | }, | ||
297 | |||
298 | deactivate: function () { | ||
299 | this.activeDraggable = null; | ||
300 | }, | ||
301 | |||
302 | updateDrag: function (event) { | ||
303 | if (!this.activeDraggable) { | ||
304 | return; | ||
305 | } | ||
306 | var pointer = event.mouse(); | ||
307 | // Mozilla-based browsers fire successive mousemove events with | ||
308 | // the same coordinates, prevent needless redrawing (moz bug?) | ||
309 | if (this._lastPointer && (MochiKit.Base.repr(this._lastPointer.page) == | ||
310 | MochiKit.Base.repr(pointer.page))) { | ||
311 | return; | ||
312 | } | ||
313 | this._lastPointer = pointer; | ||
314 | this.activeDraggable.updateDrag(event, pointer); | ||
315 | }, | ||
316 | |||
317 | endDrag: function (event) { | ||
318 | if (!this.activeDraggable) { | ||
319 | return; | ||
320 | } | ||
321 | this._lastPointer = null; | ||
322 | this.activeDraggable.endDrag(event); | ||
323 | this.activeDraggable = null; | ||
324 | }, | ||
325 | |||
326 | keyPress: function (event) { | ||
327 | if (this.activeDraggable) { | ||
328 | this.activeDraggable.keyPress(event); | ||
329 | } | ||
330 | }, | ||
331 | |||
332 | notify: function (eventName, draggable, event) { | ||
333 | MochiKit.Signal.signal(this, eventName, draggable, event); | ||
334 | } | ||
335 | }; | ||
336 | |||
337 | /** @id MochiKit.DragAndDrop.Draggable */ | ||
338 | MochiKit.DragAndDrop.Draggable = function (element, options) { | ||
339 | var cls = arguments.callee; | ||
340 | if (!(this instanceof cls)) { | ||
341 | return new cls(element, options); | ||
342 | } | ||
343 | this.__init__(element, options); | ||
344 | }; | ||
345 | |||
346 | MochiKit.DragAndDrop.Draggable.prototype = { | ||
347 | /*** | ||
348 | |||
349 | A draggable object. Simple instantiate : | ||
350 | |||
351 | new MochiKit.DragAndDrop.Draggable('myelement'); | ||
352 | |||
353 | ***/ | ||
354 | __class__ : MochiKit.DragAndDrop.Draggable, | ||
355 | |||
356 | __init__: function (element, /* optional */options) { | ||
357 | var v = MochiKit.Visual; | ||
358 | var b = MochiKit.Base; | ||
359 | options = b.update({ | ||
360 | |||
361 | /** @id MochiKit.DragAndDrop.handle */ | ||
362 | handle: false, | ||
363 | |||
364 | /** @id MochiKit.DragAndDrop.starteffect */ | ||
365 | starteffect: function (innerelement) { | ||
366 | this._savedOpacity = MochiKit.Style.getStyle(innerelement, 'opacity') || 1.0; | ||
367 | new v.Opacity(innerelement, {duration:0.2, from:this._savedOpacity, to:0.7}); | ||
368 | }, | ||
369 | /** @id MochiKit.DragAndDrop.reverteffect */ | ||
370 | reverteffect: function (innerelement, top_offset, left_offset) { | ||
371 | var dur = Math.sqrt(Math.abs(top_offset^2) + | ||
372 | Math.abs(left_offset^2))*0.02; | ||
373 | return new v.Move(innerelement, | ||
374 | {x: -left_offset, y: -top_offset, duration: dur}); | ||
375 | }, | ||
376 | |||
377 | /** @id MochiKit.DragAndDrop.endeffect */ | ||
378 | endeffect: function (innerelement) { | ||
379 | new v.Opacity(innerelement, {duration:0.2, from:0.7, to:this._savedOpacity}); | ||
380 | }, | ||
381 | |||
382 | /** @id MochiKit.DragAndDrop.onchange */ | ||
383 | onchange: b.noop, | ||
384 | |||
385 | /** @id MochiKit.DragAndDrop.zindex */ | ||
386 | zindex: 1000, | ||
387 | |||
388 | /** @id MochiKit.DragAndDrop.revert */ | ||
389 | revert: false, | ||
390 | |||
391 | /** @id MochiKit.DragAndDrop.scroll */ | ||
392 | scroll: false, | ||
393 | |||
394 | /** @id MochiKit.DragAndDrop.scrollSensitivity */ | ||
395 | scrollSensitivity: 20, | ||
396 | |||
397 | /** @id MochiKit.DragAndDrop.scrollSpeed */ | ||
398 | scrollSpeed: 15, | ||
399 | // false, or xy or [x, y] or function (x, y){return [x, y];} | ||
400 | |||
401 | /** @id MochiKit.DragAndDrop.snap */ | ||
402 | snap: false | ||
403 | }, options); | ||
404 | |||
405 | var d = MochiKit.DOM; | ||
406 | this.element = d.getElement(element); | ||
407 | |||
408 | if (options.handle && (typeof(options.handle) == 'string')) { | ||
409 | this.handle = d.getFirstElementByTagAndClassName(null, | ||
410 | options.handle, this.element); | ||
411 | } | ||
412 | if (!this.handle) { | ||
413 | this.handle = d.getElement(options.handle); | ||
414 | } | ||
415 | if (!this.handle) { | ||
416 | this.handle = this.element; | ||
417 | } | ||
418 | |||
419 | if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { | ||
420 | options.scroll = d.getElement(options.scroll); | ||
421 | this._isScrollChild = MochiKit.DOM.isChildNode(this.element, options.scroll); | ||
422 | } | ||
423 | |||
424 | MochiKit.Style.makePositioned(this.element); // fix IE | ||
425 | |||
426 | this.delta = this.currentDelta(); | ||
427 | this.options = options; | ||
428 | this.dragging = false; | ||
429 | |||
430 | this.eventMouseDown = MochiKit.Signal.connect(this.handle, | ||
431 | 'onmousedown', this, this.initDrag); | ||
432 | MochiKit.DragAndDrop.Draggables.register(this); | ||
433 | }, | ||
434 | |||
435 | /** @id MochiKit.DragAndDrop.destroy */ | ||
436 | destroy: function () { | ||
437 | MochiKit.Signal.disconnect(this.eventMouseDown); | ||
438 | MochiKit.DragAndDrop.Draggables.unregister(this); | ||
439 | }, | ||
440 | |||
441 | /** @id MochiKit.DragAndDrop.currentDelta */ | ||
442 | currentDelta: function () { | ||
443 | var s = MochiKit.Style.getStyle; | ||
444 | return [ | ||
445 | parseInt(s(this.element, 'left') || '0'), | ||
446 | parseInt(s(this.element, 'top') || '0')]; | ||
447 | }, | ||
448 | |||
449 | /** @id MochiKit.DragAndDrop.initDrag */ | ||
450 | initDrag: function (event) { | ||
451 | if (!event.mouse().button.left) { | ||
452 | return; | ||
453 | } | ||
454 | // abort on form elements, fixes a Firefox issue | ||
455 | var src = event.target(); | ||
456 | var tagName = (src.tagName || '').toUpperCase(); | ||
457 | if (tagName === 'INPUT' || tagName === 'SELECT' || | ||
458 | tagName === 'OPTION' || tagName === 'BUTTON' || | ||
459 | tagName === 'TEXTAREA') { | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | if (this._revert) { | ||
464 | this._revert.cancel(); | ||
465 | this._revert = null; | ||
466 | } | ||
467 | |||
468 | var pointer = event.mouse(); | ||
469 | var pos = MochiKit.Position.cumulativeOffset(this.element); | ||
470 | this.offset = [pointer.page.x - pos.x, pointer.page.y - pos.y]; | ||
471 | |||
472 | MochiKit.DragAndDrop.Draggables.activate(this); | ||
473 | event.stop(); | ||
474 | }, | ||
475 | |||
476 | /** @id MochiKit.DragAndDrop.startDrag */ | ||
477 | startDrag: function (event) { | ||
478 | this.dragging = true; | ||
479 | if (this.options.selectclass) { | ||
480 | MochiKit.DOM.addElementClass(this.element, | ||
481 | this.options.selectclass); | ||
482 | } | ||
483 | if (this.options.zindex) { | ||
484 | this.originalZ = parseInt(MochiKit.Style.getStyle(this.element, | ||
485 | 'z-index') || '0'); | ||
486 | this.element.style.zIndex = this.options.zindex; | ||
487 | } | ||
488 | |||
489 | if (this.options.ghosting) { | ||
490 | this._clone = this.element.cloneNode(true); | ||
491 | this.ghostPosition = MochiKit.Position.absolutize(this.element); | ||
492 | this.element.parentNode.insertBefore(this._clone, this.element); | ||
493 | } | ||
494 | |||
495 | if (this.options.scroll) { | ||
496 | if (this.options.scroll == window) { | ||
497 | var where = this._getWindowScroll(this.options.scroll); | ||
498 | this.originalScrollLeft = where.left; | ||
499 | this.originalScrollTop = where.top; | ||
500 | } else { | ||
501 | this.originalScrollLeft = this.options.scroll.scrollLeft; | ||
502 | this.originalScrollTop = this.options.scroll.scrollTop; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | MochiKit.DragAndDrop.Droppables.prepare(this.element); | ||
507 | MochiKit.DragAndDrop.Draggables.notify('start', this, event); | ||
508 | if (this.options.starteffect) { | ||
509 | this.options.starteffect(this.element); | ||
510 | } | ||
511 | }, | ||
512 | |||
513 | /** @id MochiKit.DragAndDrop.updateDrag */ | ||
514 | updateDrag: function (event, pointer) { | ||
515 | if (!this.dragging) { | ||
516 | this.startDrag(event); | ||
517 | } | ||
518 | MochiKit.Position.prepare(); | ||
519 | MochiKit.DragAndDrop.Droppables.show(pointer, this.element); | ||
520 | MochiKit.DragAndDrop.Draggables.notify('drag', this, event); | ||
521 | this.draw(pointer); | ||
522 | this.options.onchange(this); | ||
523 | |||
524 | if (this.options.scroll) { | ||
525 | this.stopScrolling(); | ||
526 | var p, q; | ||
527 | if (this.options.scroll == window) { | ||
528 | var s = this._getWindowScroll(this.options.scroll); | ||
529 | p = new MochiKit.Style.Coordinates(s.left, s.top); | ||
530 | q = new MochiKit.Style.Coordinates(s.left + s.width, | ||
531 | s.top + s.height); | ||
532 | } else { | ||
533 | p = MochiKit.Position.page(this.options.scroll); | ||
534 | p.x += this.options.scroll.scrollLeft; | ||
535 | p.y += this.options.scroll.scrollTop; | ||
536 | p.x += (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0); | ||
537 | p.y += (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0); | ||
538 | q = new MochiKit.Style.Coordinates(p.x + this.options.scroll.offsetWidth, | ||
539 | p.y + this.options.scroll.offsetHeight); | ||
540 | } | ||
541 | var speed = [0, 0]; | ||
542 | if (pointer.page.x > (q.x - this.options.scrollSensitivity)) { | ||
543 | speed[0] = pointer.page.x - (q.x - this.options.scrollSensitivity); | ||
544 | } else if (pointer.page.x < (p.x + this.options.scrollSensitivity)) { | ||
545 | speed[0] = pointer.page.x - (p.x + this.options.scrollSensitivity); | ||
546 | } | ||
547 | if (pointer.page.y > (q.y - this.options.scrollSensitivity)) { | ||
548 | speed[1] = pointer.page.y - (q.y - this.options.scrollSensitivity); | ||
549 | } else if (pointer.page.y < (p.y + this.options.scrollSensitivity)) { | ||
550 | speed[1] = pointer.page.y - (p.y + this.options.scrollSensitivity); | ||
551 | } | ||
552 | this.startScrolling(speed); | ||
553 | } | ||
554 | |||
555 | // fix AppleWebKit rendering | ||
556 | if (/AppleWebKit/.test(navigator.appVersion)) { | ||
557 | window.scrollBy(0, 0); | ||
558 | } | ||
559 | event.stop(); | ||
560 | }, | ||
561 | |||
562 | /** @id MochiKit.DragAndDrop.finishDrag */ | ||
563 | finishDrag: function (event, success) { | ||
564 | var dr = MochiKit.DragAndDrop; | ||
565 | this.dragging = false; | ||
566 | if (this.options.selectclass) { | ||
567 | MochiKit.DOM.removeElementClass(this.element, | ||
568 | this.options.selectclass); | ||
569 | } | ||
570 | |||
571 | if (this.options.ghosting) { | ||
572 | // XXX: from a user point of view, it would be better to remove | ||
573 | // the node only *after* the MochiKit.Visual.Move end when used | ||
574 | // with revert. | ||
575 | MochiKit.Position.relativize(this.element, this.ghostPosition); | ||
576 | MochiKit.DOM.removeElement(this._clone); | ||
577 | this._clone = null; | ||
578 | } | ||
579 | |||
580 | if (success) { | ||
581 | dr.Droppables.fire(event, this.element); | ||
582 | } | ||
583 | dr.Draggables.notify('end', this, event); | ||
584 | |||
585 | var revert = this.options.revert; | ||
586 | if (revert && typeof(revert) == 'function') { | ||
587 | revert = revert(this.element); | ||
588 | } | ||
589 | |||
590 | var d = this.currentDelta(); | ||
591 | if (revert && this.options.reverteffect) { | ||
592 | this._revert = this.options.reverteffect(this.element, | ||
593 | d[1] - this.delta[1], d[0] - this.delta[0]); | ||
594 | } else { | ||
595 | this.delta = d; | ||
596 | } | ||
597 | |||
598 | if (this.options.zindex) { | ||
599 | this.element.style.zIndex = this.originalZ; | ||
600 | } | ||
601 | |||
602 | if (this.options.endeffect) { | ||
603 | this.options.endeffect(this.element); | ||
604 | } | ||
605 | |||
606 | dr.Draggables.deactivate(); | ||
607 | dr.Droppables.reset(this.element); | ||
608 | }, | ||
609 | |||
610 | /** @id MochiKit.DragAndDrop.keyPress */ | ||
611 | keyPress: function (event) { | ||
612 | if (event.key().string != "KEY_ESCAPE") { | ||
613 | return; | ||
614 | } | ||
615 | this.finishDrag(event, false); | ||
616 | event.stop(); | ||
617 | }, | ||
618 | |||
619 | /** @id MochiKit.DragAndDrop.endDrag */ | ||
620 | endDrag: function (event) { | ||
621 | if (!this.dragging) { | ||
622 | return; | ||
623 | } | ||
624 | this.stopScrolling(); | ||
625 | this.finishDrag(event, true); | ||
626 | event.stop(); | ||
627 | }, | ||
628 | |||
629 | /** @id MochiKit.DragAndDrop.draw */ | ||
630 | draw: function (point) { | ||
631 | var pos = MochiKit.Position.cumulativeOffset(this.element); | ||
632 | var d = this.currentDelta(); | ||
633 | pos.x -= d[0]; | ||
634 | pos.y -= d[1]; | ||
635 | |||
636 | if (this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { | ||
637 | pos.x -= this.options.scroll.scrollLeft - this.originalScrollLeft; | ||
638 | pos.y -= this.options.scroll.scrollTop - this.originalScrollTop; | ||
639 | } | ||
640 | |||
641 | var p = [point.page.x - pos.x - this.offset[0], | ||
642 | point.page.y - pos.y - this.offset[1]]; | ||
643 | |||
644 | if (this.options.snap) { | ||
645 | if (typeof(this.options.snap) == 'function') { | ||
646 | p = this.options.snap(p[0], p[1]); | ||
647 | } else { | ||
648 | if (this.options.snap instanceof Array) { | ||
649 | var i = -1; | ||
650 | p = MochiKit.Base.map(MochiKit.Base.bind(function (v) { | ||
651 | i += 1; | ||
652 | return Math.round(v/this.options.snap[i]) * | ||
653 | this.options.snap[i]; | ||
654 | }, this), p); | ||
655 | } else { | ||
656 | p = MochiKit.Base.map(MochiKit.Base.bind(function (v) { | ||
657 | return Math.round(v/this.options.snap) * | ||
658 | this.options.snap; | ||
659 | }, this), p); | ||
660 | } | ||
661 | } | ||
662 | } | ||
663 | var style = this.element.style; | ||
664 | if ((!this.options.constraint) || | ||
665 | (this.options.constraint == 'horizontal')) { | ||
666 | style.left = p[0] + 'px'; | ||
667 | } | ||
668 | if ((!this.options.constraint) || | ||
669 | (this.options.constraint == 'vertical')) { | ||
670 | style.top = p[1] + 'px'; | ||
671 | } | ||
672 | if (style.visibility == 'hidden') { | ||
673 | style.visibility = ''; // fix gecko rendering | ||
674 | } | ||
675 | }, | ||
676 | |||
677 | /** @id MochiKit.DragAndDrop.stopScrolling */ | ||
678 | stopScrolling: function () { | ||
679 | if (this.scrollInterval) { | ||
680 | clearInterval(this.scrollInterval); | ||
681 | this.scrollInterval = null; | ||
682 | MochiKit.DragAndDrop.Draggables._lastScrollPointer = null; | ||
683 | } | ||
684 | }, | ||
685 | |||
686 | /** @id MochiKit.DragAndDrop.startScrolling */ | ||
687 | startScrolling: function (speed) { | ||
688 | if (!speed[0] && !speed[1]) { | ||
689 | return; | ||
690 | } | ||
691 | this.scrollSpeed = [speed[0] * this.options.scrollSpeed, | ||
692 | speed[1] * this.options.scrollSpeed]; | ||
693 | this.lastScrolled = new Date(); | ||
694 | this.scrollInterval = setInterval(MochiKit.Base.bind(this.scroll, this), 10); | ||
695 | }, | ||
696 | |||
697 | /** @id MochiKit.DragAndDrop.scroll */ | ||
698 | scroll: function () { | ||
699 | var current = new Date(); | ||
700 | var delta = current - this.lastScrolled; | ||
701 | this.lastScrolled = current; | ||
702 | |||
703 | if (this.options.scroll == window) { | ||
704 | var s = this._getWindowScroll(this.options.scroll); | ||
705 | if (this.scrollSpeed[0] || this.scrollSpeed[1]) { | ||
706 | var dm = delta / 1000; | ||
707 | this.options.scroll.scrollTo(s.left + dm * this.scrollSpeed[0], | ||
708 | s.top + dm * this.scrollSpeed[1]); | ||
709 | } | ||
710 | } else { | ||
711 | this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; | ||
712 | this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; | ||
713 | } | ||
714 | |||
715 | var d = MochiKit.DragAndDrop; | ||
716 | |||
717 | MochiKit.Position.prepare(); | ||
718 | d.Droppables.show(d.Draggables._lastPointer, this.element); | ||
719 | d.Draggables.notify('drag', this); | ||
720 | if (this._isScrollChild) { | ||
721 | d.Draggables._lastScrollPointer = d.Draggables._lastScrollPointer || d.Draggables._lastPointer; | ||
722 | d.Draggables._lastScrollPointer.x += this.scrollSpeed[0] * delta / 1000; | ||
723 | d.Draggables._lastScrollPointer.y += this.scrollSpeed[1] * delta / 1000; | ||
724 | if (d.Draggables._lastScrollPointer.x < 0) { | ||
725 | d.Draggables._lastScrollPointer.x = 0; | ||
726 | } | ||
727 | if (d.Draggables._lastScrollPointer.y < 0) { | ||
728 | d.Draggables._lastScrollPointer.y = 0; | ||
729 | } | ||
730 | this.draw(d.Draggables._lastScrollPointer); | ||
731 | } | ||
732 | |||
733 | this.options.onchange(this); | ||
734 | }, | ||
735 | |||
736 | _getWindowScroll: function (win) { | ||
737 | var vp, w, h; | ||
738 | MochiKit.DOM.withWindow(win, function () { | ||
739 | vp = MochiKit.Style.getViewportPosition(win.document); | ||
740 | }); | ||
741 | if (win.innerWidth) { | ||
742 | w = win.innerWidth; | ||
743 | h = win.innerHeight; | ||
744 | } else if (win.document.documentElement && win.document.documentElement.clientWidth) { | ||
745 | w = win.document.documentElement.clientWidth; | ||
746 | h = win.document.documentElement.clientHeight; | ||
747 | } else { | ||
748 | w = win.document.body.offsetWidth; | ||
749 | h = win.document.body.offsetHeight; | ||
750 | } | ||
751 | return {top: vp.y, left: vp.x, width: w, height: h}; | ||
752 | }, | ||
753 | |||
754 | /** @id MochiKit.DragAndDrop.repr */ | ||
755 | repr: function () { | ||
756 | return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]"; | ||
757 | } | ||
758 | }; | ||
759 | |||
760 | MochiKit.DragAndDrop.__new__ = function () { | ||
761 | MochiKit.Base.nameFunctions(this); | ||
762 | }; | ||
763 | |||
764 | MochiKit.DragAndDrop.__new__(); | ||
765 | |||
766 | MochiKit.Base._exportSymbols(this, MochiKit.DragAndDrop); | ||