initial commit
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
(c) Copyrights 2007 - 2008
|
||||
|
||||
Original idea by by Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
||||
|
||||
jQuery Plugin by Tzury Bar Yochay
|
||||
tzury.by@gmail.com
|
||||
http://evalinux.wordpress.com
|
||||
http://facebook.com/profile.php?id=513676303
|
||||
|
||||
Project's sites:
|
||||
http://code.google.com/p/js-hotkeys/
|
||||
http://github.com/tzuryby/hotkeys/tree/master
|
||||
|
||||
License: same as jQuery license.
|
||||
|
||||
USAGE:
|
||||
// simple usage
|
||||
$(document).bind('keydown', 'Ctrl+c', function(){ alert('copy anyone?');});
|
||||
|
||||
// special options such as disableInIput
|
||||
$(document).bind('keydown', {combi:'Ctrl+x', disableInInput: true} , function() {});
|
||||
|
||||
Note:
|
||||
This plugin wraps the following jQuery methods: $.fn.find, $.fn.bind and $.fn.unbind
|
||||
|
||||
*/
|
||||
|
||||
|
||||
(function (jQuery){
|
||||
// keep reference to the original $.fn.bind and $.fn.unbind
|
||||
jQuery.fn.__bind__ = jQuery.fn.bind;
|
||||
jQuery.fn.__unbind__ = jQuery.fn.unbind;
|
||||
jQuery.fn.__find__ = jQuery.fn.find;
|
||||
|
||||
var hotkeys = {
|
||||
version: '0.7.8',
|
||||
override: /keydown|keypress|keyup/g,
|
||||
triggersMap: {},
|
||||
|
||||
specialKeys: { 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll',
|
||||
20: 'capslock', 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',
|
||||
35:'end', 33: 'pageup', 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down',
|
||||
112:'f1',113:'f2', 114:'f3', 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8',
|
||||
120:'f9', 121:'f10', 122:'f11', 123:'f12' },
|
||||
|
||||
shiftNums: { "`":"~", "1":"!", "2":"@", "3":"#", "4":"$", "5":"%", "6":"^", "7":"&",
|
||||
"8":"*", "9":"(", "0":")", "-":"_", "=":"+", ";":":", "'":"\"", ",":"<",
|
||||
".":">", "/":"?", "\\":"|" },
|
||||
|
||||
newTrigger: function (type, combi, callback) {
|
||||
// i.e. {'keyup': {'ctrl': {cb: callback, disableInInput: false}}}
|
||||
var result = {};
|
||||
result[type] = {};
|
||||
result[type][combi] = {cb: callback, disableInInput: false};
|
||||
return result;
|
||||
}
|
||||
};
|
||||
// add firefox num pad char codes
|
||||
if (jQuery.browser.mozilla){
|
||||
hotkeys.specialKeys = jQuery.extend(hotkeys.specialKeys, { 96: '0', 97:'1', 98: '2', 99:
|
||||
'3', 100: '4', 101: '5', 102: '6', 103: '7', 104: '8', 105: '9' });
|
||||
}
|
||||
|
||||
// a wrapper around of $.fn.find
|
||||
// see more at: http://groups.google.com/group/jquery-en/browse_thread/thread/18f9825e8d22f18d
|
||||
jQuery.fn.find = function( selector ) {
|
||||
this.query=selector;
|
||||
return jQuery.fn.__find__.apply(this, arguments);
|
||||
};
|
||||
|
||||
jQuery.fn.unbind = function (type, combi, fn){
|
||||
if (jQuery.isFunction(combi)){
|
||||
fn = combi;
|
||||
combi = null;
|
||||
}
|
||||
if (combi && typeof combi === 'string'){
|
||||
var selectorId = ((this.prevObject && this.prevObject.query) || (this[0].id && this[0].id) || this[0]).toString();
|
||||
var hkTypes = type.split(' ');
|
||||
for (var x=0; x<hkTypes.length; x++){
|
||||
delete hotkeys.triggersMap[selectorId][hkTypes[x]][combi];
|
||||
}
|
||||
}
|
||||
// call jQuery original unbind
|
||||
return this.__unbind__(type, fn);
|
||||
};
|
||||
|
||||
jQuery.fn.bind = function(type, data, fn){
|
||||
// grab keyup,keydown,keypress
|
||||
var handle = type.match(hotkeys.override);
|
||||
|
||||
if (jQuery.isFunction(data) || !handle){
|
||||
// call jQuery.bind only
|
||||
return this.__bind__(type, data, fn);
|
||||
}
|
||||
else{
|
||||
// split the job
|
||||
var result = null,
|
||||
// pass the rest to the original $.fn.bind
|
||||
pass2jq = jQuery.trim(type.replace(hotkeys.override, ''));
|
||||
|
||||
// see if there are other types, pass them to the original $.fn.bind
|
||||
if (pass2jq){
|
||||
// call original jQuery.bind()
|
||||
result = this.__bind__(pass2jq, data, fn);
|
||||
}
|
||||
|
||||
if (typeof data === "string"){
|
||||
data = {'combi': data};
|
||||
}
|
||||
if(data.combi){
|
||||
for (var x=0; x < handle.length; x++){
|
||||
var eventType = handle[x];
|
||||
var combi = data.combi.toLowerCase(),
|
||||
trigger = hotkeys.newTrigger(eventType, combi, fn),
|
||||
selectorId = ((this.prevObject && this.prevObject.query) || (this[0].id && this[0].id) || this[0]).toString();
|
||||
|
||||
//trigger[eventType][combi].propagate = data.propagate;
|
||||
trigger[eventType][combi].disableInInput = data.disableInInput;
|
||||
|
||||
// first time selector is bounded
|
||||
if (!hotkeys.triggersMap[selectorId]) {
|
||||
hotkeys.triggersMap[selectorId] = trigger;
|
||||
}
|
||||
// first time selector is bounded with this type
|
||||
else if (!hotkeys.triggersMap[selectorId][eventType]) {
|
||||
hotkeys.triggersMap[selectorId][eventType] = trigger[eventType];
|
||||
}
|
||||
// make trigger point as array so more than one handler can be bound
|
||||
var mapPoint = hotkeys.triggersMap[selectorId][eventType][combi];
|
||||
if (!mapPoint){
|
||||
hotkeys.triggersMap[selectorId][eventType][combi] = [trigger[eventType][combi]];
|
||||
}
|
||||
else if (mapPoint.constructor !== Array){
|
||||
hotkeys.triggersMap[selectorId][eventType][combi] = [mapPoint];
|
||||
}
|
||||
else {
|
||||
hotkeys.triggersMap[selectorId][eventType][combi][mapPoint.length] = trigger[eventType][combi];
|
||||
}
|
||||
|
||||
// add attribute and call $.event.add per matched element
|
||||
this.each(function(){
|
||||
// jQuery wrapper for the current element
|
||||
var jqElem = jQuery(this);
|
||||
|
||||
// element already associated with another collection
|
||||
if (jqElem.attr('hkId') && jqElem.attr('hkId') !== selectorId){
|
||||
selectorId = jqElem.attr('hkId') + ";" + selectorId;
|
||||
}
|
||||
jqElem.attr('hkId', selectorId);
|
||||
});
|
||||
result = this.__bind__(handle.join(' '), data, hotkeys.handler)
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
// work-around for opera and safari where (sometimes) the target is the element which was last
|
||||
// clicked with the mouse and not the document event it would make sense to get the document
|
||||
hotkeys.findElement = function (elem){
|
||||
if (!jQuery(elem).attr('hkId')){
|
||||
if (jQuery.browser.opera || jQuery.browser.safari){
|
||||
while (!jQuery(elem).attr('hkId') && elem.parentNode){
|
||||
elem = elem.parentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return elem;
|
||||
};
|
||||
// the event handler
|
||||
hotkeys.handler = function(event) {
|
||||
var target = hotkeys.findElement(event.currentTarget),
|
||||
jTarget = jQuery(target),
|
||||
ids = jTarget.attr('hkId');
|
||||
|
||||
if(ids){
|
||||
ids = ids.split(';');
|
||||
var code = event.which,
|
||||
type = event.type,
|
||||
special = hotkeys.specialKeys[code],
|
||||
// prevent f5 overlapping with 't' (or f4 with 's', etc.)
|
||||
character = !special && String.fromCharCode(code).toLowerCase(),
|
||||
shift = event.shiftKey,
|
||||
ctrl = event.ctrlKey,
|
||||
// patch for jquery 1.2.5 && 1.2.6 see more at:
|
||||
// http://groups.google.com/group/jquery-en/browse_thread/thread/83e10b3bb1f1c32b
|
||||
alt = event.altKey || event.originalEvent.altKey,
|
||||
mapPoint = null;
|
||||
|
||||
for (var x=0; x < ids.length; x++){
|
||||
if (hotkeys.triggersMap[ids[x]][type]){
|
||||
mapPoint = hotkeys.triggersMap[ids[x]][type];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//find by: id.type.combi.options
|
||||
if (mapPoint){
|
||||
var trigger;
|
||||
// event type is associated with the hkId
|
||||
if(!shift && !ctrl && !alt) { // No Modifiers
|
||||
trigger = mapPoint[special] || (character && mapPoint[character]);
|
||||
}
|
||||
else{
|
||||
// check combinations (alt|ctrl|shift+anything)
|
||||
var modif = '';
|
||||
if(alt) modif +='alt+';
|
||||
if(ctrl) modif+= 'ctrl+';
|
||||
if(shift) modif += 'shift+';
|
||||
|
||||
// modifiers + special keys or modifiers + character or modifiers + shift character or just shift character
|
||||
trigger = mapPoint[modif+special];
|
||||
if (!trigger){
|
||||
if (character){
|
||||
trigger = mapPoint[modif+character]
|
||||
|| mapPoint[modif+hotkeys.shiftNums[character]]
|
||||
// '$' can be triggered as 'Shift+4' or 'Shift+$' or just '$'
|
||||
|| (modif === 'shift+' && mapPoint[hotkeys.shiftNums[character]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trigger){
|
||||
var result = false;
|
||||
for (var x=0; x < trigger.length; x++){
|
||||
if(trigger[x].disableInInput){
|
||||
// double check event.currentTarget and event.target
|
||||
var elem = jQuery(event.target);
|
||||
if (jTarget.is("input") || jTarget.is("textarea")
|
||||
|| elem.is("input") || elem.is("textarea")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// call the registered callback function
|
||||
result = result || trigger[x].cb.apply(this, [event]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// place it under window so it can be extended and overridden by others
|
||||
window.hotkeys = hotkeys;
|
||||
return jQuery;
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user