1
0
mirror of https://github.com/twbs/bootstrap.git synced 2025-02-22 06:39:52 +00:00

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", "path": "./dist/js/bootstrap.js",
"maxSize": "28.25 kB" "maxSize": "28.5 kB"
}, },
{ {
"path": "./dist/js/bootstrap.min.js", "path": "./dist/js/bootstrap.min.js",

View File

@ -74,12 +74,12 @@ const nativeEvents = new Set([
* Private methods * Private methods
*/ */
function getUidEvent(element, uid) { function makeEventUid(element, uid) {
return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++ return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++
} }
function getEvent(element) { function getElementEvents(element) {
const uid = getUidEvent(element) const uid = makeEventUid(element)
element.uidEvent = uid element.uidEvent = uid
eventRegistry[uid] = eventRegistry[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) 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) { function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const delegation = typeof handler === 'string' const isDelegated = typeof handler === 'string'
const originalHandler = delegation ? delegationFunction : handler // todo: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : (handler || delegationFunction)
let typeEvent = getTypeEvent(originalTypeEvent) let typeEvent = getTypeEvent(originalTypeEvent)
if (!nativeEvents.has(typeEvent)) { if (!nativeEvents.has(typeEvent)) {
typeEvent = originalTypeEvent typeEvent = originalTypeEvent
} }
return [delegation, originalHandler, typeEvent] return [isDelegated, callable, typeEvent]
} }
function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) { function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
@ -143,10 +144,7 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
return return
} }
if (!handler) { let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
handler = delegationFunction
delegationFunction = null
}
// in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position // 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 // 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) { callable = wrapFunction(callable)
delegationFunction = wrapFunction(delegationFunction)
} else {
handler = wrapFunction(handler)
}
} }
const [delegation, originalHandler, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction) const events = getElementEvents(element)
const events = getEvent(element)
const handlers = events[typeEvent] || (events[typeEvent] = {}) const handlers = events[typeEvent] || (events[typeEvent] = {})
const previousFunction = findHandler(handlers, originalHandler, delegation ? handler : null) const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)
if (previousFunction) { if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff previousFunction.oneOff = previousFunction.oneOff && oneOff
@ -177,18 +170,18 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
return return
} }
const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, '')) const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))
const fn = delegation ? const fn = isDelegated ?
bootstrapDelegationHandler(element, handler, delegationFunction) : bootstrapDelegationHandler(element, handler, callable) :
bootstrapHandler(element, handler) bootstrapHandler(element, callable)
fn.delegationSelector = delegation ? handler : null fn.delegationSelector = isDelegated ? handler : null
fn.originalHandler = originalHandler fn.callable = callable
fn.oneOff = oneOff fn.oneOff = oneOff
fn.uidEvent = uid fn.uidEvent = uid
handlers[uid] = fn handlers[uid] = fn
element.addEventListener(typeEvent, fn, delegation) element.addEventListener(typeEvent, fn, isDelegated)
} }
function removeHandler(element, events, typeEvent, handler, delegationSelector) { function removeHandler(element, events, typeEvent, handler, delegationSelector) {
@ -208,7 +201,7 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
for (const handlerKey of Object.keys(storeElementEvent)) { for (const handlerKey of Object.keys(storeElementEvent)) {
if (handlerKey.includes(namespace)) { if (handlerKey.includes(namespace)) {
const event = storeElementEvent[handlerKey] 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 return
} }
const [delegation, originalHandler, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction) const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const inNamespace = typeEvent !== originalTypeEvent const inNamespace = typeEvent !== originalTypeEvent
const events = getEvent(element) const events = getElementEvents(element)
const storeElementEvent = events[typeEvent] || {}
const isNamespace = originalTypeEvent.startsWith('.') const isNamespace = originalTypeEvent.startsWith('.')
if (typeof originalHandler !== 'undefined') { if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY. // Simplest case: handler is passed, remove that listener ONLY.
if (!events || !events[typeEvent]) { if (!storeElementEvent) {
return return
} }
removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null) removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
return return
} }
@ -254,13 +248,12 @@ const EventHandler = {
} }
} }
const storeElementEvent = events[typeEvent] || {}
for (const keyHandlers of Object.keys(storeElementEvent)) { for (const keyHandlers of Object.keys(storeElementEvent)) {
const handlerKey = keyHandlers.replace(stripUidRegex, '') const handlerKey = keyHandlers.replace(stripUidRegex, '')
if (!inNamespace || originalTypeEvent.includes(handlerKey)) { if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
const event = storeElementEvent[keyHandlers] 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() defaultPrevented = jQueryEvent.isDefaultPrevented()
} }
const evt = new Event(event, { bubbles, cancelable: true }) let evt = new Event(event, { bubbles, cancelable: true })
evt = hydrateObj(evt, args)
// 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]
}
})
}
}
if (defaultPrevented) { if (defaultPrevented) {
evt.preventDefault() 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 export default EventHandler