forked from vikunja/frontend
Dominik Pschenitschni
e779681905
- vue3-notification - vue-advanced-cropper 2 - vuedraggable 4 - vue-shortkey -> moved in repo
187 lines
4.1 KiB
JavaScript
187 lines
4.1 KiB
JavaScript
import { parseValue, decodeKey, encodeKey } from './helpers'
|
|
|
|
let mapFunctions = {}
|
|
let objAvoided = []
|
|
let elementAvoided = []
|
|
let keyPressed = false
|
|
|
|
function dispatchShortkeyEvent(pKey) {
|
|
const e = new CustomEvent('shortkey', { bubbles: false })
|
|
|
|
if (mapFunctions[pKey].key) {
|
|
e.srcKey = mapFunctions[pKey].key
|
|
}
|
|
|
|
const elm = mapFunctions[pKey].el
|
|
|
|
if (!mapFunctions[pKey].propagte) {
|
|
elm[elm.length - 1].dispatchEvent(e)
|
|
} else {
|
|
elm.forEach((elmItem) => elmItem.dispatchEvent(e))
|
|
}
|
|
}
|
|
|
|
function keyDown(pKey) {
|
|
if (
|
|
(!mapFunctions[pKey].once && !mapFunctions[pKey].push) ||
|
|
(mapFunctions[pKey].push && !keyPressed)
|
|
) {
|
|
dispatchShortkeyEvent(pKey)
|
|
}
|
|
}
|
|
|
|
function fillMappingFunctions(
|
|
mappingFunctions,
|
|
{ b, push, once, focus, propagte, el },
|
|
) {
|
|
for (let key in b) {
|
|
const k = encodeKey(b[key])
|
|
const propagated = mappingFunctions[k] && mappingFunctions[k].propagte
|
|
const elm =
|
|
mappingFunctions[k] && mappingFunctions[k].el
|
|
? mappingFunctions[k].el
|
|
: []
|
|
|
|
elm.push(el)
|
|
|
|
mappingFunctions[k] = {
|
|
push,
|
|
once,
|
|
focus,
|
|
key,
|
|
propagte: propagated || propagte,
|
|
el: elm,
|
|
}
|
|
}
|
|
}
|
|
|
|
function bindValue(value, el, binding, vnode) {
|
|
const { modifiers } = binding
|
|
const push = !!modifiers.push
|
|
const avoid = !!modifiers.avoid
|
|
const focus = !modifiers.focus
|
|
const once = !!modifiers.once
|
|
const propagte = !!modifiers.propagte
|
|
|
|
if (avoid) {
|
|
objAvoided = objAvoided.filter((itm) => !itm === el)
|
|
objAvoided.push(el)
|
|
} else {
|
|
fillMappingFunctions(mapFunctions, {
|
|
b: value,
|
|
push,
|
|
once,
|
|
focus,
|
|
propagte,
|
|
el: vnode.el,
|
|
})
|
|
}
|
|
}
|
|
|
|
function unbindValue(value, el) {
|
|
for (let key in value) {
|
|
const k = encodeKey(value[key])
|
|
const idxElm = mapFunctions[k].el.indexOf(el)
|
|
|
|
if (mapFunctions[k].el.length > 1 && idxElm > -1) {
|
|
mapFunctions[k].el.splice(idxElm, 1)
|
|
} else {
|
|
delete mapFunctions[k]
|
|
}
|
|
}
|
|
}
|
|
|
|
function availableElement(decodedKey) {
|
|
const objectIsAvoided = !!objAvoided.find(
|
|
(r) => r === document.activeElement,
|
|
)
|
|
const filterAvoided = !!elementAvoided.find(
|
|
(selector) =>
|
|
document.activeElement && document.activeElement.matches(selector),
|
|
)
|
|
return !!mapFunctions[decodedKey] && !(objectIsAvoided || filterAvoided)
|
|
}
|
|
|
|
function keyDownListener(pKey) {
|
|
const decodedKey = decodeKey(pKey)
|
|
|
|
// Check avoidable elements
|
|
if (!availableElement(decodedKey)) {
|
|
return
|
|
}
|
|
|
|
if (!mapFunctions[decodedKey].propagte) {
|
|
pKey.preventDefault()
|
|
pKey.stopPropagation()
|
|
}
|
|
|
|
if (mapFunctions[decodedKey].focus) {
|
|
keyDown(decodedKey)
|
|
keyPressed = true
|
|
} else if (!keyPressed) {
|
|
const elm = mapFunctions[decodedKey].el
|
|
elm[elm.length - 1].focus()
|
|
keyPressed = true
|
|
}
|
|
}
|
|
|
|
function keyUpListener(pKey) {
|
|
const decodedKey = decodeKey(pKey)
|
|
|
|
if (!availableElement(decodedKey)) {
|
|
keyPressed = false
|
|
return
|
|
}
|
|
|
|
if (!mapFunctions[decodedKey].propagte) {
|
|
pKey.preventDefault()
|
|
pKey.stopPropagation()
|
|
}
|
|
|
|
if (mapFunctions[decodedKey].once || mapFunctions[decodedKey].push) {
|
|
dispatchShortkeyEvent(decodedKey)
|
|
}
|
|
|
|
keyPressed = false
|
|
}
|
|
|
|
// register key presses that happen before mounting of directive
|
|
// if (process?.env?.NODE_ENV !== 'test') {
|
|
// (() => {
|
|
document.addEventListener('keydown', keyDownListener, true)
|
|
document.addEventListener('keyup', keyUpListener, true)
|
|
// })()
|
|
// }
|
|
|
|
function install(app, options) {
|
|
elementAvoided = [...(options && options.prevent ? options.prevent : [])]
|
|
|
|
app.directive('shortkey', {
|
|
beforeMount(el, binding, vnode) {
|
|
// Mapping the commands
|
|
const value = parseValue(binding.value)
|
|
bindValue(value, el, binding, vnode)
|
|
},
|
|
|
|
updated(el, binding, vnode) {
|
|
const oldValue = parseValue(binding.oldValue)
|
|
unbindValue(oldValue, el)
|
|
|
|
const newValue = parseValue(binding.value)
|
|
bindValue(newValue, el, binding, vnode)
|
|
},
|
|
|
|
unmounted(el, binding) {
|
|
const value = parseValue(binding.value)
|
|
unbindValue(value, el)
|
|
},
|
|
})
|
|
}
|
|
|
|
export default {
|
|
install,
|
|
encodeKey,
|
|
decodeKey,
|
|
keyDown,
|
|
}
|