You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.2 KiB
132 lines
4.2 KiB
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; |
|
} |
|
}); |
|
|
|
});
|
|
|