/* YUI 3.17.2 (build 9c3c78e) Copyright 2014 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('event-key', function (Y, NAME) { /** * Functionality to listen for one or more specific key combinations. * @module event * @submodule event-key */ var ALT = "+alt", CTRL = "+ctrl", META = "+meta", SHIFT = "+shift", trim = Y.Lang.trim, eventDef = { KEY_MAP: { enter : 13, space : 32, esc : 27, backspace: 8, tab : 9, pageup : 33, pagedown : 34 }, _typeRE: /^(up|down|press):/, _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g, processArgs: function (args) { var spec = args.splice(3,1)[0], mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []), config = { type: this._typeRE.test(spec) ? RegExp.$1 : null, mods: mods, keys: null }, // strip type and modifiers from spec, leaving only keyCodes bits = spec.replace(this._keysRE, ''), chr, uc, lc, i; if (bits) { bits = bits.split(','); config.keys = {}; // FIXME: need to support '65,esc' => keypress, keydown for (i = bits.length - 1; i >= 0; --i) { chr = trim(bits[i]); // catch sloppy filters, trailing commas, etc 'a,,' if (!chr) { continue; } // non-numerics are single characters or key names if (+chr == chr) { config.keys[chr] = mods; } else { lc = chr.toLowerCase(); if (this.KEY_MAP[lc]) { config.keys[this.KEY_MAP[lc]] = mods; // FIXME: '65,enter' defaults keydown for both if (!config.type) { config.type = "down"; // safest } } else { // FIXME: Character mapping only works for keypress // events. Otherwise, it uses String.fromCharCode() // from the keyCode, which is wrong. chr = chr.charAt(0); uc = chr.toUpperCase(); if (mods["+shift"]) { chr = uc; } // FIXME: stupid assumption that // the keycode of the lower case == the // charCode of the upper case // a (key:65,char:97), A (key:65,char:65) config.keys[chr.charCodeAt(0)] = (chr === uc) ? // upper case chars get +shift free Y.merge(mods, { "+shift": true }) : mods; } } } } if (!config.type) { config.type = "press"; } return config; }, on: function (node, sub, notifier, filter) { var spec = sub._extra, type = "key" + spec.type, keys = spec.keys, method = (filter) ? "delegate" : "on"; // Note: without specifying any keyCodes, this becomes a // horribly inefficient alias for 'keydown' (et al), but I // can't abort this subscription for a simple // Y.on('keypress', ...); // Please use keyCodes or just subscribe directly to keydown, // keyup, or keypress sub._detach = node[method](type, function (e) { var key = keys ? keys[e.which] : spec.mods; if (key && (!key[ALT] || (key[ALT] && e.altKey)) && (!key[CTRL] || (key[CTRL] && e.ctrlKey)) && (!key[META] || (key[META] && e.metaKey)) && (!key[SHIFT] || (key[SHIFT] && e.shiftKey))) { notifier.fire(e); } }, filter); }, detach: function (node, sub, notifier) { sub._detach.detach(); } }; eventDef.delegate = eventDef.on; eventDef.detachDelegate = eventDef.detach; /** *
Add a key listener. The listener will only be notified if the * keystroke detected meets the supplied specification. The * specification is a string that is defined as:
* *[{type}:]{code}[,{code}]*
"down", "up", or "press"
{keyCode|character|keyName}[+{modifier}]*
"shift", "ctrl", "alt", or "meta"
"enter", "space", "backspace", "esc", "tab", "pageup", or "pagedown"
Examples:
*Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");
Y.delegate("key", preventSubmit, "#forms", "enter", "input[type=text]");
Y.one("doc").on("key", viNav, "j,k,l,;");