254 lines
8.6 KiB
JavaScript
254 lines
8.6 KiB
JavaScript
/** @module dojo/dnd/Manager **/
|
|
define([
|
|
"../_base/array",
|
|
"../_base/declare",
|
|
"../_base/lang",
|
|
"../_base/window",
|
|
"../dom-class",
|
|
"../Evented",
|
|
"../has",
|
|
"../keys",
|
|
"../on",
|
|
"../topic",
|
|
"../touch",
|
|
"./common",
|
|
"./autoscroll",
|
|
"./Avatar",
|
|
"xide/mixins/EventedMixin",
|
|
"xide/lodash",
|
|
"xide/types/Types"
|
|
], function (array, declare, lang, win, domClass, Evented, has, keys, on, topic, touch, dnd, autoscroll, Avatar,EventedMixin,_,types) {
|
|
|
|
var EVENTS = types.EVENTS;
|
|
|
|
|
|
function stopEvent(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
/**
|
|
* @class module:dojo/dnd/Manager
|
|
* @extends module:dojo/Evented
|
|
*/
|
|
var Manager = declare("dojo.dnd.Manager", [Evented,EventedMixin], {
|
|
/**
|
|
* @type {module:dojo/dnd/Avatar}
|
|
*/
|
|
avatar:null,
|
|
/**
|
|
* @type {module:dojo/dnd/Source}
|
|
*/
|
|
source:null,
|
|
/**
|
|
* @type {module:dojo/dnd/Target}
|
|
*/
|
|
target:null,
|
|
/**
|
|
* @type {boolean}
|
|
*/
|
|
copy:null,
|
|
constructor: function () {
|
|
this.avatar = null;
|
|
this.source = null;
|
|
this.nodes = [];
|
|
this.copy = true;
|
|
this.target = null;
|
|
this.canDropFlag = false;
|
|
this.events = [];
|
|
},
|
|
// avatar's offset from the mouse
|
|
OFFSET_X: has("touch") ? 0 : 16,
|
|
OFFSET_Y: has("touch") ? -64 : 16,
|
|
/**
|
|
* Called when a source detected a mouse-over condition.
|
|
* @param source {module:dojo/dnd/Source} The reporter.
|
|
*/
|
|
overSource: function (source) {
|
|
if (this.avatar) {
|
|
this.target = (source && source.targetState != "Disabled") ? source : null;
|
|
this.canDropFlag = Boolean(this.target);
|
|
this.avatar.update();
|
|
}
|
|
topic.publish(EVENTS.ON_DND_SOURCE_OVER, source);
|
|
},
|
|
/**
|
|
* Called when a source detected a mouse-out condition.
|
|
* @param source {module:dojo/dnd/Source} The reporter.
|
|
*/
|
|
outSource: function (source) {
|
|
if (this.avatar) {
|
|
if (this.target == source) {
|
|
this.target = null;
|
|
this.canDropFlag = false;
|
|
this.avatar.update();
|
|
topic.publish(EVENTS.ON_DND_SOURCE_OVER, null);
|
|
}
|
|
} else {
|
|
topic.publish(EVENTS.ON_DND_SOURCE_OVER, null);
|
|
}
|
|
},
|
|
/**
|
|
* Called to initiate the DnD operation
|
|
* @param source {module:dojo/dnd/Source} The source which provides items.
|
|
* @param nodes {HTMLElement[]} The list of transferred items.
|
|
* @param copy {boolean} Copy items, if true, move items otherwise.
|
|
*/
|
|
startDrag: function (source, nodes, copy) {
|
|
// Tell autoscroll that a drag is starting
|
|
autoscroll.autoScrollStart(win.doc);
|
|
this.source = source;
|
|
this.nodes = nodes;
|
|
this.copy = Boolean(copy); // normalizing to true boolean
|
|
this.avatar = this.makeAvatar();
|
|
win.body().appendChild(this.avatar.node);
|
|
topic.publish("/dnd/start", source, nodes, this.copy);
|
|
|
|
this.events = [
|
|
on(win.doc, touch.move, lang.hitch(this, "onMouseMove")),
|
|
on(win.doc, touch.release, lang.hitch(this, "onMouseUp")),
|
|
on(win.doc, "keydown", lang.hitch(this, "onKeyDown")),
|
|
on(win.doc, "keyup", lang.hitch(this, "onKeyUp")),
|
|
|
|
// cancel text selection and text dragging
|
|
on(win.doc, "dragstart", stopEvent),
|
|
on(win.body(), "selectstart", stopEvent)
|
|
];
|
|
var c = "dojoDnd" + (copy ? "Copy" : "Move");
|
|
domClass.add(win.body(), c);
|
|
},
|
|
/**
|
|
* Called to notify if the current target can accept items.
|
|
* @param flag {boolean}
|
|
*/
|
|
canDrop: function (flag) {
|
|
var canDropFlag = Boolean(this.target && flag);
|
|
if (this.canDropFlag != canDropFlag) {
|
|
this.canDropFlag = canDropFlag;
|
|
this.avatar.update();
|
|
}
|
|
},
|
|
/**
|
|
* stop the DnD in progress
|
|
*/
|
|
stopDrag: function () {
|
|
domClass.remove(win.body(), ["dojoDndCopy", "dojoDndMove"]);
|
|
_.invoke(this.events,"remove");
|
|
this.events = [];
|
|
this.avatar.destroy();
|
|
this.avatar = null;
|
|
this.source = this.target = null;
|
|
this.nodes = [];
|
|
},
|
|
/**
|
|
* Makes the avatar; it is separate to be overwritten dynamically, if needed.
|
|
* @returns {module:dojo/dnd/Avatar}
|
|
*/
|
|
makeAvatar: function () {
|
|
return new Avatar(this);
|
|
},
|
|
/**
|
|
* Updates the avatar; it is separate to be overwritten dynamically, if needed.
|
|
*/
|
|
updateAvatar: function () {
|
|
this.avatar.update();
|
|
},
|
|
/**
|
|
* Event processor for onmousemove
|
|
* @param e {MouseEvent}
|
|
*/
|
|
onMouseMove: function (e) {
|
|
var a = this.avatar;
|
|
if (a) {
|
|
autoscroll.autoScrollNodes(e);
|
|
//autoscroll.autoScroll(e);
|
|
var s = a.node.style;
|
|
s.left = (e.pageX + this.OFFSET_X) + "px";
|
|
s.top = (e.pageY + this.OFFSET_Y) + "px";
|
|
var copy = Boolean(this.source.copyState(dnd.getCopyKeyState(e)));
|
|
if (this.copy != copy) {
|
|
this._setCopyStatus(copy);
|
|
}
|
|
}
|
|
if (has("touch")) {
|
|
// Prevent page from scrolling so that user can drag instead.
|
|
e.preventDefault();
|
|
}
|
|
},
|
|
/**
|
|
* Event processor for onmouseup
|
|
* @param e {MouseEvent}
|
|
*/
|
|
onMouseUp: function (e) {
|
|
if (this.avatar) {
|
|
if (this.target && this.canDropFlag) {
|
|
var copy = Boolean(this.source.copyState(dnd.getCopyKeyState(e)));
|
|
topic.publish(EVENTS.ON_DND_DROP_BEFORE, this.source, this.nodes, copy, this.target, e);
|
|
topic.publish(EVENTS.ON_DND_DROP, this.source, this.nodes, copy, this.target, e);
|
|
} else {
|
|
topic.publish(EVENTS.ON_DND_CANCEL);
|
|
}
|
|
this.stopDrag();
|
|
}
|
|
},
|
|
/**
|
|
* Event processor for onkeydown watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
|
|
* @param e {MouseEvent}
|
|
*/
|
|
onKeyDown: function (e) {
|
|
if (this.avatar) {
|
|
switch (e.keyCode) {
|
|
case keys.CTRL:
|
|
var copy = Boolean(this.source.copyState(true));
|
|
if (this.copy != copy) {
|
|
this._setCopyStatus(copy);
|
|
}
|
|
break;
|
|
case keys.ESCAPE:
|
|
topic.publish(EVENTS.ON_DND_CANCEL);
|
|
this.stopDrag();
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Event processor for onkeyup, watching for CTRL for copy/move status
|
|
* @param e {KeyboardEvent} keyboard event
|
|
*/
|
|
onKeyUp: function (e) {
|
|
if (this.avatar && e.keyCode == keys.CTRL) {
|
|
var copy = Boolean(this.source.copyState(false));
|
|
if (this.copy != copy) {
|
|
this._setCopyStatus(copy);
|
|
}
|
|
}
|
|
},
|
|
/**
|
|
* Changes the copy status
|
|
* @param copy {boolean} The copy status
|
|
* @private
|
|
*/
|
|
_setCopyStatus: function (copy) {
|
|
this.copy = copy;
|
|
this.source._markDndStatus(this.copy);
|
|
this.updateAvatar();
|
|
domClass.replace(win.body(),
|
|
"dojoDnd" + (this.copy ? "Copy" : "Move"),
|
|
"dojoDnd" + (this.copy ? "Move" : "Copy"));
|
|
}
|
|
});
|
|
|
|
// dnd._manager:
|
|
// The manager singleton variable. Can be overwritten if needed.
|
|
dnd._manager = null;
|
|
Manager.manager = dnd.manager = function () {
|
|
// summary:
|
|
// Returns the current DnD manager. Creates one if it is not created yet.
|
|
if (!dnd._manager) {
|
|
dnd._manager = new Manager();
|
|
}
|
|
return dnd._manager; // Object
|
|
};
|
|
return Manager;
|
|
});
|