emitter.gesture.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /**
  2. * DevExtreme (events/gesture/emitter.gesture.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 eventsEngine = require("../../events/core/events_engine");
  12. var devices = require("../../core/devices");
  13. var styleUtils = require("../../core/utils/style");
  14. var callOnce = require("../../core/utils/call_once");
  15. var domUtils = require("../../core/utils/dom");
  16. var readyCallbacks = require("../../core/utils/ready_callbacks");
  17. var ready = readyCallbacks.add;
  18. var mathUtils = require("../../core/utils/math");
  19. var noop = require("../../core/utils/common").noop;
  20. var isDefined = require("../../core/utils/type").isDefined;
  21. var eventUtils = require("../utils");
  22. var Emitter = require("../core/emitter");
  23. var sign = mathUtils.sign;
  24. var abs = Math.abs;
  25. var SLEEP = 0;
  26. var INITED = 1;
  27. var STARTED = 2;
  28. var TOUCH_BOUNDARY = 10;
  29. var IMMEDIATE_TOUCH_BOUNDARY = 0;
  30. var IMMEDIATE_TIMEOUT = 180;
  31. var supportPointerEvents = function() {
  32. return styleUtils.styleProp("pointer-events")
  33. };
  34. var setGestureCover = callOnce(function() {
  35. var GESTURE_COVER_CLASS = "dx-gesture-cover";
  36. var isDesktop = "generic" === devices.real().platform;
  37. if (!supportPointerEvents() || !isDesktop) {
  38. return noop
  39. }
  40. var $cover = $("<div>").addClass(GESTURE_COVER_CLASS).css("pointerEvents", "none");
  41. eventsEngine.subscribeGlobal($cover, "dxmousewheel", function(e) {
  42. e.preventDefault()
  43. });
  44. ready(function() {
  45. $cover.appendTo("body")
  46. });
  47. return function(toggle, cursor) {
  48. $cover.css("pointerEvents", toggle ? "all" : "none");
  49. toggle && $cover.css("cursor", cursor)
  50. }
  51. });
  52. var gestureCover = function(toggle, cursor) {
  53. var gestureCoverStrategy = setGestureCover();
  54. gestureCoverStrategy(toggle, cursor)
  55. };
  56. var GestureEmitter = Emitter.inherit({
  57. gesture: true,
  58. configure: function(data) {
  59. this.getElement().css("msTouchAction", data.immediate ? "pinch-zoom" : "");
  60. this.callBase(data)
  61. },
  62. allowInterruptionByMouseWheel: function() {
  63. return this._stage !== STARTED
  64. },
  65. getDirection: function() {
  66. return this.direction
  67. },
  68. _cancel: function() {
  69. this.callBase.apply(this, arguments);
  70. this._toggleGestureCover(false);
  71. this._stage = SLEEP
  72. },
  73. start: function(e) {
  74. if (e._needSkipEvent || eventUtils.needSkipEvent(e)) {
  75. this._cancel(e);
  76. return
  77. }
  78. this._startEvent = eventUtils.createEvent(e);
  79. this._startEventData = eventUtils.eventData(e);
  80. this._stage = INITED;
  81. this._init(e);
  82. this._setupImmediateTimer()
  83. },
  84. _setupImmediateTimer: function() {
  85. clearTimeout(this._immediateTimer);
  86. this._immediateAccepted = false;
  87. if (!this.immediate) {
  88. return
  89. }
  90. this._immediateTimer = setTimeout(function() {
  91. this._immediateAccepted = true
  92. }.bind(this), IMMEDIATE_TIMEOUT)
  93. },
  94. move: function(e) {
  95. if (this._stage === INITED && this._directionConfirmed(e)) {
  96. this._stage = STARTED;
  97. this._resetActiveElement();
  98. this._toggleGestureCover(true);
  99. this._clearSelection(e);
  100. this._adjustStartEvent(e);
  101. this._start(this._startEvent);
  102. if (this._stage === SLEEP) {
  103. return
  104. }
  105. this._requestAccept(e);
  106. this._move(e);
  107. this._forgetAccept()
  108. } else {
  109. if (this._stage === STARTED) {
  110. this._clearSelection(e);
  111. this._move(e)
  112. }
  113. }
  114. },
  115. _directionConfirmed: function(e) {
  116. var touchBoundary = this._getTouchBoundary(e);
  117. var delta = eventUtils.eventDelta(this._startEventData, eventUtils.eventData(e));
  118. var deltaX = abs(delta.x);
  119. var deltaY = abs(delta.y);
  120. var horizontalMove = this._validateMove(touchBoundary, deltaX, deltaY);
  121. var verticalMove = this._validateMove(touchBoundary, deltaY, deltaX);
  122. var direction = this.getDirection(e);
  123. var bothAccepted = "both" === direction && (horizontalMove || verticalMove);
  124. var horizontalAccepted = "horizontal" === direction && horizontalMove;
  125. var verticalAccepted = "vertical" === direction && verticalMove;
  126. return bothAccepted || horizontalAccepted || verticalAccepted || this._immediateAccepted
  127. },
  128. _validateMove: function(touchBoundary, mainAxis, crossAxis) {
  129. return mainAxis && mainAxis >= touchBoundary && (this.immediate ? mainAxis >= crossAxis : true)
  130. },
  131. _getTouchBoundary: function(e) {
  132. return this.immediate || eventUtils.isDxMouseWheelEvent(e) ? IMMEDIATE_TOUCH_BOUNDARY : TOUCH_BOUNDARY
  133. },
  134. _adjustStartEvent: function(e) {
  135. var touchBoundary = this._getTouchBoundary(e);
  136. var delta = eventUtils.eventDelta(this._startEventData, eventUtils.eventData(e));
  137. this._startEvent.pageX += sign(delta.x) * touchBoundary;
  138. this._startEvent.pageY += sign(delta.y) * touchBoundary
  139. },
  140. _resetActiveElement: function() {
  141. if ("ios" === devices.real().platform && this.getElement().find(":focus").length) {
  142. domUtils.resetActiveElement()
  143. }
  144. },
  145. _toggleGestureCover: function(toggle) {
  146. this._toggleGestureCoverImpl(toggle)
  147. },
  148. _toggleGestureCoverImpl: function(toggle) {
  149. var isStarted = this._stage === STARTED;
  150. if (isStarted) {
  151. gestureCover(toggle, this.getElement().css("cursor"))
  152. }
  153. },
  154. _clearSelection: function(e) {
  155. if (eventUtils.isDxMouseWheelEvent(e) || eventUtils.isTouchEvent(e)) {
  156. return
  157. }
  158. domUtils.clearSelection()
  159. },
  160. end: function(e) {
  161. this._toggleGestureCover(false);
  162. if (this._stage === STARTED) {
  163. this._end(e)
  164. } else {
  165. if (this._stage === INITED) {
  166. this._stop(e)
  167. }
  168. }
  169. this._stage = SLEEP
  170. },
  171. dispose: function() {
  172. clearTimeout(this._immediateTimer);
  173. this.callBase.apply(this, arguments);
  174. this._toggleGestureCover(false)
  175. },
  176. _init: noop,
  177. _start: noop,
  178. _move: noop,
  179. _stop: noop,
  180. _end: noop
  181. });
  182. GestureEmitter.initialTouchBoundary = TOUCH_BOUNDARY;
  183. GestureEmitter.touchBoundary = function(newBoundary) {
  184. if (isDefined(newBoundary)) {
  185. TOUCH_BOUNDARY = newBoundary;
  186. return
  187. }
  188. return TOUCH_BOUNDARY
  189. };
  190. module.exports = GestureEmitter;