click.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /**
  2. * DevExtreme (events/click.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 domAdapter = require("../core/dom_adapter");
  14. var domUtils = require("../core/utils/dom");
  15. var animationFrame = require("../animation/frame");
  16. var eventUtils = require("./utils");
  17. var pointerEvents = require("./pointer");
  18. var Emitter = require("./core/emitter");
  19. var registerEmitter = require("./core/emitter_registrator");
  20. var compareVersions = require("../core/utils/version").compare;
  21. var CLICK_EVENT_NAME = "dxclick";
  22. var TOUCH_BOUNDARY = 10;
  23. var abs = Math.abs;
  24. var isInput = function(element) {
  25. return $(element).is("input, textarea, select, button ,:focus, :focus *")
  26. };
  27. var misc = {
  28. requestAnimationFrame: animationFrame.requestAnimationFrame,
  29. cancelAnimationFrame: animationFrame.cancelAnimationFrame
  30. };
  31. var ClickEmitter = Emitter.inherit({
  32. ctor: function(element) {
  33. this.callBase(element);
  34. this._makeElementClickable($(element))
  35. },
  36. _makeElementClickable: function($element) {
  37. if (!$element.attr("onclick")) {
  38. $element.attr("onclick", "void(0)")
  39. }
  40. },
  41. start: function(e) {
  42. this._blurPrevented = e.isDefaultPrevented();
  43. this._startTarget = e.target;
  44. this._startEventData = eventUtils.eventData(e)
  45. },
  46. end: function(e) {
  47. if (this._eventOutOfElement(e, this.getElement().get(0)) || e.type === pointerEvents.cancel) {
  48. this._cancel(e);
  49. return
  50. }
  51. if (!isInput(e.target) && !this._blurPrevented) {
  52. domUtils.resetActiveElement()
  53. }
  54. this._accept(e);
  55. this._clickAnimationFrame = misc.requestAnimationFrame(function() {
  56. this._fireClickEvent(e)
  57. }.bind(this))
  58. },
  59. _eventOutOfElement: function(e, element) {
  60. var target = e.target;
  61. var targetChanged = !domUtils.contains(element, target) && element !== target;
  62. var gestureDelta = eventUtils.eventDelta(eventUtils.eventData(e), this._startEventData);
  63. var boundsExceeded = abs(gestureDelta.x) > TOUCH_BOUNDARY || abs(gestureDelta.y) > TOUCH_BOUNDARY;
  64. return targetChanged || boundsExceeded
  65. },
  66. _fireClickEvent: function(e) {
  67. this._fireEvent(CLICK_EVENT_NAME, e, {
  68. target: domUtils.closestCommonParent(this._startTarget, e.target)
  69. })
  70. },
  71. dispose: function() {
  72. misc.cancelAnimationFrame(this._clickAnimationFrame)
  73. }
  74. });
  75. ! function() {
  76. var NATIVE_CLICK_CLASS = "dx-native-click";
  77. var realDevice = devices.real();
  78. var useNativeClick = realDevice.generic || realDevice.ios && compareVersions(realDevice.version, [9, 3]) >= 0 || realDevice.android && compareVersions(realDevice.version, [5]) >= 0;
  79. var isNativeClickEvent = function(target) {
  80. return useNativeClick || $(target).closest("." + NATIVE_CLICK_CLASS).length
  81. };
  82. var prevented = null;
  83. var lastFiredEvent = null;
  84. var clickHandler = function(e) {
  85. var originalEvent = e.originalEvent;
  86. var eventAlreadyFired = lastFiredEvent === originalEvent || originalEvent && originalEvent.DXCLICK_FIRED;
  87. var leftButton = !e.which || 1 === e.which;
  88. if (leftButton && !prevented && isNativeClickEvent(e.target) && !eventAlreadyFired) {
  89. if (originalEvent) {
  90. originalEvent.DXCLICK_FIRED = true
  91. }
  92. lastFiredEvent = originalEvent;
  93. eventUtils.fireEvent({
  94. type: CLICK_EVENT_NAME,
  95. originalEvent: e
  96. })
  97. }
  98. };
  99. ClickEmitter = ClickEmitter.inherit({
  100. _makeElementClickable: function($element) {
  101. if (!isNativeClickEvent($element)) {
  102. this.callBase($element)
  103. }
  104. eventsEngine.on($element, "click", clickHandler)
  105. },
  106. configure: function(data) {
  107. this.callBase(data);
  108. if (data.useNative) {
  109. this.getElement().addClass(NATIVE_CLICK_CLASS)
  110. }
  111. },
  112. start: function(e) {
  113. prevented = null;
  114. if (!isNativeClickEvent(e.target)) {
  115. this.callBase(e)
  116. }
  117. },
  118. end: function(e) {
  119. if (!isNativeClickEvent(e.target)) {
  120. this.callBase(e)
  121. }
  122. },
  123. cancel: function() {
  124. prevented = true
  125. },
  126. dispose: function() {
  127. this.callBase();
  128. eventsEngine.off(this.getElement(), "click", clickHandler)
  129. }
  130. })
  131. }();
  132. ! function() {
  133. var desktopDevice = devices.real().generic;
  134. if (!desktopDevice) {
  135. var startTarget = null;
  136. var blurPrevented = false;
  137. var pointerDownHandler = function(e) {
  138. startTarget = e.target;
  139. blurPrevented = e.isDefaultPrevented()
  140. };
  141. var clickHandler = function(e) {
  142. var $target = $(e.target);
  143. if (!blurPrevented && startTarget && !$target.is(startTarget) && !$(startTarget).is("label") && isInput($target)) {
  144. domUtils.resetActiveElement()
  145. }
  146. startTarget = null;
  147. blurPrevented = false
  148. };
  149. var NATIVE_CLICK_FIXER_NAMESPACE = "NATIVE_CLICK_FIXER";
  150. var document = domAdapter.getDocument();
  151. eventsEngine.subscribeGlobal(document, eventUtils.addNamespace(pointerEvents.down, NATIVE_CLICK_FIXER_NAMESPACE), pointerDownHandler);
  152. eventsEngine.subscribeGlobal(document, eventUtils.addNamespace("click", NATIVE_CLICK_FIXER_NAMESPACE), clickHandler)
  153. }
  154. }();
  155. registerEmitter({
  156. emitter: ClickEmitter,
  157. bubble: true,
  158. events: [CLICK_EVENT_NAME]
  159. });
  160. exports.name = CLICK_EVENT_NAME;