2 MochiKit.DragAndDrop 1.4
4 See <http://mochikit.com/> for documentation, downloads, license, etc.
6 Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
7 Mochi-ized By Thomas Herve (_firstname_@nimail.org)
11 if (typeof(dojo
) != 'undefined') {
12 dojo
.provide('MochiKit.DragAndDrop');
13 dojo
.require('MochiKit.Base');
14 dojo
.require('MochiKit.DOM');
15 dojo
.require('MochiKit.Iter');
16 dojo
.require('MochiKit.Visual');
17 dojo
.require('MochiKit.Signal');
20 if (typeof(JSAN
) != 'undefined') {
21 JSAN
.use("MochiKit.Base", []);
22 JSAN
.use("MochiKit.DOM", []);
23 JSAN
.use("MochiKit.Visual", []);
24 JSAN
.use("MochiKit.Iter", []);
25 JSAN
.use("MochiKit.Signal", []);
29 if (typeof(MochiKit
.Base
) == 'undefined' ||
30 typeof(MochiKit
.DOM
) == 'undefined' ||
31 typeof(MochiKit
.Visual
) == 'undefined' ||
32 typeof(MochiKit
.Signal
) == 'undefined' ||
33 typeof(MochiKit
.Iter
) == 'undefined') {
37 throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM, MochiKit.Visual, MochiKit.Signal and MochiKit.Iter!";
40 if (typeof(MochiKit
.DragAndDrop
) == 'undefined') {
41 MochiKit
.DragAndDrop
= {};
44 MochiKit
.DragAndDrop
.NAME
= 'MochiKit.DragAndDrop';
45 MochiKit
.DragAndDrop
.VERSION
= '1.4';
47 MochiKit
.DragAndDrop
.__repr__ = function () {
48 return '[' + this.NAME
+ ' ' + this.VERSION
+ ']';
51 MochiKit
.DragAndDrop
.toString = function () {
52 return this.__repr__();
55 MochiKit
.DragAndDrop
.EXPORT
= [
60 MochiKit
.DragAndDrop
.EXPORT_OK
= [
65 MochiKit
.DragAndDrop
.Droppables
= {
68 Manage all droppables. Shouldn't be used, use the Droppable object instead.
73 remove: function (element
) {
74 this.drops
= MochiKit
.Base
.filter(function (d
) {
75 return d
.element
!= MochiKit
.DOM
.getElement(element
);
79 register: function (drop
) {
80 this.drops
.push(drop
);
83 unregister: function (drop
) {
84 this.drops
= MochiKit
.Base
.filter(function (d
) {
89 prepare: function (element
) {
90 MochiKit
.Base
.map(function (drop
) {
91 if (drop
.isAccepted(element
)) {
92 if (drop
.options
.activeclass
) {
93 MochiKit
.DOM
.addElementClass(drop
.element
,
94 drop
.options
.activeclass
);
96 drop
.options
.onactive(drop
.element
, element
);
101 findDeepestChild: function (drops
) {
104 for (i
= 1; i
< drops
.length
; ++i
) {
105 if (MochiKit
.DOM
.isParent(drops
[i
].element
, deepest
.element
)) {
112 show: function (point
, element
) {
113 if (!this.drops
.length
) {
118 if (this.last_active
) {
119 this.last_active
.deactivate();
121 MochiKit
.Iter
.forEach(this.drops
, function (drop
) {
122 if (drop
.isAffected(point
, element
)) {
126 if (affected
.length
> 0) {
127 drop
= this.findDeepestChild(affected
);
128 MochiKit
.Position
.within(drop
.element
, point
.page
.x
, point
.page
.y
);
129 drop
.options
.onhover(element
, drop
.element
,
130 MochiKit
.Position
.overlap(drop
.options
.overlap
, drop
.element
));
135 fire: function (event
, element
) {
136 if (!this.last_active
) {
139 MochiKit
.Position
.prepare();
141 if (this.last_active
.isAffected(event
.mouse(), element
)) {
142 this.last_active
.options
.ondrop(element
,
143 this.last_active
.element
, event
);
147 reset: function (element
) {
148 MochiKit
.Base
.map(function (drop
) {
149 if (drop
.options
.activeclass
) {
150 MochiKit
.DOM
.removeElementClass(drop
.element
,
151 drop
.options
.activeclass
);
153 drop
.options
.ondesactive(drop
.element
, element
);
155 if (this.last_active
) {
156 this.last_active
.deactivate();
161 /** @id MochiKit.DragAndDrop.Droppable */
162 MochiKit
.DragAndDrop
.Droppable = function (element
, options
) {
163 var cls
= arguments
.callee
;
164 if (!(this instanceof cls
)) {
165 return new cls(element
, options
);
167 this.__init__(element
, options
);
170 MochiKit
.DragAndDrop
.Droppable
.prototype = {
173 A droppable object. Simple use is to create giving an element:
175 new MochiKit.DragAndDrop.Droppable('myelement');
177 Generally you'll want to define the 'ondrop' function and maybe the
178 'accept' option to filter draggables.
181 __class__
: MochiKit
.DragAndDrop
.Droppable
,
183 __init__: function (element
, /* optional */options
) {
184 var d
= MochiKit
.DOM
;
185 var b
= MochiKit
.Base
;
186 this.element
= d
.getElement(element
);
187 this.options
= b
.update({
189 /** @id MochiKit.DragAndDrop.greedy */
192 /** @id MochiKit.DragAndDrop.hoverclass */
195 /** @id MochiKit.DragAndDrop.activeclass */
198 /** @id MochiKit.DragAndDrop.hoverfunc */
201 /** @id MochiKit.DragAndDrop.accept */
204 /** @id MochiKit.DragAndDrop.onactive */
207 /** @id MochiKit.DragAndDrop.ondesactive */
210 /** @id MochiKit.DragAndDrop.onhover */
213 /** @id MochiKit.DragAndDrop.ondrop */
216 /** @id MochiKit.DragAndDrop.containment */
222 this.options
._containers
= [];
223 b
.map(MochiKit
.Base
.bind(function (c
) {
224 this.options
._containers
.push(d
.getElement(c
));
225 }, this), this.options
.containment
);
227 d
.makePositioned(this.element
); // fix IE
229 MochiKit
.DragAndDrop
.Droppables
.register(this);
232 /** @id MochiKit.DragAndDrop.isContained */
233 isContained: function (element
) {
234 if (this.options
._containers
.length
) {
236 if (this.options
.tree
) {
237 containmentNode
= element
.treeNode
;
239 containmentNode
= element
.parentNode
;
241 return MochiKit
.Iter
.some(this.options
._containers
, function (c
) {
242 return containmentNode
== c
;
249 /** @id MochiKit.DragAndDrop.isAccepted */
250 isAccepted: function (element
) {
251 return ((!this.options
.accept
) || MochiKit
.Iter
.some(
252 this.options
.accept
, function (c
) {
253 return MochiKit
.DOM
.hasElementClass(element
, c
);
257 /** @id MochiKit.DragAndDrop.isAffected */
258 isAffected: function (point
, element
) {
259 return ((this.element
!= element
) &&
260 this.isContained(element
) &&
261 this.isAccepted(element
) &&
262 MochiKit
.Position
.within(this.element
, point
.page
.x
,
266 /** @id MochiKit.DragAndDrop.deactivate */
267 deactivate: function () {
270 A droppable is deactivate when a draggable has been over it and left.
273 if (this.options
.hoverclass
) {
274 MochiKit
.DOM
.removeElementClass(this.element
,
275 this.options
.hoverclass
);
277 this.options
.hoverfunc(this.element
, false);
278 MochiKit
.DragAndDrop
.Droppables
.last_active
= null;
281 /** @id MochiKit.DragAndDrop.activate */
282 activate: function () {
285 A droppable is active when a draggable is over it.
288 if (this.options
.hoverclass
) {
289 MochiKit
.DOM
.addElementClass(this.element
, this.options
.hoverclass
);
291 this.options
.hoverfunc(this.element
, true);
292 MochiKit
.DragAndDrop
.Droppables
.last_active
= this;
295 /** @id MochiKit.DragAndDrop.destroy */
296 destroy: function () {
299 Delete this droppable.
302 MochiKit
.DragAndDrop
.Droppables
.unregister(this);
305 /** @id MochiKit.DragAndDrop.repr */
307 return '[' + this.__class__
.NAME
+ ", options:" + MochiKit
.Base
.repr(this.options
) + "]";
311 MochiKit
.DragAndDrop
.Draggables
= {
314 Manage draggables elements. Not intended to direct use.
319 register: function (draggable
) {
320 if (this.drags
.length
=== 0) {
321 var conn
= MochiKit
.Signal
.connect
;
322 this.eventMouseUp
= conn(document
, 'onmouseup', this, this.endDrag
);
323 this.eventMouseMove
= conn(document
, 'onmousemove', this,
325 this.eventKeypress
= conn(document
, 'onkeypress', this,
328 this.drags
.push(draggable
);
331 unregister: function (draggable
) {
332 this.drags
= MochiKit
.Base
.filter(function (d
) {
333 return d
!= draggable
;
335 if (this.drags
.length
=== 0) {
336 var disc
= MochiKit
.Signal
.disconnect
;
337 disc(this.eventMouseUp
);
338 disc(this.eventMouseMove
);
339 disc(this.eventKeypress
);
343 activate: function (draggable
) {
344 // allows keypress events if window is not currently focused
347 this.activeDraggable
= draggable
;
350 deactivate: function () {
351 this.activeDraggable
= null;
354 updateDrag: function (event
) {
355 if (!this.activeDraggable
) {
358 var pointer
= event
.mouse();
359 // Mozilla-based browsers fire successive mousemove events with
360 // the same coordinates, prevent needless redrawing (moz bug?)
361 if (this._lastPointer
&& (MochiKit
.Base
.repr(this._lastPointer
.page
) ==
362 MochiKit
.Base
.repr(pointer
.page
))) {
365 this._lastPointer
= pointer
;
366 this.activeDraggable
.updateDrag(event
, pointer
);
369 endDrag: function (event
) {
370 if (!this.activeDraggable
) {
373 this._lastPointer
= null;
374 this.activeDraggable
.endDrag(event
);
375 this.activeDraggable
= null;
378 keyPress: function (event
) {
379 if (this.activeDraggable
) {
380 this.activeDraggable
.keyPress(event
);
384 notify: function (eventName
, draggable
, event
) {
385 MochiKit
.Signal
.signal(this, eventName
, draggable
, event
);
389 /** @id MochiKit.DragAndDrop.Draggable */
390 MochiKit
.DragAndDrop
.Draggable = function (element
, options
) {
391 var cls
= arguments
.callee
;
392 if (!(this instanceof cls
)) {
393 return new cls(element
, options
);
395 this.__init__(element
, options
);
398 MochiKit
.DragAndDrop
.Draggable
.prototype = {
401 A draggable object. Simple instantiate :
403 new MochiKit.DragAndDrop.Draggable('myelement');
406 __class__
: MochiKit
.DragAndDrop
.Draggable
,
408 __init__: function (element
, /* optional */options
) {
409 var v
= MochiKit
.Visual
;
410 var b
= MochiKit
.Base
;
413 /** @id MochiKit.DragAndDrop.handle */
416 /** @id MochiKit.DragAndDrop.starteffect */
417 starteffect: function (innerelement
) {
418 this._savedOpacity
= MochiKit
.Style
.getStyle(innerelement
, 'opacity') || 1.0;
419 new v
.Opacity(innerelement
, {duration
:0.2, from:this._savedOpacity
, to
:0.7});
421 /** @id MochiKit.DragAndDrop.reverteffect */
422 reverteffect: function (innerelement
, top_offset
, left_offset
) {
423 var dur
= Math
.sqrt(Math
.abs(top_offset
^2) +
424 Math
.abs(left_offset
^2))*0.02;
425 return new v
.Move(innerelement
,
426 {x
: -left_offset
, y
: -top_offset
, duration
: dur
});
429 /** @id MochiKit.DragAndDrop.endeffect */
430 endeffect: function (innerelement
) {
431 new v
.Opacity(innerelement
, {duration
:0.2, from:0.7, to
:this._savedOpacity
});
434 /** @id MochiKit.DragAndDrop.onchange */
437 /** @id MochiKit.DragAndDrop.zindex */
440 /** @id MochiKit.DragAndDrop.revert */
443 /** @id MochiKit.DragAndDrop.scroll */
446 /** @id MochiKit.DragAndDrop.scrollSensitivity */
447 scrollSensitivity
: 20,
449 /** @id MochiKit.DragAndDrop.scrollSpeed */
451 // false, or xy or [x, y] or function (x, y){return [x, y];}
453 /** @id MochiKit.DragAndDrop.snap */
457 var d
= MochiKit
.DOM
;
458 this.element
= d
.getElement(element
);
460 if (options
.handle
&& (typeof(options
.handle
) == 'string')) {
461 this.handle
= d
.getFirstElementByTagAndClassName(null,
462 options
.handle
, this.element
);
465 this.handle
= d
.getElement(options
.handle
);
468 this.handle
= this.element
;
471 if (options
.scroll
&& !options
.scroll
.scrollTo
&& !options
.scroll
.outerHTML
) {
472 options
.scroll
= d
.getElement(options
.scroll
);
473 this._isScrollChild
= MochiKit
.DOM
.isChildNode(this.element
, options
.scroll
);
476 d
.makePositioned(this.element
); // fix IE
478 this.delta
= this.currentDelta();
479 this.options
= options
;
480 this.dragging
= false;
482 this.eventMouseDown
= MochiKit
.Signal
.connect(this.handle
,
483 'onmousedown', this, this.initDrag
);
484 MochiKit
.DragAndDrop
.Draggables
.register(this);
487 /** @id MochiKit.DragAndDrop.destroy */
488 destroy: function () {
489 MochiKit
.Signal
.disconnect(this.eventMouseDown
);
490 MochiKit
.DragAndDrop
.Draggables
.unregister(this);
493 /** @id MochiKit.DragAndDrop.currentDelta */
494 currentDelta: function () {
495 var s
= MochiKit
.Style
.getStyle
;
497 parseInt(s(this.element
, 'left') || '0'),
498 parseInt(s(this.element
, 'top') || '0')];
501 /** @id MochiKit.DragAndDrop.initDrag */
502 initDrag: function (event
) {
503 if (!event
.mouse().button
.left
) {
506 // abort on form elements, fixes a Firefox issue
507 var src
= event
.target();
508 var tagName
= (src
.tagName
|| '').toUpperCase();
509 if (tagName
=== 'INPUT' || tagName
=== 'SELECT' ||
510 tagName
=== 'OPTION' || tagName
=== 'BUTTON' ||
511 tagName
=== 'TEXTAREA') {
516 this._revert
.cancel();
520 var pointer
= event
.mouse();
521 var pos
= MochiKit
.Position
.cumulativeOffset(this.element
);
522 this.offset
= [pointer
.page
.x
- pos
.x
, pointer
.page
.y
- pos
.y
];
524 MochiKit
.DragAndDrop
.Draggables
.activate(this);
528 /** @id MochiKit.DragAndDrop.startDrag */
529 startDrag: function (event
) {
530 this.dragging
= true;
531 if (this.options
.selectclass
) {
532 MochiKit
.DOM
.addElementClass(this.element
,
533 this.options
.selectclass
);
535 if (this.options
.zindex
) {
536 this.originalZ
= parseInt(MochiKit
.Style
.getStyle(this.element
,
538 this.element
.style
.zIndex
= this.options
.zindex
;
541 if (this.options
.ghosting
) {
542 this._clone
= this.element
.cloneNode(true);
543 this.ghostPosition
= MochiKit
.Position
.absolutize(this.element
);
544 this.element
.parentNode
.insertBefore(this._clone
, this.element
);
547 if (this.options
.scroll
) {
548 if (this.options
.scroll
== window
) {
549 var where
= this._getWindowScroll(this.options
.scroll
);
550 this.originalScrollLeft
= where
.left
;
551 this.originalScrollTop
= where
.top
;
553 this.originalScrollLeft
= this.options
.scroll
.scrollLeft
;
554 this.originalScrollTop
= this.options
.scroll
.scrollTop
;
558 MochiKit
.DragAndDrop
.Droppables
.prepare(this.element
);
559 MochiKit
.DragAndDrop
.Draggables
.notify('start', this, event
);
560 if (this.options
.starteffect
) {
561 this.options
.starteffect(this.element
);
565 /** @id MochiKit.DragAndDrop.updateDrag */
566 updateDrag: function (event
, pointer
) {
567 if (!this.dragging
) {
568 this.startDrag(event
);
570 MochiKit
.Position
.prepare();
571 MochiKit
.DragAndDrop
.Droppables
.show(pointer
, this.element
);
572 MochiKit
.DragAndDrop
.Draggables
.notify('drag', this, event
);
574 this.options
.onchange(this);
576 if (this.options
.scroll
) {
577 this.stopScrolling();
579 if (this.options
.scroll
== window
) {
580 var s
= this._getWindowScroll(this.options
.scroll
);
581 p
= new MochiKit
.Style
.Coordinates(s
.left
, s
.top
);
582 q
= new MochiKit
.Style
.Coordinates(s
.left
+ s
.width
,
585 p
= MochiKit
.Position
.page(this.options
.scroll
);
586 p
.x
+= this.options
.scroll
.scrollLeft
;
587 p
.y
+= this.options
.scroll
.scrollTop
;
588 p
.x
+= (window
.pageXOffset
|| document
.documentElement
.scrollLeft
|| document
.body
.scrollLeft
|| 0);
589 p
.y
+= (window
.pageYOffset
|| document
.documentElement
.scrollTop
|| document
.body
.scrollTop
|| 0);
590 q
= new MochiKit
.Style
.Coordinates(p
.x
+ this.options
.scroll
.offsetWidth
,
591 p
.y
+ this.options
.scroll
.offsetHeight
);
594 if (pointer
.page
.x
> (q
.x
- this.options
.scrollSensitivity
)) {
595 speed
[0] = pointer
.page
.x
- (q
.x
- this.options
.scrollSensitivity
);
596 } else if (pointer
.page
.x
< (p
.x
+ this.options
.scrollSensitivity
)) {
597 speed
[0] = pointer
.page
.x
- (p
.x
+ this.options
.scrollSensitivity
);
599 if (pointer
.page
.y
> (q
.y
- this.options
.scrollSensitivity
)) {
600 speed
[1] = pointer
.page
.y
- (q
.y
- this.options
.scrollSensitivity
);
601 } else if (pointer
.page
.y
< (p
.y
+ this.options
.scrollSensitivity
)) {
602 speed
[1] = pointer
.page
.y
- (p
.y
+ this.options
.scrollSensitivity
);
604 this.startScrolling(speed
);
607 // fix AppleWebKit rendering
608 if (/AppleWebKit'/.test(navigator
.appVersion
)) {
609 window
.scrollBy(0, 0);
614 /** @id MochiKit.DragAndDrop.finishDrag */
615 finishDrag: function (event
, success
) {
616 var dr
= MochiKit
.DragAndDrop
;
617 this.dragging
= false;
618 if (this.options
.selectclass
) {
619 MochiKit
.DOM
.removeElementClass(this.element
,
620 this.options
.selectclass
);
623 if (this.options
.ghosting
) {
624 // XXX: from a user point of view, it would be better to remove
625 // the node only *after* the MochiKit.Visual.Move end when used
627 MochiKit
.Position
.relativize(this.element
, this.ghostPosition
);
628 MochiKit
.DOM
.removeElement(this._clone
);
633 dr
.Droppables
.fire(event
, this.element
);
635 dr
.Draggables
.notify('end', this, event
);
637 var revert
= this.options
.revert
;
638 if (revert
&& typeof(revert
) == 'function') {
639 revert
= revert(this.element
);
642 var d
= this.currentDelta();
643 if (revert
&& this.options
.reverteffect
) {
644 this._revert
= this.options
.reverteffect(this.element
,
645 d
[1] - this.delta
[1], d
[0] - this.delta
[0]);
650 if (this.options
.zindex
) {
651 this.element
.style
.zIndex
= this.originalZ
;
654 if (this.options
.endeffect
) {
655 this.options
.endeffect(this.element
);
658 dr
.Draggables
.deactivate();
659 dr
.Droppables
.reset(this.element
);
662 /** @id MochiKit.DragAndDrop.keyPress */
663 keyPress: function (event
) {
664 if (event
.key().string
!= "KEY_ESCAPE") {
667 this.finishDrag(event
, false);
671 /** @id MochiKit.DragAndDrop.endDrag */
672 endDrag: function (event
) {
673 if (!this.dragging
) {
676 this.stopScrolling();
677 this.finishDrag(event
, true);
681 /** @id MochiKit.DragAndDrop.draw */
682 draw: function (point
) {
683 var pos
= MochiKit
.Position
.cumulativeOffset(this.element
);
684 var d
= this.currentDelta();
688 if (this.options
.scroll
&& (this.options
.scroll
!= window
&& this._isScrollChild
)) {
689 pos
.x
-= this.options
.scroll
.scrollLeft
- this.originalScrollLeft
;
690 pos
.y
-= this.options
.scroll
.scrollTop
- this.originalScrollTop
;
693 var p
= [point
.page
.x
- pos
.x
- this.offset
[0],
694 point
.page
.y
- pos
.y
- this.offset
[1]];
696 if (this.options
.snap
) {
697 if (typeof(this.options
.snap
) == 'function') {
698 p
= this.options
.snap(p
[0], p
[1]);
700 if (this.options
.snap
instanceof Array
) {
702 p
= MochiKit
.Base
.map(MochiKit
.Base
.bind(function (v
) {
704 return Math
.round(v
/this.options
.snap
[i
]) *
705 this.options
.snap
[i
];
708 p
= MochiKit
.Base
.map(MochiKit
.Base
.bind(function (v
) {
709 return Math
.round(v
/this.options
.snap
) *
715 var style
= this.element
.style
;
716 if ((!this.options
.constraint
) ||
717 (this.options
.constraint
== 'horizontal')) {
718 style
.left
= p
[0] + 'px';
720 if ((!this.options
.constraint
) ||
721 (this.options
.constraint
== 'vertical')) {
722 style
.top
= p
[1] + 'px';
724 if (style
.visibility
== 'hidden') {
725 style
.visibility
= ''; // fix gecko rendering
729 /** @id MochiKit.DragAndDrop.stopScrolling */
730 stopScrolling: function () {
731 if (this.scrollInterval
) {
732 clearInterval(this.scrollInterval
);
733 this.scrollInterval
= null;
734 MochiKit
.DragAndDrop
.Draggables
._lastScrollPointer
= null;
738 /** @id MochiKit.DragAndDrop.startScrolling */
739 startScrolling: function (speed
) {
740 if (!speed
[0] && !speed
[1]) {
743 this.scrollSpeed
= [speed
[0] * this.options
.scrollSpeed
,
744 speed
[1] * this.options
.scrollSpeed
];
745 this.lastScrolled
= new Date();
746 this.scrollInterval
= setInterval(MochiKit
.Base
.bind(this.scroll
, this), 10);
749 /** @id MochiKit.DragAndDrop.scroll */
750 scroll: function () {
751 var current
= new Date();
752 var delta
= current
- this.lastScrolled
;
753 this.lastScrolled
= current
;
755 if (this.options
.scroll
== window
) {
756 var s
= this._getWindowScroll(this.options
.scroll
);
757 if (this.scrollSpeed
[0] || this.scrollSpeed
[1]) {
758 var dm
= delta
/ 1000;
759 this.options
.scroll
.scrollTo(s
.left
+ dm
* this.scrollSpeed
[0],
760 s
.top
+ dm
* this.scrollSpeed
[1]);
763 this.options
.scroll
.scrollLeft
+= this.scrollSpeed
[0] * delta
/ 1000;
764 this.options
.scroll
.scrollTop
+= this.scrollSpeed
[1] * delta
/ 1000;
767 var d
= MochiKit
.DragAndDrop
;
769 MochiKit
.Position
.prepare();
770 d
.Droppables
.show(d
.Draggables
._lastPointer
, this.element
);
771 d
.Draggables
.notify('drag', this);
772 if (this._isScrollChild
) {
773 d
.Draggables
._lastScrollPointer
= d
.Draggables
._lastScrollPointer
|| d
.Draggables
._lastPointer
;
774 d
.Draggables
._lastScrollPointer
.x
+= this.scrollSpeed
[0] * delta
/ 1000;
775 d
.Draggables
._lastScrollPointer
.y
+= this.scrollSpeed
[1] * delta
/ 1000;
776 if (d
.Draggables
._lastScrollPointer
.x
< 0) {
777 d
.Draggables
._lastScrollPointer
.x
= 0;
779 if (d
.Draggables
._lastScrollPointer
.y
< 0) {
780 d
.Draggables
._lastScrollPointer
.y
= 0;
782 this.draw(d
.Draggables
._lastScrollPointer
);
785 this.options
.onchange(this);
788 _getWindowScroll: function (win
) {
790 MochiKit
.DOM
.withWindow(win
, function () {
791 vp
= MochiKit
.Style
.getViewportPosition(win
.document
);
793 if (win
.innerWidth
) {
796 } else if (win
.document
.documentElement
&& win
.document
.documentElement
.clientWidth
) {
797 w
= win
.document
.documentElement
.clientWidth
;
798 h
= win
.document
.documentElement
.clientHeight
;
800 w
= win
.document
.body
.offsetWidth
;
801 h
= win
.document
.body
.offsetHeight
;
803 return {top
: vp
.x
, left
: vp
.y
, width
: w
, height
: h
};
806 /** @id MochiKit.DragAndDrop.repr */
808 return '[' + this.__class__
.NAME
+ ", options:" + MochiKit
.Base
.repr(this.options
) + "]";
812 MochiKit
.DragAndDrop
.__new__ = function () {
813 MochiKit
.Base
.nameFunctions(this);
816 ":common": this.EXPORT
,
817 ":all": MochiKit
.Base
.concat(this.EXPORT
, this.EXPORT_OK
)
821 MochiKit
.DragAndDrop
.__new__();
823 MochiKit
.Base
._exportSymbols(this, MochiKit
.DragAndDrop
);