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