-
Notifications
You must be signed in to change notification settings - Fork 0
/
Mover.js
132 lines (120 loc) · 4.21 KB
/
Mover.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
define([
"../_base/array", "../_base/declare", "../_base/lang", "../sniff", "../_base/window",
"../dom", "../dom-geometry", "../dom-style", "../Evented", "../on", "../touch", "./common", "./autoscroll"
], function(array, declare, lang, has, win, dom, domGeom, domStyle, Evented, on, touch, dnd, autoscroll){
// module:
// dojo/dnd/Mover
return declare("dojo.dnd.Mover", [Evented], {
// summary:
// an object which makes a node follow the mouse, or touch-drag on touch devices.
// Used as a default mover, and as a base class for custom movers.
constructor: function(node, e, host){
// node: Node
// a node (or node's id) to be moved
// e: Event
// a mouse event, which started the move;
// only pageX and pageY properties are used
// host: Object?
// object which implements the functionality of the move,
// and defines proper events (onMoveStart and onMoveStop)
this.node = dom.byId(node);
this.marginBox = {l: e.pageX, t: e.pageY};
this.mouseButton = e.button;
var h = (this.host = host), d = node.ownerDocument;
function stopEvent(e){
e.preventDefault();
e.stopPropagation();
}
this.events = [
// At the start of a drag, onFirstMove is called, and then the following
// listener is disconnected.
on(d, touch.move, lang.hitch(this, "onFirstMove")),
// These are called continually during the drag
on(d, touch.move, lang.hitch(this, "onMouseMove")),
// And these are called at the end of the drag
on(d, touch.release, lang.hitch(this, "onMouseUp")),
// cancel text selection and text dragging
on(d, "dragstart", stopEvent),
on(d.body, "selectstart", stopEvent)
];
// Tell autoscroll that a drag is starting
autoscroll.autoScrollStart(d);
// notify that the move has started
if(h && h.onMoveStart){
h.onMoveStart(this);
}
},
// mouse event processors
onMouseMove: function(e){
// summary:
// event processor for onmousemove/ontouchmove
// e: Event
// mouse/touch event
autoscroll.autoScroll(e);
var m = this.marginBox;
this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
e.preventDefault();
e.stopPropagation();
},
onMouseUp: function(e){
if(has("webkit") && has("mac") && this.mouseButton == 2 ?
e.button == 0 : this.mouseButton == e.button){ // TODO Should condition be met for touch devices, too?
this.destroy();
}
e.preventDefault();
e.stopPropagation();
},
// utilities
onFirstMove: function(e){
// summary:
// makes the node absolute; it is meant to be called only once.
// relative and absolutely positioned nodes are assumed to use pixel units
var s = this.node.style, l, t, h = this.host;
switch(s.position){
case "relative":
case "absolute":
// assume that left and top values are in pixels already
l = Math.round(parseFloat(s.left)) || 0;
t = Math.round(parseFloat(s.top)) || 0;
break;
default:
s.position = "absolute"; // enforcing the absolute mode
var m = domGeom.getMarginBox(this.node);
// event.pageX/pageY (which we used to generate the initial
// margin box) includes padding and margin set on the body.
// However, setting the node's position to absolute and then
// doing domGeom.marginBox on it *doesn't* take that additional
// space into account - so we need to subtract the combined
// padding and margin. We use getComputedStyle and
// _getMarginBox/_getContentBox to avoid the extra lookup of
// the computed style.
var b = win.doc.body;
var bs = domStyle.getComputedStyle(b);
var bm = domGeom.getMarginBox(b, bs);
var bc = domGeom.getContentBox(b, bs);
l = m.l - (bc.l - bm.l);
t = m.t - (bc.t - bm.t);
break;
}
this.marginBox.l = l - this.marginBox.l;
this.marginBox.t = t - this.marginBox.t;
if(h && h.onFirstMove){
h.onFirstMove(this, e);
}
// Disconnect touch.move that call this function
this.events.shift().remove();
},
destroy: function(){
// summary:
// stops the move, deletes all references, so the object can be garbage-collected
array.forEach(this.events, function(handle){ handle.remove(); });
// undo global settings
var h = this.host;
if(h && h.onMoveStop){
h.onMoveStop(this);
}
// destroy objects
this.events = this.node = this.host = null;
}
});
});