You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
10 KiB

  1. /*!
  2. * Bootstrap event-handler.js v5.1.3 (https://getbootstrap.com/)
  3. * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  8. typeof define === 'function' && define.amd ? define(factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.EventHandler = factory());
  10. })(this, (function () { 'use strict';
  11. /**
  12. * --------------------------------------------------------------------------
  13. * Bootstrap (v5.1.3): util/index.js
  14. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  15. * --------------------------------------------------------------------------
  16. */
  17. const getjQuery = () => {
  18. const {
  19. jQuery
  20. } = window;
  21. if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
  22. return jQuery;
  23. }
  24. return null;
  25. };
  26. /**
  27. * --------------------------------------------------------------------------
  28. * Bootstrap (v5.1.3): dom/event-handler.js
  29. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  30. * --------------------------------------------------------------------------
  31. */
  32. /**
  33. * ------------------------------------------------------------------------
  34. * Constants
  35. * ------------------------------------------------------------------------
  36. */
  37. const namespaceRegex = /[^.]*(?=\..*)\.|.*/;
  38. const stripNameRegex = /\..*/;
  39. const stripUidRegex = /::\d+$/;
  40. const eventRegistry = {}; // Events storage
  41. let uidEvent = 1;
  42. const customEvents = {
  43. mouseenter: 'mouseover',
  44. mouseleave: 'mouseout'
  45. };
  46. const customEventsRegex = /^(mouseenter|mouseleave)/i;
  47. const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']);
  48. /**
  49. * ------------------------------------------------------------------------
  50. * Private methods
  51. * ------------------------------------------------------------------------
  52. */
  53. function getUidEvent(element, uid) {
  54. return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++;
  55. }
  56. function getEvent(element) {
  57. const uid = getUidEvent(element);
  58. element.uidEvent = uid;
  59. eventRegistry[uid] = eventRegistry[uid] || {};
  60. return eventRegistry[uid];
  61. }
  62. function bootstrapHandler(element, fn) {
  63. return function handler(event) {
  64. event.delegateTarget = element;
  65. if (handler.oneOff) {
  66. EventHandler.off(element, event.type, fn);
  67. }
  68. return fn.apply(element, [event]);
  69. };
  70. }
  71. function bootstrapDelegationHandler(element, selector, fn) {
  72. return function handler(event) {
  73. const domElements = element.querySelectorAll(selector);
  74. for (let {
  75. target
  76. } = event; target && target !== this; target = target.parentNode) {
  77. for (let i = domElements.length; i--;) {
  78. if (domElements[i] === target) {
  79. event.delegateTarget = target;
  80. if (handler.oneOff) {
  81. EventHandler.off(element, event.type, selector, fn);
  82. }
  83. return fn.apply(target, [event]);
  84. }
  85. }
  86. } // To please ESLint
  87. return null;
  88. };
  89. }
  90. function findHandler(events, handler, delegationSelector = null) {
  91. const uidEventList = Object.keys(events);
  92. for (let i = 0, len = uidEventList.length; i < len; i++) {
  93. const event = events[uidEventList[i]];
  94. if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {
  95. return event;
  96. }
  97. }
  98. return null;
  99. }
  100. function normalizeParams(originalTypeEvent, handler, delegationFn) {
  101. const delegation = typeof handler === 'string';
  102. const originalHandler = delegation ? delegationFn : handler;
  103. let typeEvent = getTypeEvent(originalTypeEvent);
  104. const isNative = nativeEvents.has(typeEvent);
  105. if (!isNative) {
  106. typeEvent = originalTypeEvent;
  107. }
  108. return [delegation, originalHandler, typeEvent];
  109. }
  110. function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {
  111. if (typeof originalTypeEvent !== 'string' || !element) {
  112. return;
  113. }
  114. if (!handler) {
  115. handler = delegationFn;
  116. delegationFn = null;
  117. } // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
  118. // this prevents the handler from being dispatched the same way as mouseover or mouseout does
  119. if (customEventsRegex.test(originalTypeEvent)) {
  120. const wrapFn = fn => {
  121. return function (event) {
  122. if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) {
  123. return fn.call(this, event);
  124. }
  125. };
  126. };
  127. if (delegationFn) {
  128. delegationFn = wrapFn(delegationFn);
  129. } else {
  130. handler = wrapFn(handler);
  131. }
  132. }
  133. const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn);
  134. const events = getEvent(element);
  135. const handlers = events[typeEvent] || (events[typeEvent] = {});
  136. const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null);
  137. if (previousFn) {
  138. previousFn.oneOff = previousFn.oneOff && oneOff;
  139. return;
  140. }
  141. const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''));
  142. const fn = delegation ? bootstrapDelegationHandler(element, handler, delegationFn) : bootstrapHandler(element, handler);
  143. fn.delegationSelector = delegation ? handler : null;
  144. fn.originalHandler = originalHandler;
  145. fn.oneOff = oneOff;
  146. fn.uidEvent = uid;
  147. handlers[uid] = fn;
  148. element.addEventListener(typeEvent, fn, delegation);
  149. }
  150. function removeHandler(element, events, typeEvent, handler, delegationSelector) {
  151. const fn = findHandler(events[typeEvent], handler, delegationSelector);
  152. if (!fn) {
  153. return;
  154. }
  155. element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));
  156. delete events[typeEvent][fn.uidEvent];
  157. }
  158. function removeNamespacedHandlers(element, events, typeEvent, namespace) {
  159. const storeElementEvent = events[typeEvent] || {};
  160. Object.keys(storeElementEvent).forEach(handlerKey => {
  161. if (handlerKey.includes(namespace)) {
  162. const event = storeElementEvent[handlerKey];
  163. removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector);
  164. }
  165. });
  166. }
  167. function getTypeEvent(event) {
  168. // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
  169. event = event.replace(stripNameRegex, '');
  170. return customEvents[event] || event;
  171. }
  172. const EventHandler = {
  173. on(element, event, handler, delegationFn) {
  174. addHandler(element, event, handler, delegationFn, false);
  175. },
  176. one(element, event, handler, delegationFn) {
  177. addHandler(element, event, handler, delegationFn, true);
  178. },
  179. off(element, originalTypeEvent, handler, delegationFn) {
  180. if (typeof originalTypeEvent !== 'string' || !element) {
  181. return;
  182. }
  183. const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn);
  184. const inNamespace = typeEvent !== originalTypeEvent;
  185. const events = getEvent(element);
  186. const isNamespace = originalTypeEvent.startsWith('.');
  187. if (typeof originalHandler !== 'undefined') {
  188. // Simplest case: handler is passed, remove that listener ONLY.
  189. if (!events || !events[typeEvent]) {
  190. return;
  191. }
  192. removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null);
  193. return;
  194. }
  195. if (isNamespace) {
  196. Object.keys(events).forEach(elementEvent => {
  197. removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));
  198. });
  199. }
  200. const storeElementEvent = events[typeEvent] || {};
  201. Object.keys(storeElementEvent).forEach(keyHandlers => {
  202. const handlerKey = keyHandlers.replace(stripUidRegex, '');
  203. if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
  204. const event = storeElementEvent[keyHandlers];
  205. removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector);
  206. }
  207. });
  208. },
  209. trigger(element, event, args) {
  210. if (typeof event !== 'string' || !element) {
  211. return null;
  212. }
  213. const $ = getjQuery();
  214. const typeEvent = getTypeEvent(event);
  215. const inNamespace = event !== typeEvent;
  216. const isNative = nativeEvents.has(typeEvent);
  217. let jQueryEvent;
  218. let bubbles = true;
  219. let nativeDispatch = true;
  220. let defaultPrevented = false;
  221. let evt = null;
  222. if (inNamespace && $) {
  223. jQueryEvent = $.Event(event, args);
  224. $(element).trigger(jQueryEvent);
  225. bubbles = !jQueryEvent.isPropagationStopped();
  226. nativeDispatch = !jQueryEvent.isImmediatePropagationStopped();
  227. defaultPrevented = jQueryEvent.isDefaultPrevented();
  228. }
  229. if (isNative) {
  230. evt = document.createEvent('HTMLEvents');
  231. evt.initEvent(typeEvent, bubbles, true);
  232. } else {
  233. evt = new CustomEvent(event, {
  234. bubbles,
  235. cancelable: true
  236. });
  237. } // merge custom information in our event
  238. if (typeof args !== 'undefined') {
  239. Object.keys(args).forEach(key => {
  240. Object.defineProperty(evt, key, {
  241. get() {
  242. return args[key];
  243. }
  244. });
  245. });
  246. }
  247. if (defaultPrevented) {
  248. evt.preventDefault();
  249. }
  250. if (nativeDispatch) {
  251. element.dispatchEvent(evt);
  252. }
  253. if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {
  254. jQueryEvent.preventDefault();
  255. }
  256. return evt;
  257. }
  258. };
  259. return EventHandler;
  260. }));
  261. //# sourceMappingURL=event-handler.js.map