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