ExamplesPlaygroundReference Source

coral-spectrum/coral-utils/src/scripts/Events.js

  1. /**
  2. * Copyright 2019 Adobe. All rights reserved.
  3. * This file is licensed to you under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License. You may obtain a copy
  5. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. *
  7. * Unless required by applicable law or agreed to in writing, software distributed under
  8. * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
  9. * OF ANY KIND, either express or implied. See the License for the specific language
  10. * governing permissions and limitations under the License.
  11. */
  12.  
  13. import commons from './Commons';
  14. import Vent from '@adobe/vent';
  15.  
  16. /**
  17. Events helper.
  18. */
  19. class Events {
  20. /**
  21. @param {HTMLElement|String} elementOrSelector
  22. The element or selector indicating the element to use as the delegation root.
  23. */
  24. constructor(elementOrSelector) {
  25. this._vent = new Vent(elementOrSelector);
  26. }
  27.  
  28. /**
  29. Add an event listener.
  30.  
  31. @param {String} eventName
  32. The event name to listen for, including optional namespace(s).
  33. @param {String} [selector]
  34. The selector to use for event delegation.
  35. @param {Function} handler
  36. The function that will be called when the event is fired.
  37. @param {Boolean} [useCapture]
  38. Whether or not to listen during the capturing or bubbling phase.
  39. @returns {Events} this, chainable.
  40. */
  41. on(eventName, selector, handler, useCapture) {
  42. this._vent.on(eventName, selector, handler, useCapture);
  43. return this;
  44. }
  45.  
  46. /**
  47. Remove an event listener.
  48.  
  49. @param {String} [eventName]
  50. The event name to stop listening for, including optional namespace(s).
  51. @param {String} [selector]
  52. The selector that was used for event delegation.
  53. @param {Function} [handler]
  54. The function that was passed to <code>on()</code>.
  55. @param {Boolean} [useCapture]
  56. Only remove listeners with <code>useCapture</code> set to the value passed in.
  57. @returns {Event} this, chainable.
  58. */
  59. off(eventName, selector, handler, useCapture) {
  60. this._vent.off(eventName, selector, handler, useCapture);
  61. return this;
  62. }
  63.  
  64. /**
  65. Dispatch a custom event at the root element.
  66.  
  67. @param {String} eventName
  68. The name of the event to dispatch.
  69. @param {Object} [options]
  70. CustomEvent options.
  71. @param {Object} [options.bubbles=true]
  72. Whether the event should bubble.
  73. @param {Object} [options.cancelable=true]
  74. Whether the event should be cancelable.
  75. @param {Object} [options.detail]
  76. Data to pass to handlers as <code>event.detail</code>
  77. @returns {CustomEvent} dispatched event.
  78. */
  79. dispatch(eventName, options) {
  80. return this._vent.dispatch(eventName, options);
  81. }
  82.  
  83. /**
  84. Destroy this instance, removing all events and references.
  85. */
  86. destroy() {
  87. this._vent.destroy();
  88. }
  89.  
  90. /**
  91. * @ignore
  92. * @param {MouseEvent | TouchEvent} event
  93. * @returns {boolean}
  94. * Keyboards, Assistive Technologies, and element.click() all produce a "virtual"
  95. * click event. This is a method of inferring such clicks. Every browser except
  96. * IE 11 only sets a zero value of "detail" for click events that are "virtual".
  97. * However, IE 11 uses a zero value for all click events. For IE 11 we rely on
  98. * the quirk that it produces click events that are of type PointerEvent, and
  99. * where only the "virtual" click lacks a pointerType field.
  100. *
  101. * Original licensing for the following method can be found in the
  102. * NOTICE file in the root directory of this source tree.
  103. * See https://github.com/facebook/react/blob/3c713d513195a53788b3f8bb4b70279d68b15bcc/packages/react-interactions/events/src/dom/shared/index.js#L74-L87
  104. */
  105. isVirtualEvent(event) {
  106. // JAWS/NVDA with Firefox.
  107. if (event.mozInputSource === 0 && event.isTrusted) {
  108. return true;
  109. }
  110.  
  111. // Android TalkBack's detail value varies depending on the event listener providing the event so we have specific logic here instead
  112. // If pointerType is defined, event is from a click listener. For events from mousedown listener, detail === 0 is a sufficient check
  113. // to detect TalkBack virtual clicks.
  114. if (commons.isAndroid() && event.pointerType) {
  115. return event.type === 'click' && event.buttons === 1;
  116. }
  117.  
  118. return event.detail === 0 && !event.pointerType;
  119. }
  120. }
  121.  
  122. /**
  123. An enhanced event helper.
  124.  
  125. @type {Events}
  126. */
  127. const events = new Events(window);
  128.  
  129. export default events;