drag.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /**
  2. * DevExtreme (events/drag.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var $ = require("../core/renderer");
  11. var dataUtils = require("../core/element_data");
  12. var wrapToArray = require("../core/utils/array").wrapToArray;
  13. var inArray = require("../core/utils/array").inArray;
  14. var iteratorUtils = require("../core/utils/iterator");
  15. var contains = require("../core/utils/dom").contains;
  16. var registerEvent = require("./core/event_registrator");
  17. var eventUtils = require("./utils");
  18. var GestureEmitter = require("./gesture/emitter.gesture");
  19. var registerEmitter = require("./core/emitter_registrator");
  20. var DRAG_START_EVENT = "dxdragstart";
  21. var DRAG_EVENT = "dxdrag";
  22. var DRAG_END_EVENT = "dxdragend";
  23. var DRAG_ENTER_EVENT = "dxdragenter";
  24. var DRAG_LEAVE_EVENT = "dxdragleave";
  25. var DROP_EVENT = "dxdrop";
  26. var DX_DRAG_EVENTS_COUNT_KEY = "dxDragEventsCount";
  27. var knownDropTargets = [];
  28. var knownDropTargetSelectors = [];
  29. var knownDropTargetConfigs = [];
  30. var dropTargetRegistration = {
  31. setup: function(element, data) {
  32. var knownDropTarget = inArray(element, knownDropTargets) !== -1;
  33. if (!knownDropTarget) {
  34. knownDropTargets.push(element);
  35. knownDropTargetSelectors.push([]);
  36. knownDropTargetConfigs.push(data || {})
  37. }
  38. },
  39. add: function(element, handleObj) {
  40. var index = inArray(element, knownDropTargets);
  41. this.updateEventsCounter(element, handleObj.type, 1);
  42. var selector = handleObj.selector;
  43. if (inArray(selector, knownDropTargetSelectors[index]) === -1) {
  44. knownDropTargetSelectors[index].push(selector)
  45. }
  46. },
  47. updateEventsCounter: function(element, event, value) {
  48. if ([DRAG_ENTER_EVENT, DRAG_LEAVE_EVENT, DROP_EVENT].indexOf(event) > -1) {
  49. var eventsCount = dataUtils.data(element, DX_DRAG_EVENTS_COUNT_KEY) || 0;
  50. dataUtils.data(element, DX_DRAG_EVENTS_COUNT_KEY, Math.max(0, eventsCount + value))
  51. }
  52. },
  53. remove: function(element, handleObj) {
  54. this.updateEventsCounter(element, handleObj.type, -1)
  55. },
  56. teardown: function(element) {
  57. var handlersCount = dataUtils.data(element, DX_DRAG_EVENTS_COUNT_KEY);
  58. if (!handlersCount) {
  59. var index = inArray(element, knownDropTargets);
  60. knownDropTargets.splice(index, 1);
  61. knownDropTargetSelectors.splice(index, 1);
  62. knownDropTargetConfigs.splice(index, 1);
  63. dataUtils.removeData(element, DX_DRAG_EVENTS_COUNT_KEY)
  64. }
  65. }
  66. };
  67. registerEvent(DRAG_ENTER_EVENT, dropTargetRegistration);
  68. registerEvent(DRAG_LEAVE_EVENT, dropTargetRegistration);
  69. registerEvent(DROP_EVENT, dropTargetRegistration);
  70. var getItemDelegatedTargets = function($element) {
  71. var dropTargetIndex = inArray($element.get(0), knownDropTargets);
  72. var dropTargetSelectors = knownDropTargetSelectors[dropTargetIndex];
  73. var $delegatedTargets = $element.find(dropTargetSelectors.join(", "));
  74. if (inArray(void 0, dropTargetSelectors) !== -1) {
  75. $delegatedTargets = $delegatedTargets.add($element)
  76. }
  77. return $delegatedTargets
  78. };
  79. var getItemConfig = function($element) {
  80. var dropTargetIndex = inArray($element.get(0), knownDropTargets);
  81. return knownDropTargetConfigs[dropTargetIndex]
  82. };
  83. var getItemPosition = function(dropTargetConfig, $element) {
  84. if (dropTargetConfig.itemPositionFunc) {
  85. return dropTargetConfig.itemPositionFunc($element)
  86. } else {
  87. return $element.offset()
  88. }
  89. };
  90. var getItemSize = function(dropTargetConfig, $element) {
  91. if (dropTargetConfig.itemSizeFunc) {
  92. return dropTargetConfig.itemSizeFunc($element)
  93. }
  94. return {
  95. width: $element.get(0).getBoundingClientRect().width,
  96. height: $element.get(0).getBoundingClientRect().height
  97. }
  98. };
  99. var DragEmitter = GestureEmitter.inherit({
  100. ctor: function(element) {
  101. this.callBase(element);
  102. this.direction = "both"
  103. },
  104. _init: function(e) {
  105. this._initEvent = e
  106. },
  107. _start: function(e) {
  108. e = this._fireEvent(DRAG_START_EVENT, this._initEvent);
  109. this._maxLeftOffset = e.maxLeftOffset;
  110. this._maxRightOffset = e.maxRightOffset;
  111. this._maxTopOffset = e.maxTopOffset;
  112. this._maxBottomOffset = e.maxBottomOffset;
  113. var dropTargets = wrapToArray(e.targetElements || (null === e.targetElements ? [] : knownDropTargets));
  114. this._dropTargets = iteratorUtils.map(dropTargets, function(element) {
  115. return $(element).get(0)
  116. })
  117. },
  118. _move: function(e) {
  119. var eventData = eventUtils.eventData(e);
  120. var dragOffset = this._calculateOffset(eventData);
  121. e = this._fireEvent(DRAG_EVENT, e, {
  122. offset: dragOffset
  123. });
  124. this._processDropTargets(e);
  125. if (!e._cancelPreventDefault) {
  126. e.preventDefault()
  127. }
  128. },
  129. _calculateOffset: function(eventData) {
  130. return {
  131. x: this._calculateXOffset(eventData),
  132. y: this._calculateYOffset(eventData)
  133. }
  134. },
  135. _calculateXOffset: function(eventData) {
  136. if ("vertical" !== this.direction) {
  137. var offset = eventData.x - this._startEventData.x;
  138. return this._fitOffset(offset, this._maxLeftOffset, this._maxRightOffset)
  139. }
  140. return 0
  141. },
  142. _calculateYOffset: function(eventData) {
  143. if ("horizontal" !== this.direction) {
  144. var offset = eventData.y - this._startEventData.y;
  145. return this._fitOffset(offset, this._maxTopOffset, this._maxBottomOffset)
  146. }
  147. return 0
  148. },
  149. _fitOffset: function(offset, minOffset, maxOffset) {
  150. if (null != minOffset) {
  151. offset = Math.max(offset, -minOffset)
  152. }
  153. if (null != maxOffset) {
  154. offset = Math.min(offset, maxOffset)
  155. }
  156. return offset
  157. },
  158. _processDropTargets: function(e) {
  159. var target = this._findDropTarget(e);
  160. var sameTarget = target === this._currentDropTarget;
  161. if (!sameTarget) {
  162. this._fireDropTargetEvent(e, DRAG_LEAVE_EVENT);
  163. this._currentDropTarget = target;
  164. this._fireDropTargetEvent(e, DRAG_ENTER_EVENT)
  165. }
  166. },
  167. _fireDropTargetEvent: function(event, eventName) {
  168. if (!this._currentDropTarget) {
  169. return
  170. }
  171. var eventData = {
  172. type: eventName,
  173. originalEvent: event,
  174. draggingElement: this._$element.get(0),
  175. target: this._currentDropTarget
  176. };
  177. eventUtils.fireEvent(eventData)
  178. },
  179. _findDropTarget: function(e) {
  180. var that = this;
  181. var result;
  182. iteratorUtils.each(knownDropTargets, function(_, target) {
  183. if (!that._checkDropTargetActive(target)) {
  184. return
  185. }
  186. var $target = $(target);
  187. iteratorUtils.each(getItemDelegatedTargets($target), function(_, delegatedTarget) {
  188. var $delegatedTarget = $(delegatedTarget);
  189. if (that._checkDropTarget(getItemConfig($target), $delegatedTarget, e)) {
  190. result = delegatedTarget
  191. }
  192. })
  193. });
  194. return result
  195. },
  196. _checkDropTargetActive: function(target) {
  197. var active = false;
  198. iteratorUtils.each(this._dropTargets, function(_, activeTarget) {
  199. active = active || activeTarget === target || contains(activeTarget, target);
  200. return !active
  201. });
  202. return active
  203. },
  204. _checkDropTarget: function(config, $target, e) {
  205. var isDraggingElement = $target.get(0) === this._$element.get(0);
  206. if (isDraggingElement) {
  207. return false
  208. }
  209. var targetPosition = getItemPosition(config, $target);
  210. if (e.pageX < targetPosition.left) {
  211. return false
  212. }
  213. if (e.pageY < targetPosition.top) {
  214. return false
  215. }
  216. var targetSize = getItemSize(config, $target);
  217. if (e.pageX > targetPosition.left + targetSize.width) {
  218. return false
  219. }
  220. if (e.pageY > targetPosition.top + targetSize.height) {
  221. return false
  222. }
  223. return $target
  224. },
  225. _end: function(e) {
  226. var eventData = eventUtils.eventData(e);
  227. this._fireEvent(DRAG_END_EVENT, e, {
  228. offset: this._calculateOffset(eventData)
  229. });
  230. this._fireDropTargetEvent(e, DROP_EVENT);
  231. delete this._currentDropTarget
  232. }
  233. });
  234. registerEmitter({
  235. emitter: DragEmitter,
  236. events: [DRAG_START_EVENT, DRAG_EVENT, DRAG_END_EVENT]
  237. });
  238. exports.move = DRAG_EVENT;
  239. exports.start = DRAG_START_EVENT;
  240. exports.end = DRAG_END_EVENT;
  241. exports.enter = DRAG_ENTER_EVENT;
  242. exports.leave = DRAG_LEAVE_EVENT;
  243. exports.drop = DROP_EVENT;