Assorted Event handler patches (#36171)

* EventHandler: rename functions & variables

* EventHandler: export event hydration to function

* EventHandler: rename variable

* EventHandler: simplify checks and make use of one variable

Move check of falsie delegated-selector, caused by tooltip.js

* EventHandler: more renaming

* Update event-handler.js

* bump bunldewatch

Co-authored-by: XhmikosR <xhmikosr@gmail.com>
This commit is contained in:
GeoSot 2022-05-16 17:59:50 +03:00 committed by GitHub
parent da541014cb
commit b5a956781f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 48 deletions

View File

@ -50,7 +50,7 @@
},
{
"path": "./dist/js/bootstrap.js",
"maxSize": "28.25 kB"
"maxSize": "28.5 kB"
},
{
"path": "./dist/js/bootstrap.min.js",

View File

@ -74,12 +74,12 @@ const nativeEvents = new Set([
* Private methods
*/
function getUidEvent(element, uid) {
function makeEventUid(element, uid) {
return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++
}
function getEvent(element) {
const uid = getUidEvent(element)
function getElementEvents(element) {
const uid = makeEventUid(element)
element.uidEvent = uid
eventRegistry[uid] = eventRegistry[uid] || {}
@ -121,21 +121,22 @@ function bootstrapDelegationHandler(element, selector, fn) {
}
}
function findHandler(events, handler, delegationSelector = null) {
function findHandler(events, callable, delegationSelector = null) {
return Object.values(events)
.find(event => event.originalHandler === handler && event.delegationSelector === delegationSelector)
.find(event => event.callable === callable && event.delegationSelector === delegationSelector)
}
function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const delegation = typeof handler === 'string'
const originalHandler = delegation ? delegationFunction : handler
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 [delegation, originalHandler, typeEvent]
return [isDelegated, callable, typeEvent]
}
function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
@ -143,10 +144,7 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
return
}
if (!handler) {
handler = delegationFunction
delegationFunction = null
}
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
@ -159,17 +157,12 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
}
}
if (delegationFunction) {
delegationFunction = wrapFunction(delegationFunction)
} else {
handler = wrapFunction(handler)
}
callable = wrapFunction(callable)
}
const [delegation, originalHandler, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const events = getEvent(element)
const events = getElementEvents(element)
const handlers = events[typeEvent] || (events[typeEvent] = {})
const previousFunction = findHandler(handlers, originalHandler, delegation ? handler : null)
const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)
if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff
@ -177,18 +170,18 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
return
}
const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''))
const fn = delegation ?
bootstrapDelegationHandler(element, handler, delegationFunction) :
bootstrapHandler(element, handler)
const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))
const fn = isDelegated ?
bootstrapDelegationHandler(element, handler, callable) :
bootstrapHandler(element, callable)
fn.delegationSelector = delegation ? handler : null
fn.originalHandler = originalHandler
fn.delegationSelector = isDelegated ? handler : null
fn.callable = callable
fn.oneOff = oneOff
fn.uidEvent = uid
handlers[uid] = fn
element.addEventListener(typeEvent, fn, delegation)
element.addEventListener(typeEvent, fn, isDelegated)
}
function removeHandler(element, events, typeEvent, handler, delegationSelector) {
@ -208,7 +201,7 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
for (const handlerKey of Object.keys(storeElementEvent)) {
if (handlerKey.includes(namespace)) {
const event = storeElementEvent[handlerKey]
removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
}
@ -233,18 +226,19 @@ const EventHandler = {
return
}
const [delegation, originalHandler, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const inNamespace = typeEvent !== originalTypeEvent
const events = getEvent(element)
const events = getElementEvents(element)
const storeElementEvent = events[typeEvent] || {}
const isNamespace = originalTypeEvent.startsWith('.')
if (typeof originalHandler !== 'undefined') {
if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY.
if (!events || !events[typeEvent]) {
if (!storeElementEvent) {
return
}
removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
return
}
@ -254,13 +248,12 @@ const EventHandler = {
}
}
const storeElementEvent = events[typeEvent] || {}
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.originalHandler, event.delegationSelector)
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
},
@ -288,18 +281,8 @@ const EventHandler = {
defaultPrevented = jQueryEvent.isDefaultPrevented()
}
const evt = new Event(event, { bubbles, cancelable: true })
// merge custom information in our event
if (typeof args !== 'undefined') {
for (const key of Object.keys(args)) {
Object.defineProperty(evt, key, {
get() {
return args[key]
}
})
}
}
let evt = new Event(event, { bubbles, cancelable: true })
evt = hydrateObj(evt, args)
if (defaultPrevented) {
evt.preventDefault()
@ -317,4 +300,16 @@ const EventHandler = {
}
}
function hydrateObj(obj, meta) {
for (const [key, value] of Object.entries(meta || {})) {
Object.defineProperty(obj, key, {
get() {
return value
}
})
}
return obj
}
export default EventHandler