Last active
May 28, 2020 21:05
-
-
Save FranciscoG/97035afb29b53f61d15662ff41710048 to your computer and use it in GitHub Desktop.
Vue custom directive that only allows certain keys to be typed into an element that accepts keyboard input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* `v-kesAllowed` directive | |
* | |
* This works by blocking keys during onKeyDown by using a whitelist regex and | |
* testing `event.key` | |
*/ | |
/** | |
* these keys should be allowed in all cases because they handle traversing and a11y | |
*/ | |
const baseAllowedRegex = new RegExp('Backspace|ArrowLeft|ArrowRight|ArrowUp|ArrowDown|Tab|Delete') | |
/** | |
* allow only numbers | |
*/ | |
const numbersRegex = new RegExp(`[0-9]`) | |
/** | |
* Similar to numbers but also allows commas minus the currency symbol | |
*/ | |
const currencyRegex = new RegExp(`[0-9,]`) | |
/** | |
* Regex to be used for any part of a person's full name with full support for | |
* international language character | |
* | |
* u flag for 'unicode' | |
* https://www.regular-expressions.info/unicode.html | |
* | |
* \p{L} - any kind of letter from any language. case insensitive | |
* | |
* \p{Zs} - any unicode space character that takes up visible space | |
* | |
* \p{Pd} - any kind of hyphen or dash. | |
* | |
* periods - for things like: Jr. Sr. | |
* | |
* apostrophe (aka single quote) - for names like O'Malley | |
* | |
* This should cover _most_ names in the US, Europe, and probably the world | |
* | |
*/ | |
let namesRegex | |
try { | |
namesRegex = new RegExp(`[\\p{L}\\p{Zs}\\p{Pd}\\.\\\\']`, 'u') | |
} catch (e) { | |
// Unicode Property Escapes is very new in JS so not all browsers support it. This is a fallback | |
// that is specifically made for the western world. | |
// It supports: | |
// Latin-1 Supplement, Latin Extended-A, Latin Extended-B, Latin Extended Additional | |
// If you need full worldwide language support you can use this to generate a regex: | |
// https://mothereff.in/regexpu#input=var+regex+%3D+/%5Cp%7BL%7D/u%3B&unicodePropertyEscape=1 | |
namesRegex = new RegExp(`[a-z\u00C0-\u024F\u1E00-\u1EFF\\s-']`, 'i') | |
} | |
/** | |
* Just letters from any language, like in Middle initials | |
*/ | |
let lettersRegex | |
try { | |
lettersRegex = new RegExp('\\p{L}', 'u') | |
} catch (e) { | |
lettersRegex = new RegExp(`[a-z\u00C0-\u024F\u1E00-\u1EFF]`, 'i') | |
} | |
function onKeyDown (re) { | |
return function handler (e) { | |
if (e.metaKey) { | |
// allow shortcuts like Ctrl/Command + A | |
return true | |
} | |
if (re.test(e.key) || baseAllowedRegex.test(e.key)) { | |
return true | |
} | |
e.preventDefault() | |
return false | |
} | |
} | |
export const AllowedTypes = { | |
CURRENCY: 'currency', | |
NAMES: 'names', | |
NUMBERS: 'numbers', | |
LETTERS: 'letters' | |
} | |
/** | |
* Directive that whitelists keys allowed to be typed inside an input and | |
* prevents anything else from being typed | |
* | |
* <Component v-keysAllowed="AllowedTypes.CURRENCY" /> | |
* | |
* TODO: instead of accepting a string, use modifiers | |
* <Component v-keysAllowed.currency /> | |
* OR | |
* <Component v-keysAllowed:currency /> | |
*/ | |
export default { | |
bind (el, binding, vnode) { | |
switch (binding.value) { | |
case AllowedTypes.CURRENCY: | |
self.handler = onKeyDown(currencyRegex) | |
break | |
case AllowedTypes.NAMES: | |
self.handler = onKeyDown(namesRegex) | |
break | |
case AllowedTypes.NUMBERS: | |
self.handler = onKeyDown(numbersRegex) | |
break | |
case AllowedTypes.LETTERS: | |
self.handler = onKeyDown(lettersRegex) | |
break | |
default: | |
self.handler = null | |
} | |
if (self.handler) { | |
el.addEventListener('keydown', self.handler) | |
} | |
}, | |
unbind (el, binding, vnode) { | |
if (self.handler) { | |
el.removeEventListener('keydown', self.handler) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment