dd-drag.js revision 8a6b21bbf4ce4b186b37c9f3623a198acd13b950
4a14ce5ba00ab7bc55c99ffdcf59c7a4ab902721Automatic Updater * Provides the ability to drag a Node.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @module dd
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @submodule dd-drag
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * Provides the ability to drag a Node.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @class Drag
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @extends Base
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @constructor
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @namespace DD
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:mouseup
0c6ada0a814f3c5417daa1654129bc2af56ed504Automatic Updater * @description Handles the mouseup DOM event, does nothing internally just fires.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:mouseDown
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @preventable _defMouseDownFn
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
0c6ada0a814f3c5417daa1654129bc2af56ed504Automatic Updater * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:afterMouseDown
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires after the mousedown event has been cleared.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:removeHandle
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires after a handle is removed.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl>
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:addHandle
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires after a handle is added.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
c247e3f281613fabe1af362e9f3157e35ebbe52cMark Andrews * @event drag:removeInvalid
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * @description Fires after an invalid selector is removed.
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * @param {EventFacade} event An Event Facade object with the following specific property added:
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl>
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:addInvalid
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires after an invalid selector is added.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:start
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires at the start of a drag operation.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageX</dt><dd>The original node position X.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageY</dt><dd>The original node position Y.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>startTime</dt><dd>The startTime of the event. getTime on the current Date object.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:end
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires at the end of a drag operation.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageX</dt><dd>The current node position X.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageY</dt><dd>The current node position Y.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>startTime</dt><dd>The startTime of the event, from the start event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>endTime</dt><dd>The endTime of the event. getTime on the current Date object.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:drag
1224c3b69b3d18f7127aa042644936af25a2d679Mark Andrews * @description Fires every mousemove during a drag operation.
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * <dt>pageX</dt><dd>The current node position X.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageY</dt><dd>The current node position Y.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>scroll</dt><dd>Should a scroll action occur.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>info</dt><dd>Object hash containing calculated XY arrays: start, xy, delta, offset</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:align
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @preventable _defAlignFn
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires when this node is aligned.
c247e3f281613fabe1af362e9f3157e35ebbe52cMark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
c247e3f281613fabe1af362e9f3157e35ebbe52cMark Andrews * <dt>pageX</dt><dd>The current node position X.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageY</dt><dd>The current node position Y.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:over
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires when this node is over a Drop Target. (Fired from dd-drop)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:enter
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires when this node enters a Drop Target. (Fired from dd-drop)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:exit
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires when this node exits a Drop Target. (Fired from dd-drop)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:drophit
1d216bfaa764f2b40c57cf61987453c5a6fa9b0aMark Andrews * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drop</dt><dd>The best guess on what was dropped on.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>others</dt><dd>An array of all the other drop targets that was dropped on.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @bubbles DDM
b2f07642fd712c8fda81a116bcdde229ab291f33Tinderbox User * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @event drag:dropmiss
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @param {EventFacade} event An Event Facade object with the following specific property added:
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageX</dt><dd>The current node position X.</dd>
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * <dt>pageY</dt><dd>The current node position Y.</dd>
0c6ada0a814f3c5417daa1654129bc2af56ed504Automatic Updater * @bubbles DDM
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews * @type {CustomEvent}
5a4557e8de2951a2796676b5ec4b6a90caa5be14Mark Andrews Drag = function(o) {
4abdfc917e6635a7c81d1f931a0c79227e72d025Mark Andrews Drag.superclass.constructor.apply(this, arguments);
4abdfc917e6635a7c81d1f931a0c79227e72d025Mark Andrews Y.error('Failed to register node, already in use: ' + o.node);
* This property defaults to "mousedown", but when drag-gestures is loaded, it is changed to "gesturemovestart"
node: {
return node;
dragNode: {
return node;
offsetNode: {
value: true
value: false
* @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
lock: {
value: false,
if (lock) {
return lock;
* @description A payload holder to store arbitrary data about this drag object, can be used to store any value.
data: {
value: false
* @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
move: {
value: true
* @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
useShim: {
value: true
* @description This config option is set by Drag to inform you of which handle fired the drag event (in the case that there are several handles): default false.
activeHandle: {
value: false
* @description By default a drag operation will only begin if the mousedown occurred with the primary mouse button. Setting this to false will allow for all mousedown events to trigger a drag.
value: true
* @description This attribute is not meant to be used by the implementor, it is meant to be used as an Event tracker so you can listen for it to change.
dragging: {
value: false
parent: {
value: false
* @description This attribute only works if the dd-drop module has been loaded. It will make this node a drop target as well as draggable.
target: {
value: false,
return config;
* @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
dragMode: {
value: null,
groups: {
getter: function() {
if (!this._groups) {
this._groups = {};
var ret = [];
return ret;
setter: function(g) {
this._groups = {};
Y.each(g, function(v, k) {
this._groups[v] = true;
* @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
handles: {
value: null,
setter: function(g) {
this._handles = {};
Y.each(g, function(v, k) {
var key = v;
this._handles = null;
* @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling. Use bubbleTargets in config
bubbles: {
setter: function(t) {
this.addTarget(t);
haltDown: {
value: true
_canDrag: function(n) {
* @description Add this Drag instance to a group, this should be used for on-the-fly group additions.
addToGroup: function(g) {
this._groups[g] = true;
* @description Remove this Drag instance from a group, this should be used for on-the-fly group removals.
removeFromGroup: function(g) {
delete this._groups[g];
* @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
target: null,
if (config === false) {
if (this.target) {
this.target = null;
config = {};
config.bubbleTargets = ('bubbleTargets' in config) ? config.bubbleTargets : Y.Object.values(this._yuievt.targets);
_groups: null,
* @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
_createEvents: function() {
queuable: false,
emitFacade: true,
bubbles: true,
queuable: false,
emitFacade: true,
bubbles: true,
queuable: false,
emitFacade: true,
bubbles: true,
queuable: false,
emitFacade: true,
bubbles: true,
var ev = [
this.publish(v, {
type: v,
emitFacade: true,
bubbles: true,
preventable: false,
queuable: false,
_ev_md: null,
* @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
_startTime: null,
* @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
_endTime: null,
_handles: null,
_invalids: null,
* @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
_dragThreshMet: null,
_fromTimeout: null,
_clickTimeout: null,
deltaXY: null,
startXY: null,
nodeXY: null,
lastXY: null,
* @description The xy that the node will be set to. Changing this will alter the position as it's dragged.
actXY: null,
realXY: null,
mouseXY: null,
region: null,
this._fixIEMouseUp();
* @description The function we use as the ondragstart handler when we start a drag in Internet Explorer. This keeps IE from blowing up on images as drag handles.
_fixDragStart: function(e) {
e.preventDefault();
* @description The function we use as the onselectstart handler when we start a drag in Internet Explorer
_ieSelectFix: function() {
* @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
_ieSelectBack: null,
* @description This method copies the onselectstart listner on the document to the _ieSelectFix property
_fixIEMouseDown: function(e) {
* @description This method copies the _ieSelectFix property back to the onselectstart listner on the document.
_fixIEMouseUp: function() {
_defMouseDownFn: function(e) {
this._dragThreshMet = false;
* @description Method first checks to see if we have handles, if so it validates the click against the handle. Then if it finds a valid handle, it checks it against the invalid handles list. Returns true if a good handle was used, false otherwise.
hTest = null,
els = null,
nlist = null,
set = false;
if (this._handles) {
nlist = i;
hTest = n;
if (this._invalids) {
if (hTest) {
set = false;
set = true;
_timeoutCheck: function() {
this.start();
* @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
if (!this._handles) {
this._handles = {};
* @description Add a selector string to test the handle against. If the test passes the drag operation will not continue.
this.actXY = [];
this._createEvents();
_prep: function() {
this._dragThreshMet = false;
_unprep: function() {
start: function() {
this.region = {
end: function() {
if (this._clickTimeout) {
_defEndFn: function(e) {
this._fixIEMouseUp();
this._ev_md = null;
* @description Handler for preventing the drag:end event. It will reset the node back to it's start position
_prevEndFn: function(e) {
this._fixIEMouseUp();
this._ev_md = null;
this.region = null;
_defAlignFn: function(e) {
this._moveNode();
this.region = {
info: {
_defDragFn: function(e) {
if (e.scroll) {
if (!this._dragThreshMet) {
this._dragThreshMet = true;
this.start();
if (this._clickTimeout) {
* @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
stopDrag: function() {
destructor: function() {
this._unprep();
this.detachAll();
if (this.target) {