From 6082f1fda79fbe75ed5b39a2e60961b2f90c982c Mon Sep 17 00:00:00 2001 From: Cyrus David Date: Fri, 12 Apr 2013 05:56:07 -0700 Subject: [PATCH] add keymage v1.0.0 --- ajax/libs/keymage/1.0.0/keymage.js | 313 +++++++++++++++++++++++++ ajax/libs/keymage/1.0.0/keymage.min.js | 6 + ajax/libs/keymage/package.json | 24 ++ 3 files changed, 343 insertions(+) create mode 100644 ajax/libs/keymage/1.0.0/keymage.js create mode 100644 ajax/libs/keymage/1.0.0/keymage.min.js create mode 100644 ajax/libs/keymage/package.json diff --git a/ajax/libs/keymage/1.0.0/keymage.js b/ajax/libs/keymage/1.0.0/keymage.js new file mode 100644 index 000000000..8339aca97 --- /dev/null +++ b/ajax/libs/keymage/1.0.0/keymage.js @@ -0,0 +1,313 @@ +// keymage.js - Javascript keyboard event handling +// http://github.com/piranha/keymage +// +// (c) 2012 Alexander Solovyov +// under terms of ISC License + +(function(define, undefined) { +define(function() { + // Defining all keys + var MODPROPS = ['shiftKey', 'ctrlKey', 'altKey', 'metaKey']; + var MODS = { + 'shift': 'shift', + 'ctrl': 'ctrl', 'control': 'ctrl', + 'alt': 'alt', 'option': 'alt', + 'win': 'meta', 'cmd': 'meta', 'super': 'meta', + 'meta': 'meta', + // default modifier for os x is cmd and for others is ctrl + 'defmod': ~navigator.userAgent.indexOf('Mac OS X') ? + 'meta' : 'ctrl' + }; + var MODORDER = ['shift', 'ctrl', 'alt', 'meta']; + var MODNUMS = [16, 17, 18, 91]; + + var KEYS = { + 'backspace': 8, + 'tab': 9, + 'enter': 13, 'return': 13, + 'pause': 19, + 'caps': 20, 'capslock': 20, + 'escape': 27, 'esc': 27, + 'space': 32, + 'pgup': 33, 'pageup': 33, + 'pgdown': 34, 'pagedown': 34, + 'end': 35, + 'home': 36, + 'ins': 45, 'insert': 45, + 'del': 46, 'delete': 46, + + 'left': 37, + 'up': 38, + 'right': 39, + 'down': 40, + + '*': 106, + '+': 107, 'plus': 107, + '-': 109, 'minus': 109, + ';': 186, + '=': 187, + ',': 188, + '.': 190, + '/': 191, + '`': 192, + '[': 219, + '\\': 220, + ']': 221, + "'": 222 + }; + + var i; + // numpad + for (i = 0; i < 10; i++) { + KEYS['num-' + i] = i + 95; + } + // top row 0-9 + for (i = 0; i < 10; i++) { + KEYS[i.toString()] = i + 48; + } + // f1-f24 + for (i = 1; i < 25; i++) { + KEYS['f' + i] = i + 111; + } + // alphabet + for (i = 65; i < 91; i++) { + KEYS[String.fromCharCode(i).toLowerCase()] = i; + } + + // Reverse key codes + var KEYREV = {}; + for (var k in KEYS) { + var val = KEYS[k]; + if (!KEYREV[val] || KEYREV[val].length < k.length) { + KEYREV[val] = k; + } + } + + // ----------------------- + // Actual work is done here + + var currentScope = ''; + var allChains = {}; + + function parseKeyString(keystring) { + var bits = keystring.split('-'); + var button = bits[bits.length - 1]; + var key = {code: KEYS[button]}; + + if (!key.code) { + throw 'Unknown key "' + button + '" in keystring "' + + keystring + '"'; + } + + var mod; + for (var i = 0; i < bits.length - 1; i++) { + button = bits[i]; + mod = MODS[button]; + if (!mod) { + throw 'Unknown modifier "' + button + '" in keystring "' + + keystring + '"'; + } + key[mod] = true; + } + + return key; + } + + function stringifyKey(key) { + var s = ''; + for (var i = 0; i < MODORDER.length; i++) { + if (key[MODORDER[i]]) { + s += MODORDER[i] + '-'; + } + } + s += KEYREV[key.code]; + return s; + } + + function normalizeKeyChain(keychainString) { + var keychain = []; + var keys = keychainString.split(' '); + + for (var i = 0; i < keys.length; i++) { + var key = parseKeyString(keys[i]); + key = stringifyKey(key); + keychain.push(key); + } + + keychain.original = keychainString; + return keychain; + } + + function eventKeyString(e) { + var key = {code: e.keyCode}; + for (var i = 0; i < MODPROPS.length; i++) { + var mod = MODPROPS[i]; + if (e[mod]) { + key[mod.slice(0, mod.length - 3)] = true; + } + } + return stringifyKey(key); + } + + function getNestedChains(chains, scope) { + for (var i = 0; i < scope.length; i++) { + var bit = scope[i]; + + if (bit) { + chains = chains[bit]; + } + + if (!chains) { + break; + } + } + return chains; + } + + var sequence = []; + function dispatch(e) { + // Skip all modifiers + if (~MODNUMS.indexOf(e.keyCode)) { + return; + } + + var seq = sequence.slice(); + seq.push(eventKeyString(e)); + var scope = currentScope.split('.'); + var matched, chains, key; + + for (var i = scope.length; i >= 0; i--) { + chains = getNestedChains(allChains, scope.slice(0, i)); + if (!chains) { + continue; + } + matched = true; + for (var j = 0; j < seq.length; j++) { + key = seq[j]; + if (!chains[key]) { + matched = false; + break; + } + chains = chains[key]; + } + + if (matched) { + break; + } + } + + var definitionScope = scope.slice(0, i).join('.'); + var preventDefault = chains.preventDefault; + + // partial match, save the sequence + if (matched && !chains.handlers) { + sequence = seq; + if (preventDefault) { + e.preventDefault(); + } + return; + } + + if (matched) { + for (i = 0; i < chains.handlers.length; i++) { + var handler = chains.handlers[i]; + var options = handler._keymage; + + var res = handler.call(options.context, e, { + shortcut: options.original, + scope: currentScope, + definitionScope: definitionScope + }); + + if (res === false || preventDefault) { + e.preventDefault(); + } + } + } + + // either matched or not, drop the sequence + sequence = []; + } + + function assignKey(scope, keychain, fn) { + var bits = scope.split('.'); + var chains = allChains; + + bits = bits.concat(keychain); + + for (var i = 0, l = bits.length; i < l; i++) { + var bit = bits[i]; + if (!bit) continue; + + chains = chains[bit] || (chains[bit] = {}); + if (fn._keymage.preventDefault) { + chains.preventDefault = true; + } + + if (i === l - 1) { + var handlers = chains.handlers || (chains.handlers = []); + handlers.push(fn); + } + } + } + + // optional arguments: scope, options. + function keymage(scope, keychain, fn, options) { + if (keychain === undefined && fn === undefined) { + return function(keychain, fn) { + return keymage(scope, keychain, fn); + }; + } + + if (typeof keychain === 'function') { + options = fn; + fn = keychain; + keychain = scope; + scope = ''; + } + + var normalized = normalizeKeyChain(keychain); + fn._keymage = options || {}; + fn._keymage.original = keychain; + assignKey(scope, normalized, fn); + } + + keymage.parse = parseKeyString; + keymage.stringify = stringifyKey; + + keymage.bindings = allChains; + + keymage.setScope = function(scope) { + currentScope = scope ? scope : ''; + }; + + keymage.getScope = function() { return currentScope; }; + + keymage.pushScope = function(scope) { + currentScope = (currentScope ? currentScope + '.' : '') + scope; + return currentScope; + }; + + keymage.popScope = function(scope) { + var i; + + if (!scope) { + i = currentScope.lastIndexOf('.'); + scope = currentScope.slice(i + 1); + currentScope = currentScope.slice(0, i); + return scope; + } + + currentScope = currentScope.replace( + new RegExp('(^|\\.)' + scope + '(\\.|$).*'), ''); + return scope; + }; + + + window.addEventListener('keydown', dispatch, false); + + return keymage; +}); +})(typeof define !== 'undefined' ? define : function(factory) { + window.keymage = factory(); +}); diff --git a/ajax/libs/keymage/1.0.0/keymage.min.js b/ajax/libs/keymage/1.0.0/keymage.min.js new file mode 100644 index 000000000..a0e57b6ef --- /dev/null +++ b/ajax/libs/keymage/1.0.0/keymage.min.js @@ -0,0 +1,6 @@ +// keymage.js - Javascript keyboard event handling +// http://github.com/piranha/keymage +// +// (c) 2012 Alexander Solovyov +// under terms of ISC License +(function(a,b){a(function(){function m(a){var b=a.split("-"),d=b[b.length-1],e={code:f[d]};if(!e.code)throw'Unknown key "'+d+'" in keystring "'+a+'"';var g;for(var h=0;h=0;h--){f=q(l,c.slice(0,h));if(!f)continue;d=!0;for(var i=0;i