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