draggable.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /**
  2. * DevExtreme (ui/draggable.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 window = require("../core/utils/window").getWindow();
  12. var eventsEngine = require("../events/core/events_engine");
  13. var stringUtils = require("../core/utils/string");
  14. var registerComponent = require("../core/component_registrator");
  15. var translator = require("../animation/translator");
  16. var dasherize = require("../core/utils/inflector").dasherize;
  17. var extend = require("../core/utils/extend").extend;
  18. var DOMComponent = require("../core/dom_component");
  19. var eventUtils = require("../events/utils");
  20. var pointerEvents = require("../events/pointer");
  21. var dragEvents = require("../events/drag");
  22. var positionUtils = require("../animation/position");
  23. var isFunction = require("../core/utils/type").isFunction;
  24. var noop = require("../core/utils/common").noop;
  25. var DRAGGABLE = "dxDraggable";
  26. var DRAGSTART_EVENT_NAME = eventUtils.addNamespace(dragEvents.start, DRAGGABLE);
  27. var DRAG_EVENT_NAME = eventUtils.addNamespace(dragEvents.move, DRAGGABLE);
  28. var DRAGEND_EVENT_NAME = eventUtils.addNamespace(dragEvents.end, DRAGGABLE);
  29. var POINTERDOWN_EVENT_NAME = eventUtils.addNamespace(pointerEvents.down, DRAGGABLE);
  30. var DRAGGABLE_CLASS = dasherize(DRAGGABLE);
  31. var DRAGGABLE_DRAGGING_CLASS = DRAGGABLE_CLASS + "-dragging";
  32. var Draggable = DOMComponent.inherit({
  33. _getDefaultOptions: function() {
  34. return extend(this.callBase(), {
  35. onDragStart: noop,
  36. onDrag: noop,
  37. onDragEnd: noop,
  38. immediate: true,
  39. direction: "both",
  40. area: window,
  41. boundOffset: 0,
  42. allowMoveByClick: false
  43. })
  44. },
  45. _init: function() {
  46. this.callBase();
  47. this._attachEventHandlers()
  48. },
  49. _attachEventHandlers: function() {
  50. if (this.option("disabled")) {
  51. return
  52. }
  53. var $element = this.$element().css("position", "absolute");
  54. var eventHandlers = {};
  55. var allowMoveByClick = this.option("allowMoveByClick");
  56. eventHandlers[DRAGSTART_EVENT_NAME] = this._dragStartHandler.bind(this);
  57. eventHandlers[DRAG_EVENT_NAME] = this._dragHandler.bind(this);
  58. eventHandlers[DRAGEND_EVENT_NAME] = this._dragEndHandler.bind(this);
  59. if (allowMoveByClick) {
  60. eventHandlers[POINTERDOWN_EVENT_NAME] = this._pointerDownHandler.bind(this);
  61. $element = this._getArea()
  62. }
  63. eventsEngine.on($element, eventHandlers, {
  64. direction: this.option("direction"),
  65. immediate: this.option("immediate")
  66. })
  67. },
  68. _detachEventHandlers: function() {
  69. eventsEngine.off(this.$element(), "." + DRAGGABLE);
  70. eventsEngine.off(this._getArea(), "." + DRAGGABLE)
  71. },
  72. _move: function(position) {
  73. translator.move(this.$element(), position)
  74. },
  75. _pointerDownHandler: function(e) {
  76. if (eventUtils.needSkipEvent(e)) {
  77. return
  78. }
  79. var areaOffset = this._getAreaOffset($(e.currentTarget));
  80. var direction = this.option("direction");
  81. var position = {};
  82. if ("horizontal" === direction || "both" === direction) {
  83. position.left = e.pageX - this.$element().width() / 2 - areaOffset.left
  84. }
  85. if ("vertical" === direction || "both" === direction) {
  86. position.top = e.pageY - this.$element().height() / 2 - areaOffset.top
  87. }
  88. this._move(position);
  89. this._getAction("onDrag")({
  90. event: e
  91. })
  92. },
  93. _dragStartHandler: function(e) {
  94. var $element = this.$element();
  95. if ($element.is(".dx-state-disabled, .dx-state-disabled *")) {
  96. e.cancel = true;
  97. return
  98. }
  99. var $area = this._getArea();
  100. var areaOffset = this._getAreaOffset($area);
  101. var boundOffset = this._getBoundOffset();
  102. var areaWidth = $area.outerWidth();
  103. var areaHeight = $area.outerHeight();
  104. var elementWidth = $element.width();
  105. var elementHeight = $element.height();
  106. this._toggleDraggingClass(true);
  107. var startOffset = {
  108. left: $element.offset().left - areaOffset.left,
  109. top: $element.offset().top - areaOffset.top
  110. };
  111. this._startPosition = translator.locate($element);
  112. e.maxLeftOffset = startOffset.left - boundOffset.left;
  113. e.maxRightOffset = areaWidth - startOffset.left - elementWidth - boundOffset.right;
  114. e.maxTopOffset = startOffset.top - boundOffset.top;
  115. e.maxBottomOffset = areaHeight - startOffset.top - elementHeight - boundOffset.bottom;
  116. this._getAction("onDragStart")({
  117. event: e
  118. })
  119. },
  120. _getAreaOffset: function($area) {
  121. var offset = $area && positionUtils.offset($area);
  122. return offset ? offset : {
  123. left: 0,
  124. top: 0
  125. }
  126. },
  127. _toggleDraggingClass: function(value) {
  128. this.$element().toggleClass(DRAGGABLE_DRAGGING_CLASS, value)
  129. },
  130. _getBoundOffset: function() {
  131. var boundOffset = this.option("boundOffset");
  132. if (isFunction(boundOffset)) {
  133. boundOffset = boundOffset.call(this)
  134. }
  135. return stringUtils.quadToObject(boundOffset)
  136. },
  137. _getArea: function() {
  138. var area = this.option("area");
  139. if (isFunction(area)) {
  140. area = area.call(this)
  141. }
  142. return $(area)
  143. },
  144. _dragHandler: function(e) {
  145. var offset = e.offset;
  146. var startPosition = this._startPosition;
  147. this._move({
  148. left: startPosition.left + offset.x,
  149. top: startPosition.top + offset.y
  150. });
  151. this._getAction("onDrag")({
  152. event: e
  153. })
  154. },
  155. _dragEndHandler: function(e) {
  156. this._toggleDraggingClass(false);
  157. this._getAction("onDragEnd")({
  158. event: e
  159. })
  160. },
  161. _getAction: function(name) {
  162. return this["_" + name + "Action"] || this._createActionByOption(name)
  163. },
  164. _render: function() {
  165. this.callBase();
  166. this.$element().addClass(DRAGGABLE_CLASS)
  167. },
  168. _optionChanged: function(args) {
  169. var name = args.name;
  170. switch (name) {
  171. case "onDragStart":
  172. case "onDrag":
  173. case "onDragEnd":
  174. this["_" + name + "Action"] = this._createActionByOption(name);
  175. break;
  176. case "allowMoveByClick":
  177. case "direction":
  178. case "disabled":
  179. this._detachEventHandlers();
  180. this._attachEventHandlers();
  181. break;
  182. case "boundOffset":
  183. case "area":
  184. break;
  185. default:
  186. this.callBase(args)
  187. }
  188. },
  189. _dispose: function() {
  190. this.callBase();
  191. this._detachEventHandlers()
  192. }
  193. });
  194. registerComponent(DRAGGABLE, Draggable);
  195. module.exports = Draggable;