2 Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
8 YUI.add('dd-drag', function(Y) {
12 * Provides the ability to drag a Node.
17 * Provides the ability to drag a Node.
26 DRAGGING = 'dragging',
27 DRAG_NODE = 'dragNode',
28 OFFSET_HEIGHT = 'offsetHeight',
29 OFFSET_WIDTH = 'offsetWidth',
32 * @description Handles the mouseup DOM event, does nothing internally just fires.
34 * @type {Event.Custom}
37 * @event drag:mouseDown
38 * @description Handles the mousedown DOM event, checks to see if you have a valid handle then starts the drag timers.
39 * @preventable _defMouseDownFn
40 * @param {Event.Facade} event An Event Facade object with the following specific property added:
41 * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl>
43 * @type {Event.Custom}
45 EV_MOUSE_DOWN = 'drag:mouseDown',
47 * @event drag:afterMouseDown
48 * @description Fires after the mousedown event has been cleared.
49 * @param {Event.Facade} event An Event Facade object with the following specific property added:
50 * <dl><dt>ev</dt><dd>The original mousedown event.</dd></dl>
52 * @type {Event.Custom}
54 EV_AFTER_MOUSE_DOWN = 'drag:afterMouseDown',
56 * @event drag:removeHandle
57 * @description Fires after a handle is removed.
58 * @param {Event.Facade} event An Event Facade object with the following specific property added:
59 * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl>
61 * @type {Event.Custom}
63 EV_REMOVE_HANDLE = 'drag:removeHandle',
65 * @event drag:addHandle
66 * @description Fires after a handle is added.
67 * @param {Event.Facade} event An Event Facade object with the following specific property added:
68 * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl>
70 * @type {Event.Custom}
72 EV_ADD_HANDLE = 'drag:addHandle',
74 * @event drag:removeInvalid
75 * @description Fires after an invalid selector is removed.
76 * @param {Event.Facade} event An Event Facade object with the following specific property added:
77 * <dl><dt>handle</dt><dd>The handle that was removed.</dd></dl>
79 * @type {Event.Custom}
81 EV_REMOVE_INVALID = 'drag:removeInvalid',
83 * @event drag:addInvalid
84 * @description Fires after an invalid selector is added.
85 * @param {Event.Facade} event An Event Facade object with the following specific property added:
86 * <dl><dt>handle</dt><dd>The handle that was added.</dd></dl>
88 * @type {Event.Custom}
90 EV_ADD_INVALID = 'drag:addInvalid',
93 * @description Fires at the start of a drag operation.
94 * @param {Event.Facade} event An Event Facade object with the following specific property added:
96 * <dt>pageX</dt><dd>The original node position X.</dd>
97 * <dt>pageY</dt><dd>The original node position Y.</dd>
98 * <dt>startTime</dt><dd>The startTime of the event. getTime on the current Date object.</dd>
101 * @type {Event.Custom}
103 EV_START = 'drag:start',
106 * @description Fires at the end of a drag operation.
107 * @param {Event.Facade} event An Event Facade object with the following specific property added:
109 * <dt>pageX</dt><dd>The current node position X.</dd>
110 * <dt>pageY</dt><dd>The current node position Y.</dd>
111 * <dt>startTime</dt><dd>The startTime of the event, from the start event.</dd>
112 * <dt>endTime</dt><dd>The endTime of the event. getTime on the current Date object.</dd>
115 * @type {Event.Custom}
120 * @description Fires every mousemove during a drag operation.
121 * @param {Event.Facade} event An Event Facade object with the following specific property added:
123 * <dt>pageX</dt><dd>The current node position X.</dd>
124 * <dt>pageY</dt><dd>The current node position Y.</dd>
125 * <dt>scroll</dt><dd>Should a scroll action occur.</dd>
126 * <dt>info</dt><dd>Object hash containing calculated XY arrays: start, xy, delta, offset</dd>
129 * @type {Event.Custom}
131 EV_DRAG = 'drag:drag',
134 * @preventable _defAlignFn
135 * @description Fires when this node is aligned.
136 * @param {Event.Facade} event An Event Facade object with the following specific property added:
138 * <dt>pageX</dt><dd>The current node position X.</dd>
139 * <dt>pageY</dt><dd>The current node position Y.</dd>
142 * @type {Event.Custom}
144 EV_ALIGN = 'drag:align',
147 * @description Fires when this node is over a Drop Target. (Fired from dd-drop)
148 * @param {Event.Facade} event An Event Facade object with the following specific property added:
150 * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
151 * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
154 * @type {Event.Custom}
158 * @description Fires when this node enters a Drop Target. (Fired from dd-drop)
159 * @param {Event.Facade} event An Event Facade object with the following specific property added:
161 * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
162 * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
165 * @type {Event.Custom}
169 * @description Fires when this node exits a Drop Target. (Fired from dd-drop)
170 * @param {Event.Facade} event An Event Facade object with the following specific property added:
172 * <dt>drop</dt><dd>The drop object at the time of the event.</dd>
175 * @type {Event.Custom}
178 * @event drag:drophit
179 * @description Fires when this node is dropped on a valid Drop Target. (Fired from dd-ddm-drop)
180 * @param {Event.Facade} event An Event Facade object with the following specific property added:
182 * <dt>drop</dt><dd>The best guess on what was dropped on.</dd>
183 * <dt>drag</dt><dd>The drag object at the time of the event.</dd>
184 * <dt>others</dt><dd>An array of all the other drop targets that was dropped on.</dd>
187 * @type {Event.Custom}
190 * @event drag:dropmiss
191 * @description Fires when this node is dropped on an invalid Drop Target. (Fired from dd-ddm-drop)
192 * @param {Event.Facade} event An Event Facade object with the following specific property added:
194 * <dt>pageX</dt><dd>The current node position X.</dd>
195 * <dt>pageY</dt><dd>The current node position Y.</dd>
198 * @type {Event.Custom}
202 this._lazyAddAttrs = false;
203 Drag.superclass.constructor.apply(this, arguments);
205 var valid = DDM._regDrag(this);
207 Y.error('Failed to register node, already in use: ' + o.node);
214 * This property defaults to "mousedown", but when drag-gestures is loaded, it is changed to "gesturemovestart"
216 * @property START_EVENT
218 Drag.START_EVENT = 'mousedown';
223 * @description Y.Node instance to use as the element to initiate a drag operation
227 setter: function(node) {
230 Y.error('DD.Drag: Invalid Node Given: ' + node);
236 * @attribute dragNode
237 * @description Y.Node instance to use as the draggable element, defaults to node
241 setter: function(node) {
244 Y.error('DD.Drag: Invalid dragNode Given: ' + node);
250 * @attribute offsetNode
251 * @description Offset the drag element by the difference in cursor position: default true
258 * @attribute startCentered
259 * @description Center the dragNode to the mouse position on drag:start: default false
266 * @attribute clickPixelThresh
267 * @description The number of pixels to move to start a drag operation, default is 3.
271 value: DDM.get('clickPixelThresh')
274 * @attribute clickTimeThresh
275 * @description The number of milliseconds a mousedown has to pass to start a drag operation, default is 1000.
279 value: DDM.get('clickTimeThresh')
283 * @description Set to lock this drag element so that it can't be dragged: default false.
288 setter: function(lock) {
290 this.get(NODE).addClass(DDM.CSS_PREFIX + '-locked');
292 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-locked');
299 * @description A payload holder to store arbitrary data about this drag object, can be used to store any value.
307 * @description If this is false, the drag element will not move with the cursor: default true. Can be used to "resize" the element.
315 * @description Use the protective shim on all drag operations: default true. Only works with dd-ddm, not dd-ddm-base.
322 * @attribute activeHandle
323 * @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.
330 * @attribute primaryButtonOnly
331 * @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.
338 * @attribute dragging
339 * @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.
350 * @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.
355 setter: function(config) {
356 this._handleTarget(config);
361 * @attribute dragMode
362 * @description This attribute only works if the dd-drop module is active. It will set the dragMode (point, intersect, strict) of this Drag instance.
367 setter: function(mode) {
368 return DDM._setDragMode(mode);
373 * @description Array of groups to add this drag into.
383 Y.each(this._groups, function(v, k) {
388 setter: function(g) {
390 Y.each(g, function(v, k) {
391 this._groups[v] = true;
398 * @description Array of valid handles to add. Adding something here will set all handles, even if previously added with addHandle
403 setter: function(g) {
406 Y.each(g, function(v, k) {
408 if (v instanceof Y.Node || v instanceof Y.NodeList) {
411 this._handles[key] = v;
414 this._handles = null;
422 * @description Controls the default bubble parent for this Drag instance. Default: Y.DD.DDM. Set to false to disable bubbling. Use bubbleTargets in config
426 setter: function(t) {
432 * @attribute haltDown
433 * @description Should the mousedown event be halted. Default: true
441 Y.extend(Drag, Y.Base, {
444 * @property _bubbleTargets
445 * @description The default bubbleTarget for this object. Default: Y.DD.DDM
447 _bubbleTargets: Y.DD.DDM,
450 * @description Add this Drag instance to a group, this should be used for on-the-fly group additions.
451 * @param {String} g The group to add this Drag Instance to.
455 addToGroup: function(g) {
456 this._groups[g] = true;
457 DDM._activateTargets();
461 * @method removeFromGroup
462 * @description Remove this Drag instance from a group, this should be used for on-the-fly group removals.
463 * @param {String} g The group to remove this Drag Instance from.
467 removeFromGroup: function(g) {
468 delete this._groups[g];
469 DDM._activateTargets();
474 * @description This will be a reference to the Drop instance associated with this drag if the target: true config attribute is set..
480 * @method _handleTarget
481 * @description Attribute handler for the target config attribute.
482 * @param {Boolean/Object}
483 * @return {Boolean/Object}
485 _handleTarget: function(config) {
487 if (config === false) {
489 DDM._unregTarget(this.target);
494 if (!Y.Lang.isObject(config)) {
497 config.bubbleTargets = ('bubbleTargets' in config) ? config.bubbleTargets : Y.Object.values(this._yuievt.targets);
498 config.node = this.get(NODE);
499 config.groups = config.groups || this.get('groups');
500 this.target = new Y.DD.Drop(config);
509 * @description Storage Array for the groups this drag belongs to.
515 * @method _createEvents
516 * @description This method creates all the events for this Event Target and publishes them so we get Event Bubbling.
518 _createEvents: function() {
520 this.publish(EV_MOUSE_DOWN, {
521 defaultFn: this._defMouseDownFn,
528 this.publish(EV_ALIGN, {
529 defaultFn: this._defAlignFn,
536 this.publish(EV_DRAG, {
537 defaultFn: this._defDragFn,
544 this.publish(EV_END, {
545 defaultFn: this._defEndFn,
546 preventedFn: this._prevEndFn,
567 Y.each(ev, function(v, k) {
581 * @description A private reference to the mousedown DOM event
582 * @type {Event.Facade}
587 * @property _startTime
588 * @description The getTime of the mousedown event. Not used, just here in case someone wants/needs to use it.
595 * @description The getTime of the mouseup event. Not used, just here in case someone wants/needs to use it.
602 * @description A private hash of the valid drag handles
608 * @property _invalids
609 * @description A private hash of the invalid selector strings
615 * @property _invalidsDefault
616 * @description A private hash of the default invalid selector strings: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true}
619 _invalidsDefault: {'textarea': true, 'input': true, 'a': true, 'button': true, 'select': true },
622 * @property _dragThreshMet
623 * @description Private flag to see if the drag threshhold was met
626 _dragThreshMet: null,
629 * @property _fromTimeout
630 * @description Flag to determine if the drag operation came from a timeout
636 * @property _clickTimeout
637 * @description Holder for the setTimeout call
643 * @description The offset of the mouse position to the element's position
649 * @description The initial mouse position
655 * @description The initial element position
661 * @description The position of the element as it's moving (for offset calculations)
667 * @description The xy that the node will be set to. Changing this will alter the position as it's dragged.
673 * @description The real xy position of the node.
679 * @description The XY coords of the mousemove
685 * @description A region object associated with this drag, used for checking regions while dragging.
691 * @method _handleMouseUp
692 * @description Handler for the mouseup DOM event
693 * @param {Event.Facade}
695 _handleMouseUp: function(ev) {
696 this.fire('drag:mouseup');
697 this._fixIEMouseUp();
698 if (DDM.activeDrag) {
704 * @method _fixDragStart
705 * @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.
707 _fixDragStart: function(e) {
712 * @method _ieSelectFix
713 * @description The function we use as the onselectstart handler when we start a drag in Internet Explorer
715 _ieSelectFix: function() {
720 * @property _ieSelectBack
721 * @description We will hold a copy of the current "onselectstart" method on this property, and reset it after we are done using it.
726 * @method _fixIEMouseDown
727 * @description This method copies the onselectstart listner on the document to the _ieSelectFix property
729 _fixIEMouseDown: function(e) {
731 this._ieSelectBack = Y.config.doc.body.onselectstart;
732 Y.config.doc.body.onselectstart = this._ieSelectFix;
737 * @method _fixIEMouseUp
738 * @description This method copies the _ieSelectFix property back to the onselectstart listner on the document.
740 _fixIEMouseUp: function() {
742 Y.config.doc.body.onselectstart = this._ieSelectBack;
747 * @method _handleMouseDownEvent
748 * @description Handler for the mousedown DOM event
749 * @param {Event.Facade}
751 _handleMouseDownEvent: function(ev) {
752 this.fire(EV_MOUSE_DOWN, { ev: ev });
756 * @method _defMouseDownFn
757 * @description Handler for the mousedown DOM event
758 * @param {Event.Facade}
760 _defMouseDownFn: function(e) {
763 this._dragThreshMet = false;
766 if (this.get('primaryButtonOnly') && ev.button > 1) {
769 if (this.validClick(ev)) {
770 this._fixIEMouseDown(ev);
771 if (this.get('haltDown')) {
777 this._setStartPosition([ev.pageX, ev.pageY]);
779 DDM.activeDrag = this;
781 this._clickTimeout = Y.later(this.get('clickTimeThresh'), this, this._timeoutCheck);
783 this.fire(EV_AFTER_MOUSE_DOWN, { ev: ev });
787 * @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.
788 * @param {Event.Facade}
791 validClick: function(ev) {
792 var r = false, n = false,
799 Y.each(this._handles, function(i, n) {
800 if (i instanceof Y.Node || i instanceof Y.NodeList) {
803 if (nlist instanceof Y.Node) {
804 nlist = new Y.NodeList(i._node);
806 nlist.each(function(nl) {
807 if (nl.contains(tar)) {
812 } else if (Y.Lang.isString(n)) {
813 //Am I this or am I inside this
814 if (tar.test(n + ', ' + n + ' *') && !hTest) {
822 if (n.contains(tar) || n.compareTo(tar)) {
827 if (this._invalids) {
828 Y.each(this._invalids, function(i, n) {
829 if (Y.Lang.isString(n)) {
830 //Am I this or am I inside this
831 if (tar.test(n + ', ' + n + ' *')) {
840 els = ev.currentTarget.all(hTest);
842 els.each(function(n, i) {
843 if ((n.contains(tar) || n.compareTo(tar)) && !set) {
845 this.set('activeHandle', n);
849 this.set('activeHandle', this.get(NODE));
856 * @method _setStartPosition
857 * @description Sets the current position of the Element and calculates the offset
858 * @param {Array} xy The XY coords to set the position to.
860 _setStartPosition: function(xy) {
863 this.nodeXY = this.lastXY = this.realXY = this.get(NODE).getXY();
865 if (this.get('offsetNode')) {
866 this.deltaXY = [(this.startXY[0] - this.nodeXY[0]), (this.startXY[1] - this.nodeXY[1])];
868 this.deltaXY = [0, 0];
873 * @method _timeoutCheck
874 * @description The method passed to setTimeout to determine if the clickTimeThreshold was met.
876 _timeoutCheck: function() {
877 if (!this.get('lock') && !this._dragThreshMet && this._ev_md) {
878 this._fromTimeout = this._dragThreshMet = true;
880 this._alignNode([this._ev_md.pageX, this._ev_md.pageY], true);
884 * @method removeHandle
885 * @description Remove a Selector added by addHandle
886 * @param {String} str The selector for the handle to be removed.
890 removeHandle: function(str) {
892 if (str instanceof Y.Node || str instanceof Y.NodeList) {
895 if (this._handles[key]) {
896 delete this._handles[key];
897 this.fire(EV_REMOVE_HANDLE, { handle: str });
903 * @description Add a handle to a drag element. Drag only initiates when a mousedown happens on this element.
904 * @param {String} str The selector to test for a valid handle. Must be a child of the element.
908 addHandle: function(str) {
909 if (!this._handles) {
913 if (str instanceof Y.Node || str instanceof Y.NodeList) {
916 this._handles[key] = str;
917 this.fire(EV_ADD_HANDLE, { handle: str });
921 * @method removeInvalid
922 * @description Remove an invalid handle added by addInvalid
923 * @param {String} str The invalid handle to remove from the internal list.
927 removeInvalid: function(str) {
928 if (this._invalids[str]) {
929 this._invalids[str] = null;
930 delete this._invalids[str];
931 this.fire(EV_REMOVE_INVALID, { handle: str });
937 * @description Add a selector string to test the handle against. If the test passes the drag operation will not continue.
938 * @param {String} str The selector to test against to determine if this is an invalid drag handle.
942 addInvalid: function(str) {
943 if (Y.Lang.isString(str)) {
944 this._invalids[str] = true;
945 this.fire(EV_ADD_INVALID, { handle: str });
951 * @method initializer
952 * @description Internal init handler
954 initializer: function(cfg) {
955 this.get(NODE).dd = this;
957 if (!this.get(NODE).get('id')) {
958 var id = Y.stamp(this.get(NODE));
959 this.get(NODE).set('id', id);
964 this._invalids = Y.clone(this._invalidsDefault, true);
966 this._createEvents();
968 if (!this.get(DRAG_NODE)) {
969 this.set(DRAG_NODE, this.get(NODE));
973 //Don't prep the DD instance until all plugins are loaded.
974 this.on('initializedChange', Y.bind(this._prep, this));
976 //Shouldn't have to do this..
977 this.set('groups', this.get('groups'));
982 * @description Attach event listners and add classname
985 this._dragThreshMet = false;
986 var node = this.get(NODE);
987 node.addClass(DDM.CSS_PREFIX + '-draggable');
988 node.on(Drag.START_EVENT, Y.bind(this._handleMouseDownEvent, this));
989 node.on('mouseup', Y.bind(this._handleMouseUp, this));
990 node.on('dragstart', Y.bind(this._fixDragStart, this));
995 * @description Detach event listeners and remove classname
997 _unprep: function() {
998 var node = this.get(NODE);
999 node.removeClass(DDM.CSS_PREFIX + '-draggable');
1004 * @description Starts the drag operation
1009 if (!this.get('lock') && !this.get(DRAGGING)) {
1010 var node = this.get(NODE), ow, oh, xy;
1011 this._startTime = (new Date()).getTime();
1014 node.addClass(DDM.CSS_PREFIX + '-dragging');
1015 this.fire(EV_START, {
1016 pageX: this.nodeXY[0],
1017 pageY: this.nodeXY[1],
1018 startTime: this._startTime
1020 node = this.get(DRAG_NODE);
1023 ow = node.get(OFFSET_WIDTH);
1024 oh = node.get(OFFSET_HEIGHT);
1026 if (this.get('startCentered')) {
1027 this._setStartPosition([xy[0] + (ow / 2), xy[1] + (oh / 2)]);
1040 this.set(DRAGGING, true);
1046 * @description Ends the drag operation
1051 this._endTime = (new Date()).getTime();
1052 if (this._clickTimeout) {
1053 this._clickTimeout.cancel();
1055 this._dragThreshMet = this._fromTimeout = false;
1057 if (!this.get('lock') && this.get(DRAGGING)) {
1059 pageX: this.lastXY[0],
1060 pageY: this.lastXY[1],
1061 startTime: this._startTime,
1062 endTime: this._endTime
1065 this.get(NODE).removeClass(DDM.CSS_PREFIX + '-dragging');
1066 this.set(DRAGGING, false);
1067 this.deltaXY = [0, 0];
1074 * @description Handler for fixing the selection in IE
1076 _defEndFn: function(e) {
1077 this._fixIEMouseUp();
1082 * @method _prevEndFn
1083 * @description Handler for preventing the drag:end event. It will reset the node back to it's start position
1085 _prevEndFn: function(e) {
1086 this._fixIEMouseUp();
1088 this.get(DRAG_NODE).setXY(this.nodeXY);
1095 * @description Calculates the offsets and set's the XY that the element will move to.
1096 * @param {Array} xy The xy coords to align with.
1098 _align: function(xy) {
1099 this.fire(EV_ALIGN, {pageX: xy[0], pageY: xy[1] });
1103 * @method _defAlignFn
1104 * @description Calculates the offsets and set's the XY that the element will move to.
1105 * @param {Event.Facade} e The drag:align event.
1107 _defAlignFn: function(e) {
1108 this.actXY = [e.pageX - this.deltaXY[0], e.pageY - this.deltaXY[1]];
1112 * @method _alignNode
1113 * @description This method performs the alignment before the element move.
1114 * @param {Array} eXY The XY to move the element to, usually comes from the mousemove DOM event.
1116 _alignNode: function(eXY) {
1123 * @description This method performs the actual element move.
1125 _moveNode: function(scroll) {
1126 //if (!this.get(DRAGGING)) {
1129 var diffXY = [], diffXY2 = [], startXY = this.nodeXY, xy = this.actXY;
1131 diffXY[0] = (xy[0] - this.lastXY[0]);
1132 diffXY[1] = (xy[1] - this.lastXY[1]);
1134 diffXY2[0] = (xy[0] - this.nodeXY[0]);
1135 diffXY2[1] = (xy[1] - this.nodeXY[1]);
1143 right: xy[0] + this.get(DRAG_NODE).get(OFFSET_WIDTH),
1144 bottom: xy[1] + this.get(DRAG_NODE).get(OFFSET_HEIGHT),
1148 this.fire(EV_DRAG, {
1164 * @method _defDragFn
1165 * @description Default function for drag:drag. Fired from _moveNode.
1166 * @param {Event.Facade} ev The drag:drag event
1168 _defDragFn: function(e) {
1169 if (this.get('move')) {
1171 e.scroll.node.set('scrollTop', e.scroll.top);
1172 e.scroll.node.set('scrollLeft', e.scroll.left);
1174 this.get(DRAG_NODE).setXY([e.pageX, e.pageY]);
1175 this.realXY = [e.pageX, e.pageY];
1181 * @description Fired from DragDropMgr (DDM) on mousemove.
1182 * @param {Event.Facade} ev The mousemove DOM event
1184 _move: function(ev) {
1185 if (this.get('lock')) {
1188 this.mouseXY = [ev.pageX, ev.pageY];
1189 if (!this._dragThreshMet) {
1190 var diffX = Math.abs(this.startXY[0] - ev.pageX),
1191 diffY = Math.abs(this.startXY[1] - ev.pageY);
1192 if (diffX > this.get('clickPixelThresh') || diffY > this.get('clickPixelThresh')) {
1193 this._dragThreshMet = true;
1195 this._alignNode([ev.pageX, ev.pageY]);
1198 if (this._clickTimeout) {
1199 this._clickTimeout.cancel();
1201 this._alignNode([ev.pageX, ev.pageY]);
1207 * @description Method will forcefully stop a drag operation. For example calling this from inside an ESC keypress handler will stop this drag.
1211 stopDrag: function() {
1212 if (this.get(DRAGGING)) {
1219 * @method destructor
1220 * @description Lifecycle destructor, unreg the drag from the DDM and remove listeners
1222 destructor: function() {
1226 this.target.destroy();
1228 DDM._unregDrag(this);
1238 }, '3.3.0' ,{requires:['dd-ddm-base'], skinnable:false});