2019-03-01 17:31:34 +01:00
/ * !
2022-11-21 19:19:01 +01:00
* Bootstrap event - handler . js v5 . 2.3 ( https : //getbootstrap.com/)
2022-05-13 08:07:23 +02:00
* Copyright 2011 - 2022 The Bootstrap Authors ( https : //github.com/twbs/bootstrap/graphs/contributors)
2020-06-16 20:50:01 +02:00
* Licensed under MIT ( https : //github.com/twbs/bootstrap/blob/main/LICENSE)
2019-03-01 17:31:34 +01:00
* /
( function ( global , factory ) {
2022-05-13 08:07:23 +02:00
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' ;
2019-03-01 17:31:34 +01:00
2021-08-04 17:41:51 +02:00
/ * *
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
2022-11-21 19:19:01 +01:00
* Bootstrap ( v5 . 2.3 ) : dom / event - handler . js
2021-08-04 17:41:51 +02:00
* Licensed under MIT ( https : //github.com/twbs/bootstrap/blob/main/LICENSE)
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
2019-03-01 17:31:34 +01:00
/ * *
* Constants
* /
2021-03-23 17:26:54 +01:00
const namespaceRegex = /[^.]*(?=\..*)\.|.*/ ;
const stripNameRegex = /\..*/ ;
const stripUidRegex = /::\d+$/ ;
const eventRegistry = { } ; // Events storage
2019-03-01 17:31:34 +01:00
2021-03-23 17:26:54 +01:00
let uidEvent = 1 ;
const customEvents = {
2019-03-01 17:31:34 +01:00
mouseenter : 'mouseover' ,
mouseleave : 'mouseout'
} ;
2021-03-23 17:26:54 +01:00
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' ] ) ;
2019-03-01 17:31:34 +01:00
/ * *
* Private methods
* /
2022-07-19 17:43:58 +02:00
function makeEventUid ( element , uid ) {
2021-03-23 17:26:54 +01:00
return uid && ` ${ uid } :: ${ uidEvent ++ } ` || element . uidEvent || uidEvent ++ ;
2019-03-01 17:31:34 +01:00
}
2022-07-19 17:43:58 +02:00
function getElementEvents ( element ) {
const uid = makeEventUid ( element ) ;
2019-03-01 17:31:34 +01:00
element . uidEvent = uid ;
2019-03-11 16:13:30 +01:00
eventRegistry [ uid ] = eventRegistry [ uid ] || { } ;
return eventRegistry [ uid ] ;
2019-03-01 17:31:34 +01:00
}
function bootstrapHandler ( element , fn ) {
return function handler ( event ) {
2022-07-19 17:43:58 +02:00
hydrateObj ( event , {
delegateTarget : element
} ) ;
2020-09-14 17:12:06 +02:00
2019-03-01 17:31:34 +01:00
if ( handler . oneOff ) {
EventHandler . off ( element , event . type , fn ) ;
}
return fn . apply ( element , [ event ] ) ;
} ;
}
function bootstrapDelegationHandler ( element , selector , fn ) {
return function handler ( event ) {
2021-03-23 17:26:54 +01:00
const domElements = element . querySelectorAll ( selector ) ;
2019-03-01 17:31:34 +01:00
2021-03-23 17:26:54 +01:00
for ( let {
target
} = event ; target && target !== this ; target = target . parentNode ) {
2022-05-13 08:07:23 +02:00
for ( const domElement of domElements ) {
if ( domElement !== target ) {
continue ;
}
2020-09-14 17:12:06 +02:00
2022-07-19 17:43:58 +02:00
hydrateObj ( event , {
delegateTarget : target
} ) ;
2019-03-01 17:31:34 +01:00
2022-05-13 08:07:23 +02:00
if ( handler . oneOff ) {
EventHandler . off ( element , event . type , selector , fn ) ;
2019-03-01 17:31:34 +01:00
}
2022-05-13 08:07:23 +02:00
return fn . apply ( target , [ event ] ) ;
}
}
2019-03-01 17:31:34 +01:00
} ;
}
2022-07-19 17:43:58 +02:00
function findHandler ( events , callable , delegationSelector = null ) {
return Object . values ( events ) . find ( event => event . callable === callable && event . delegationSelector === delegationSelector ) ;
2019-03-01 17:31:34 +01:00
}
2022-05-13 08:07:23 +02:00
function normalizeParameters ( originalTypeEvent , handler , delegationFunction ) {
2022-07-19 17:43:58 +02:00
const isDelegated = typeof handler === 'string' ; // todo: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : handler || delegationFunction ;
2021-05-05 21:32:12 +02:00
let typeEvent = getTypeEvent ( originalTypeEvent ) ;
2019-03-01 17:31:34 +01:00
2022-05-13 08:07:23 +02:00
if ( ! nativeEvents . has ( typeEvent ) ) {
2019-03-01 17:31:34 +01:00
typeEvent = originalTypeEvent ;
}
2022-07-19 17:43:58 +02:00
return [ isDelegated , callable , typeEvent ] ;
2019-03-01 17:31:34 +01:00
}
2022-05-13 08:07:23 +02:00
function addHandler ( element , originalTypeEvent , handler , delegationFunction , oneOff ) {
2019-03-01 17:31:34 +01:00
if ( typeof originalTypeEvent !== 'string' || ! element ) {
return ;
}
2022-07-19 17:43:58 +02:00
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
2021-05-05 21:32:12 +02:00
// this prevents the handler from being dispatched the same way as mouseover or mouseout does
2022-05-13 08:07:23 +02:00
if ( originalTypeEvent in customEvents ) {
const wrapFunction = fn => {
2021-05-05 21:32:12 +02:00
return function ( event ) {
if ( ! event . relatedTarget || event . relatedTarget !== event . delegateTarget && ! event . delegateTarget . contains ( event . relatedTarget ) ) {
return fn . call ( this , event ) ;
}
} ;
} ;
2022-07-19 17:43:58 +02:00
callable = wrapFunction ( callable ) ;
2019-03-01 17:31:34 +01:00
}
2022-07-19 17:43:58 +02:00
const events = getElementEvents ( element ) ;
2021-03-23 17:26:54 +01:00
const handlers = events [ typeEvent ] || ( events [ typeEvent ] = { } ) ;
2022-07-19 17:43:58 +02:00
const previousFunction = findHandler ( handlers , callable , isDelegated ? handler : null ) ;
2019-03-01 17:31:34 +01:00
2022-05-13 08:07:23 +02:00
if ( previousFunction ) {
previousFunction . oneOff = previousFunction . oneOff && oneOff ;
2019-03-01 17:31:34 +01:00
return ;
}
2022-07-19 17:43:58 +02:00
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 ;
2019-03-01 17:31:34 +01:00
fn . oneOff = oneOff ;
fn . uidEvent = uid ;
handlers [ uid ] = fn ;
2022-07-19 17:43:58 +02:00
element . addEventListener ( typeEvent , fn , isDelegated ) ;
2019-03-01 17:31:34 +01:00
}
function removeHandler ( element , events , typeEvent , handler , delegationSelector ) {
2021-03-23 17:26:54 +01:00
const fn = findHandler ( events [ typeEvent ] , handler , delegationSelector ) ;
2019-03-01 17:31:34 +01:00
2019-07-12 23:56:26 +02:00
if ( ! fn ) {
2019-03-01 17:31:34 +01:00
return ;
}
element . removeEventListener ( typeEvent , fn , Boolean ( delegationSelector ) ) ;
delete events [ typeEvent ] [ fn . uidEvent ] ;
}
function removeNamespacedHandlers ( element , events , typeEvent , namespace ) {
2021-03-23 17:26:54 +01:00
const storeElementEvent = events [ typeEvent ] || { } ;
2022-05-13 08:07:23 +02:00
for ( const handlerKey of Object . keys ( storeElementEvent ) ) {
2020-11-23 14:17:16 +01:00
if ( handlerKey . includes ( namespace ) ) {
2021-03-23 17:26:54 +01:00
const event = storeElementEvent [ handlerKey ] ;
2022-07-19 17:43:58 +02:00
removeHandler ( element , events , typeEvent , event . callable , event . delegationSelector ) ;
2019-03-01 17:31:34 +01:00
}
2022-05-13 08:07:23 +02:00
}
2019-03-01 17:31:34 +01:00
}
2021-05-05 21:32:12 +02:00
function getTypeEvent ( event ) {
// allow to get the native events from namespaced events ('click.bs.button' --> 'click')
event = event . replace ( stripNameRegex , '' ) ;
return customEvents [ event ] || event ;
}
2021-03-23 17:26:54 +01:00
const EventHandler = {
2022-05-13 08:07:23 +02:00
on ( element , event , handler , delegationFunction ) {
addHandler ( element , event , handler , delegationFunction , false ) ;
2019-03-01 17:31:34 +01:00
} ,
2021-03-23 17:26:54 +01:00
2022-05-13 08:07:23 +02:00
one ( element , event , handler , delegationFunction ) {
addHandler ( element , event , handler , delegationFunction , true ) ;
2019-03-01 17:31:34 +01:00
} ,
2021-03-23 17:26:54 +01:00
2022-05-13 08:07:23 +02:00
off ( element , originalTypeEvent , handler , delegationFunction ) {
2019-03-01 17:31:34 +01:00
if ( typeof originalTypeEvent !== 'string' || ! element ) {
return ;
}
2022-07-19 17:43:58 +02:00
const [ isDelegated , callable , typeEvent ] = normalizeParameters ( originalTypeEvent , handler , delegationFunction ) ;
2021-03-23 17:26:54 +01:00
const inNamespace = typeEvent !== originalTypeEvent ;
2022-07-19 17:43:58 +02:00
const events = getElementEvents ( element ) ;
const storeElementEvent = events [ typeEvent ] || { } ;
2021-03-23 17:26:54 +01:00
const isNamespace = originalTypeEvent . startsWith ( '.' ) ;
2019-03-01 17:31:34 +01:00
2022-07-19 17:43:58 +02:00
if ( typeof callable !== 'undefined' ) {
2019-03-01 17:31:34 +01:00
// Simplest case: handler is passed, remove that listener ONLY.
2022-07-19 17:43:58 +02:00
if ( ! Object . keys ( storeElementEvent ) . length ) {
2019-03-01 17:31:34 +01:00
return ;
}
2022-07-19 17:43:58 +02:00
removeHandler ( element , events , typeEvent , callable , isDelegated ? handler : null ) ;
2019-03-01 17:31:34 +01:00
return ;
}
if ( isNamespace ) {
2022-05-13 08:07:23 +02:00
for ( const elementEvent of Object . keys ( events ) ) {
2019-10-08 08:39:10 +02:00
removeNamespacedHandlers ( element , events , elementEvent , originalTypeEvent . slice ( 1 ) ) ;
2022-05-13 08:07:23 +02:00
}
2019-03-01 17:31:34 +01:00
}
2022-05-13 08:07:23 +02:00
for ( const keyHandlers of Object . keys ( storeElementEvent ) ) {
2021-03-23 17:26:54 +01:00
const handlerKey = keyHandlers . replace ( stripUidRegex , '' ) ;
2019-03-01 17:31:34 +01:00
2020-11-23 14:17:16 +01:00
if ( ! inNamespace || originalTypeEvent . includes ( handlerKey ) ) {
2021-03-23 17:26:54 +01:00
const event = storeElementEvent [ keyHandlers ] ;
2022-07-19 17:43:58 +02:00
removeHandler ( element , events , typeEvent , event . callable , event . delegationSelector ) ;
2019-03-01 17:31:34 +01:00
}
2022-05-13 08:07:23 +02:00
}
2019-03-01 17:31:34 +01:00
} ,
2021-03-23 17:26:54 +01:00
trigger ( element , event , args ) {
2019-03-01 17:31:34 +01:00
if ( typeof event !== 'string' || ! element ) {
return null ;
}
2022-05-13 08:07:23 +02:00
const $ = index . getjQuery ( ) ;
2021-05-05 21:32:12 +02:00
const typeEvent = getTypeEvent ( event ) ;
2021-03-23 17:26:54 +01:00
const inNamespace = event !== typeEvent ;
2022-05-13 08:07:23 +02:00
let jQueryEvent = null ;
2021-03-23 17:26:54 +01:00
let bubbles = true ;
let nativeDispatch = true ;
let defaultPrevented = false ;
2019-03-01 17:31:34 +01:00
2019-08-27 15:03:21 +02:00
if ( inNamespace && $ ) {
jQueryEvent = $ . Event ( event , args ) ;
$ ( element ) . trigger ( jQueryEvent ) ;
2019-03-01 17:31:34 +01:00
bubbles = ! jQueryEvent . isPropagationStopped ( ) ;
nativeDispatch = ! jQueryEvent . isImmediatePropagationStopped ( ) ;
defaultPrevented = jQueryEvent . isDefaultPrevented ( ) ;
}
2022-07-19 17:43:58 +02:00
let evt = new Event ( event , {
2022-05-13 08:07:23 +02:00
bubbles ,
cancelable : true
2022-07-19 17:43:58 +02:00
} ) ;
evt = hydrateObj ( evt , args ) ;
2019-03-01 17:31:34 +01:00
if ( defaultPrevented ) {
evt . preventDefault ( ) ;
}
if ( nativeDispatch ) {
element . dispatchEvent ( evt ) ;
}
2022-05-13 08:07:23 +02:00
if ( evt . defaultPrevented && jQueryEvent ) {
2019-03-01 17:31:34 +01:00
jQueryEvent . preventDefault ( ) ;
}
return evt ;
}
2021-03-23 17:26:54 +01:00
2019-03-01 17:31:34 +01:00
} ;
2022-07-19 17:43:58 +02:00
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 ;
}
2019-03-01 17:31:34 +01:00
return EventHandler ;
2021-10-05 17:50:18 +02:00
} ) ) ;
2019-05-08 15:11:24 +02:00
//# sourceMappingURL=event-handler.js.map