@atlassian/aui
Version:
Atlassian User Interface library
177 lines (152 loc) • 5.18 kB
JavaScript
/*
* Modified by Atlassian to allow chaining of keys
*
* jQuery Hotkeys Plugin
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Based upon the plugin by Tzury Bar Yochay:
* http://github.com/tzuryby/hotkeys
*
* Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/
(function(jQuery){
jQuery.hotkeys = {
version: "0.8",
specialKeys: {
8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
91 : "meta",
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll",
188: ",", 190: ".", 191: "/", 224: "meta", 219: '[', 221: ']'
},
// These only work under Mac Gecko when using keypress (see http://unixpapa.com/js/key.html).
keypressKeys: [ "<", ">", "?" ],
shiftNums: {
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ":", "'": "\"", ",": "<",
".": ">", "/": "?", "\\": "|"
}
};
jQuery.each(jQuery.hotkeys.keypressKeys, function (_, key) {
jQuery.hotkeys.shiftNums[ key ] = key;
});
function TimedNumber(timer) {
this.num = 0;
this.timer = timer > 0 ? timer : false;
}
TimedNumber.prototype.val = function () {
return this.num;
};
TimedNumber.prototype.inc = function () {
if (this.timer) {
clearTimeout(this.timeout);
this.timeout = setTimeout(jQuery.proxy(TimedNumber.prototype.reset, this), this.timer);
}
this.num++;
};
TimedNumber.prototype.reset = function () {
if (this.timer) {
clearTimeout(this.timeout);
}
this.num = 0;
};
function keyHandler( handleObj ) {
// Only care when a possible input has been specified
if ( !(jQuery.isPlainObject(handleObj.data) || jQuery.isArray(handleObj.data) || typeof handleObj.data === "string") ) {
return;
}
var origHandler = handleObj.handler,
options = {
timer: 700,
combo: []
};
(function (data) {
if (typeof data === 'string') {
options.combo = [ data ];
} else if (jQuery.isArray(data)) {
options.combo = data;
} else {
jQuery.extend(options, data);
}
options.combo = jQuery.map(options.combo, function (key) {
return key.toLowerCase();
});
})(handleObj.data);
handleObj.index = new TimedNumber(options.timer);
handleObj.handler = function( event ) {
// Don't fire in text-accepting inputs that we didn't directly bind to
// important to note that jQuery.fn.prop is only available on jquery 1.6+
if ( this !== event.target && (/textarea|select|input/i.test( event.target.nodeName ) ||
jQuery(event.target).prop('contenteditable') === 'true' )) {
return;
}
// Keypress represents characters, not special keys
var special = event.type !== 'keypress' ? jQuery.hotkeys.specialKeys[ event.which ] : null,
character = String.fromCharCode( event.which ).toLowerCase(),
key, modif = "", possible = {};
// check combinations (alt|ctrl|shift+anything)
if ( event.altKey && special !== "alt" ) {
modif += "alt+";
}
if ( event.ctrlKey && special !== "ctrl" ) {
modif += "ctrl+";
}
// TODO: Need to make sure this works consistently across platforms
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
modif += "meta+";
}
if ( event.shiftKey && special !== "shift" ) {
modif += "shift+";
}
// Under Chrome and Safari, meta's keycode == '['s charcode
// Even if they did type this key combo we could not use it because it is browser back in Chrome/Safari on OS X
if (event.metaKey && character === '[') {
character = null;
}
if ( special ) {
possible[ modif + special ] = true;
}
if ( character ) {
possible[ modif + character ] = true;
}
// "$" can be specified as "shift+4" or "$"
if ( /shift+/.test(modif) ) {
possible [ modif.replace('shift+', '') + jQuery.hotkeys.shiftNums[ (special || character) ] ] = true;
}
var index = handleObj.index,
combo = options.combo;
if ( pressed(combo[index.val()], possible) ) {
if ( index.val() === combo.length - 1 ) {
index.reset();
return origHandler.apply(this, arguments);
} else {
index.inc();
}
} else {
index.reset();
// For mutli-key combinations, we might have restarted the key sequence.
if ( pressed(combo[0], possible) ) {
index.inc();
}
}
};
}
function pressed(key, possible) {
var keys = key.split(' ');
for (var i = 0, len = keys.length; i < len; i++) {
if ( possible[keys[i]] ) {
return true;
}
}
return false;
}
jQuery.each([ "keydown", "keyup", "keypress" ], function() {
jQuery.event.special[ this ] = { add: keyHandler };
});
})( jQuery );