key-controller
Version:
A library that abstracts handling keyboard controls in the browser
1 lines • 9.52 kB
Source Map (JSON)
{"version":3,"sources":["lib/invert.js","lib/rotate.js","lib/compound.js","lib/controller.js","lib/index.js","index.js"],"names":["invert","json","swapped","key","undefined","Array","isArray","forEach","value","rotate","keyFallback","rotated","outer","inner","desensitize","keystring","keys","split","pop","push","primaryKey","keyArray","map","str","toLowerCase","sort","join","decorate","event","modifiers","altKey","ctrlKey","metaKey","Controller","generator","models","_models","_virtuals","_handlers","controls","virtualsByEvent","keymap","virtual","err","Error","handler","e","fn","wildcardFn","body","removeEventListener","addEventListener","controller"],"mappings":"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","file":"key-controller.min.map","sourceRoot":"..","sourcesContent":["'use strict'\n\n/**\n * Swaps JSON values with keys; assumes JSON is a bijection\n * Array values are destructured as keys in the inverted JSON\n * @func invert\n * @param {Object} json JSON to invert\n * @throws {type} The duplicate value if the JSON is not a bijection\n * @returns {Object} A copy of the original JSON with its keys and values inverted\n */\nfunction invert (json) {\n let swapped = {}\n\n for (const key in json) {\n if (swapped[json[key]] !== undefined) {\n throw json[key]\n }\n\n if (Array.isArray(json[key])) {\n json[key].forEach((value) => {\n if (swapped[value] !== undefined) {\n throw value\n }\n\n swapped[value] = key\n })\n } else {\n swapped[json[key]] = key\n }\n }\n\n return swapped\n}\n\nexport default invert\n","'use strict'\n\n/**\n * Rotates the inner and outer keys of a depth-2 JSON\n * Creates an inner key to rotate if no inner key exists\n * @func rotate\n * @param {Object} json JSON to rotate\n * @param {Object} [keyFallback='inner'] Inner key to create if no inner key exists\n * @returns {Object} A copy of the original JSON with keys rotated\n */\nfunction rotate (json, keyFallback = 'inner') {\n let rotated = {}\n\n for (const outer in json) {\n if (typeof json[outer] !== 'object') {\n if (!rotated[keyFallback]) {\n rotated[keyFallback] = {}\n }\n rotated[keyFallback][outer] = json[outer]\n } else {\n for (const inner in json[outer]) {\n if (!rotated[inner]) {\n rotated[inner] = {}\n }\n rotated[inner][outer] = json[outer][inner]\n }\n }\n }\n\n return rotated\n}\n\nexport default rotate\n","'use strict'\n\n/**\n * Normalizes the case and ordering of compound keys\n * @func desensitize\n * @param {string} keystring The compound key to normalize\n * @returns {string} The normalized compound key\n */\nfunction desensitize (keystring) {\n const keys = keystring.split('+')\n\n if (keystring === '+') {\n return keystring\n }\n if (keystring.split('').pop() === '+') {\n keys.pop()\n keys.pop()\n keys.push('+')\n }\n\n const primaryKey = keys.pop()\n const keyArray = keys.map(str => str.toLowerCase()).sort()\n\n keyArray.push(primaryKey)\n\n return keyArray.join('+')\n}\n\n/**\n * Decorates KeyboardEvent.key to reflect whether Alt, Ctrl, or Meta\n * has been pressed. Shift is ignored, since e.key already accounts for it\n * @func decorate\n * @param {Object} event A KeyboardEvent\n * @returns {string} KeyboardEvent.key, decorated to reflect if peripheral keys were held\n */\nfunction decorate (event) {\n let modifiers = ''\n\n if (event.altKey) {\n modifiers += 'alt+'\n }\n if (event.ctrlKey) {\n modifiers += 'ctrl+'\n }\n if (event.metaKey) {\n modifiers += 'meta+'\n }\n\n return modifiers + event.key\n}\n\nexport {\n desensitize,\n decorate\n}\n","'use strict'\n\nimport invert from './invert'\nimport rotate from './rotate'\nimport { decorate, desensitize } from './compound'\n\nclass Controller {\n /**\n * Create a Controller; caches model, virtuals, and options\n * @param {Object} model The object passed and mutated in the virtuals\n * @param {Function} generator A function that returns a map of virtual keys to handlers\n */\n constructor (generator, ...models) {\n this._models = models\n this._virtuals = generator(...models)\n this._handlers = {}\n }\n\n /**\n * Binds keyboard controls to virtual keys\n * @param {Object} controls A mapping of virtual keys to keyboard codes\n */\n register (controls) {\n const shorthandDefault = 'keydown'\n const virtualsByEvent = rotate(this._virtuals, shorthandDefault)\n let keymap\n\n for (const virtual in controls) {\n if (Array.isArray(controls[virtual])) {\n controls[virtual] = controls[virtual].map(desensitize)\n } else {\n controls[virtual] = desensitize(controls[virtual])\n }\n }\n\n try {\n keymap = invert(controls)\n } catch (err) {\n throw new Error(`Cannot register controls; attempting to bind ${err} to multiple virtual keys`)\n }\n\n for (const event in virtualsByEvent) {\n const handler = (e) => {\n const fn = virtualsByEvent[event][keymap[decorate(e)]]\n const wildcardFn = virtualsByEvent[event]['_']\n\n if (fn) {\n fn(e)\n }\n if (wildcardFn) {\n wildcardFn(e)\n }\n }\n\n document.body.removeEventListener(event, this._handlers[event])\n document.body.addEventListener(event, handler)\n this._handlers[event] = handler\n }\n }\n\n /**\n * Unbinds the controller from the DOM\n */\n unbind () {\n for (const event in this._virtuals) {\n document.body.removeEventListener(event, this._handlers[event])\n }\n }\n\n /**\n * Binds the controller to the DOM\n */\n bind () {\n for (const event in this._virtuals) {\n document.body.addEventListener(event, this._handlers[event])\n }\n }\n}\n\nexport default Controller\n","'use strict'\n\nimport Controller from './controller'\n\nexport default Controller\n","import controller from './lib'\n\nexport default controller\n"]}