| /*! |
| * Bootstrap event-handler.js v5.2.1 (https://getbootstrap.com/) |
| * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| */ |
| (function (global, factory) { |
| typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../util/index')) : |
| typeof define === 'function' && define.amd ? define(['../util/index'], factory) : |
| (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.EventHandler = factory(global.Index)); |
| })(this, (function (index) { 'use strict'; |
| |
| /** |
| * -------------------------------------------------------------------------- |
| * Bootstrap (v5.2.1): dom/event-handler.js |
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) |
| * -------------------------------------------------------------------------- |
| */ |
| /** |
| * Constants |
| */ |
| |
| const namespaceRegex = /[^.]*(?=\..*)\.|.*/; |
| const stripNameRegex = /\..*/; |
| const stripUidRegex = /::\d+$/; |
| const eventRegistry = {}; // Events storage |
| |
| let uidEvent = 1; |
| const customEvents = { |
| mouseenter: 'mouseover', |
| mouseleave: 'mouseout' |
| }; |
| 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']); |
| /** |
| * Private methods |
| */ |
| |
| function makeEventUid(element, uid) { |
| return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; |
| } |
| |
| function getElementEvents(element) { |
| const uid = makeEventUid(element); |
| element.uidEvent = uid; |
| eventRegistry[uid] = eventRegistry[uid] || {}; |
| return eventRegistry[uid]; |
| } |
| |
| function bootstrapHandler(element, fn) { |
| return function handler(event) { |
| hydrateObj(event, { |
| delegateTarget: element |
| }); |
| |
| if (handler.oneOff) { |
| EventHandler.off(element, event.type, fn); |
| } |
| |
| return fn.apply(element, [event]); |
| }; |
| } |
| |
| function bootstrapDelegationHandler(element, selector, fn) { |
| return function handler(event) { |
| const domElements = element.querySelectorAll(selector); |
| |
| for (let { |
| target |
| } = event; target && target !== this; target = target.parentNode) { |
| for (const domElement of domElements) { |
| if (domElement !== target) { |
| continue; |
| } |
| |
| hydrateObj(event, { |
| delegateTarget: target |
| }); |
| |
| if (handler.oneOff) { |
| EventHandler.off(element, event.type, selector, fn); |
| } |
| |
| return fn.apply(target, [event]); |
| } |
| } |
| }; |
| } |
| |
| function findHandler(events, callable, delegationSelector = null) { |
| return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector); |
| } |
| |
| function normalizeParameters(originalTypeEvent, handler, delegationFunction) { |
| const isDelegated = typeof handler === 'string'; // todo: tooltip passes `false` instead of selector, so we need to check |
| |
| const callable = isDelegated ? delegationFunction : handler || delegationFunction; |
| let typeEvent = getTypeEvent(originalTypeEvent); |
| |
| if (!nativeEvents.has(typeEvent)) { |
| typeEvent = originalTypeEvent; |
| } |
| |
| return [isDelegated, callable, typeEvent]; |
| } |
| |
| function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) { |
| if (typeof originalTypeEvent !== 'string' || !element) { |
| return; |
| } |
| |
| let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position |
| // this prevents the handler from being dispatched the same way as mouseover or mouseout does |
| |
| if (originalTypeEvent in customEvents) { |
| const wrapFunction = fn => { |
| return function (event) { |
| if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { |
| return fn.call(this, event); |
| } |
| }; |
| }; |
| |
| callable = wrapFunction(callable); |
| } |
| |
| const events = getElementEvents(element); |
| const handlers = events[typeEvent] || (events[typeEvent] = {}); |
| const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null); |
| |
| if (previousFunction) { |
| previousFunction.oneOff = previousFunction.oneOff && oneOff; |
| return; |
| } |
| |
| const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, '')); |
| const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable); |
| fn.delegationSelector = isDelegated ? handler : null; |
| fn.callable = callable; |
| fn.oneOff = oneOff; |
| fn.uidEvent = uid; |
| handlers[uid] = fn; |
| element.addEventListener(typeEvent, fn, isDelegated); |
| } |
| |
| function removeHandler(element, events, typeEvent, handler, delegationSelector) { |
| const fn = findHandler(events[typeEvent], handler, delegationSelector); |
| |
| if (!fn) { |
| return; |
| } |
| |
| element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); |
| delete events[typeEvent][fn.uidEvent]; |
| } |
| |
| function removeNamespacedHandlers(element, events, typeEvent, namespace) { |
| const storeElementEvent = events[typeEvent] || {}; |
| |
| for (const handlerKey of Object.keys(storeElementEvent)) { |
| if (handlerKey.includes(namespace)) { |
| const event = storeElementEvent[handlerKey]; |
| removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); |
| } |
| } |
| } |
| |
| function getTypeEvent(event) { |
| // allow to get the native events from namespaced events ('click.bs.button' --> 'click') |
| event = event.replace(stripNameRegex, ''); |
| return customEvents[event] || event; |
| } |
| |
| const EventHandler = { |
| on(element, event, handler, delegationFunction) { |
| addHandler(element, event, handler, delegationFunction, false); |
| }, |
| |
| one(element, event, handler, delegationFunction) { |
| addHandler(element, event, handler, delegationFunction, true); |
| }, |
| |
| off(element, originalTypeEvent, handler, delegationFunction) { |
| if (typeof originalTypeEvent !== 'string' || !element) { |
| return; |
| } |
| |
| const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); |
| const inNamespace = typeEvent !== originalTypeEvent; |
| const events = getElementEvents(element); |
| const storeElementEvent = events[typeEvent] || {}; |
| const isNamespace = originalTypeEvent.startsWith('.'); |
| |
| if (typeof callable !== 'undefined') { |
| // Simplest case: handler is passed, remove that listener ONLY. |
| if (!Object.keys(storeElementEvent).length) { |
| return; |
| } |
| |
| removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null); |
| return; |
| } |
| |
| if (isNamespace) { |
| for (const elementEvent of Object.keys(events)) { |
| removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); |
| } |
| } |
| |
| for (const keyHandlers of Object.keys(storeElementEvent)) { |
| const handlerKey = keyHandlers.replace(stripUidRegex, ''); |
| |
| if (!inNamespace || originalTypeEvent.includes(handlerKey)) { |
| const event = storeElementEvent[keyHandlers]; |
| removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); |
| } |
| } |
| }, |
| |
| trigger(element, event, args) { |
| if (typeof event !== 'string' || !element) { |
| return null; |
| } |
| |
| const $ = index.getjQuery(); |
| const typeEvent = getTypeEvent(event); |
| const inNamespace = event !== typeEvent; |
| let jQueryEvent = null; |
| let bubbles = true; |
| let nativeDispatch = true; |
| let defaultPrevented = false; |
| |
| if (inNamespace && $) { |
| jQueryEvent = $.Event(event, args); |
| $(element).trigger(jQueryEvent); |
| bubbles = !jQueryEvent.isPropagationStopped(); |
| nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); |
| defaultPrevented = jQueryEvent.isDefaultPrevented(); |
| } |
| |
| let evt = new Event(event, { |
| bubbles, |
| cancelable: true |
| }); |
| evt = hydrateObj(evt, args); |
| |
| if (defaultPrevented) { |
| evt.preventDefault(); |
| } |
| |
| if (nativeDispatch) { |
| element.dispatchEvent(evt); |
| } |
| |
| if (evt.defaultPrevented && jQueryEvent) { |
| jQueryEvent.preventDefault(); |
| } |
| |
| return evt; |
| } |
| |
| }; |
| |
| function hydrateObj(obj, meta) { |
| for (const [key, value] of Object.entries(meta || {})) { |
| try { |
| obj[key] = value; |
| } catch (_unused) { |
| Object.defineProperty(obj, key, { |
| configurable: true, |
| |
| get() { |
| return value; |
| } |
| |
| }); |
| } |
| } |
| |
| return obj; |
| } |
| |
| return EventHandler; |
| |
| })); |
| //# sourceMappingURL=event-handler.js.map |