UNPKG

dojo

Version:

Dojo core is a powerful, lightweight library that makes common tasks quicker and easier. Animate elements, manipulate the DOM, and query with easy CSS syntax, all without sacrificing performance.

133 lines (120 loc) 4.31 kB
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; } }); });