pinafore/src/routes/_utils/delegate.js

60 wiersze
1.7 KiB
JavaScript

// Delegate certain events to the global document for perf purposes.
const callbacks = {}
if (process.browser) {
window.__delegateCallbacks = callbacks
}
function onEvent (e) {
const { type, keyCode, target } = e
if (!(type === 'click' || (type === 'keydown' && keyCode === 13))) {
// we're not interested in any non-click or non-Enter events
return
}
let key
let element = target
while (element) {
if ((key = element.getAttribute('id'))) {
break
}
element = element.parentElement
}
if (key && callbacks[key]) {
if (type === 'click') {
const selection = window.getSelection()
const selectionStr = selection && selection.toString()
if (selectionStr && selectionStr.length && target.contains(selection.anchorNode)) {
return // ignore if the user is selecting text inside the clickable area
}
}
const res = callbacks[key](e) // callback returns true to indicate it has handled the action
if (process.env.NODE_ENV !== 'production' && typeof res !== 'boolean') {
console.warn(`Callback returned a non-boolean response: "${key}". This should never happen.`)
}
if (res) {
e.preventDefault()
e.stopPropagation()
}
}
}
export function registerClickDelegates (component, delegates) {
Object.assign(callbacks, delegates)
component.on('destroy', () => {
Object.keys(delegates).forEach(key => {
delete callbacks[key]
})
})
}
export function registerClickDelegate (component, key, callback) {
registerClickDelegates(component, { [key]: callback })
}
if (process.browser) {
document.addEventListener('click', onEvent)
document.addEventListener('keydown', onEvent)
}