UNPKG

accesskey-js

Version:

Easily and quickly assign shortcut keys to your web applications.

182 lines (151 loc) 5.5 kB
export default function accesskey() { const config = { handler: (event, element, context) => { element.click(); }, splitter: '+', }; const handlers = {}; function setGlobalSplitter(splitter) { config.splitter = splitter; return this; } function registerHandler(name, fn) { handlers[name] = fn; return this; } function getRegisteredHandler(name) { return handlers[name] || null; }; function isDescendantOfInternalContext(element) { let current = element.parentElement; while (current) { if (current.hasAttribute('accesskey-context')) { return current; } current = current.parentElement; } return false; }; function getKeyDef(context, element) { let splitted = element.accessKey.split(getSplitterToElement(context, element)); let def = { key: null, ctrl: false, shift: false, alt: false, meta: false, }; splitted.forEach(key => { switch (key.toLowerCase()) { case 'ctrl': def.ctrl = true; break; case 'shift': def.shift = true; break; case 'alt': def.alt = true; break; case 'meta': def.meta = true; break; default: def.key = key.toUpperCase(); break; } }); return def; } function init() { getContexts().forEach(context => { let elements = context.querySelectorAll(':scope [accesskey]'); elements.forEach(element => { if (context === isDescendantOfInternalContext(element)) { if (!ignoreAccessKey(context, element)) { context.addEventListener('keydown', (event) => { let keyDef = getKeyDef(context, element); if (event.key.toUpperCase() === keyDef.key && event.ctrlKey === keyDef.ctrl && event.shiftKey === keyDef.shift && event.altKey === keyDef.alt && event.metaKey === keyDef.meta) { if (stopPropagation(context, element)) { event.stopPropagation(); } if (preventDefault(context, element)) { event.preventDefault(); } getHandlerToElement(context, element)(event, element, context); } }); } } }); }); } function ignoreAccessKey(context, element) { if (element.hasAttribute('accesskey-ignore')) { return true; } if (context.hasAttribute('accesskey-ignore')) { return true; } return false; } function stopPropagation(context, element) { if (element.hasAttribute('accesskey-no-stop-propagation')) { return false; } if (context.hasAttribute('accesskey-no-stop-propagation')) { return false; } return true; } function preventDefault(context, element) { if (element.hasAttribute('accesskey-no-prevent-default')) { return false; } if (context.hasAttribute('accesskey-no-prevent-default')) { return false; } return true; } function getHandlerToElement(context, element) { if (element.hasAttribute('accesskey-handler')) { let handlerName = element.getAttribute('accesskey-handler'); let handler = getRegisteredHandler(handlerName); if (handler) return handler; if (handlerName in window) return window[handlerName]; } if (context.hasAttribute('accesskey-handler')) { let handlerName = context.getAttribute('accesskey-handler'); let handler = getRegisteredHandler(handlerName); if (handler) return handler; if (handlerName in window) return window[handlerName]; } return config.handler; } function getSplitterToElement(context, element) { if (element.hasAttribute('accesskey-splitter')) { return element.getAttribute('accesskey-splitter'); } if (context.hasAttribute('accesskey-splitter')) { return context.getAttribute('accesskey-splitter'); } return config.splitter; } function getContexts() { let contexts = document.querySelectorAll('[accesskey-context]'); if (contexts.length === 0) { throw new Error('No accesskey contexts found!'); } return contexts; } function setGlobalHandler(handler) { config.handler = handler; return this; } return { init, setGlobalHandler, registerHandler, setGlobalSplitter, }; };