Jqurey版本: 1.7.1
插件: js-hotkeys0.7.9
问题描述: bind多个快捷键后, 按一个快捷键会执行多次(等于你绑定的个数)
这是官网的问题描述:
So there is a problem with the current codebase.Namely if you bind more than one shortcut event to a dom element then thoseevents will fire N numbers of times (where N is the number of events youassigned to an element).
比如:
$(document).bind('keyup', 'ctrl+t', handle_keyboard_add_command);
$(document).bind('keyup', 'ctrl+a', handle_keyboard_add_action);
$(document).bind('keyup', {combi:'up', disableInInput: true},handle_keyboard_up);
$(document).bind('keyup', {combi:'down', disableInInput: true},handle_keyboard_down);
$(document).bind('keyup', {combi:'right', disableInInput: true},handle_keyboard_right);
$(document).bind('keyup', {combi:'left', disableInInput: true},handle_keyboard_left);
$(document).bind('keyup', {combi:'home', disableInInput: true},handle_keyboard_home);
$(document).bind('keyup', {combi:'end', disableInInput: true},handle_keyboard_end);
$(document).bind('keyup', {combi:'return', disableInInput: true},handle_keyboard_enter);
$(document).bind('keyup', {combi:'space', disableInInput: true},handle_keyboard_space);
如果你点击ctrl-t; handle_keyboard_add_command会被执行10次;
原因是源码中hotkeys.handler并没有规定事件event是从哪来的;From my analysis of the code a map of shortcuts with a key of the dom_element from which the event can be fired. If that dom_element is found, then the code looks for a match for the specific shortcut combination, if it finds a match it fires the handler. However no where in that logic does it make sure that the shortcut combination corresponds to the even fired. This isn't hard to do, we have the comibination in event.data.combi, we just have to check it. I altered the code to do this:
修改hotkeys.handler方法便可
// 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
if(mapPoint[special]) {
trigger =mapPoint[special];
if(trigger &&special != event.data.combi) {
return;
}
} elseif(character&& mapPoint[character]) {
trigger =mapPoint[character];
if(trigger &&character != event.data.combi) {
return;
}
}
} 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 + shiftcharacter or just shift character
trigger =mapPoint[modif+special];
// only continue if we match the combi key of the current event
if(trigger && (modif+special) !=event.data.combi) {
return;
}
if (!trigger){
if (character){
if(mapPoint[modif+character]){
trigger =mapPoint[modif+character];
if(trigger &&(modif+character) != event.data.combi) {
return;
}
} elseif(mapPoint[modif+hotkeys.shiftNums[character]]){
trigger =mapPoint[modif+hotkeys.shiftNums[character]];
if(trigger &&(modif+hotkeys.shiftNums[character]) != event.data.combi) {
return;
}
} elseif(modif === 'shift+' &&mapPoint[hotkeys.shiftNums[character]]) {
trigger = mapPoint[hotkeys.shiftNums[character]];
if(trigger &&hotkeys.shiftNums[character] != event.data.combi) {
return;
}
}
}
}
}
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") || jTarget.is("select")
|| elem.is("input") || elem.is("textarea") || elem.is("select")) {
returntrue;
}
}
// call the registered callback function
result = result ||trigger[x].cb.apply(this, [event]);
}
return result;
}
}
}
};
主要修改的是这两段代码:
if(mapPoint[special]) {
trigger =mapPoint[special];
if(trigger &&special != event.data.combi) {
return;
}
} elseif(character&& mapPoint[character]) {
trigger =mapPoint[character];
if(trigger &&character != event.data.combi) {
return;
}
}
if(mapPoint[modif+character]) {
trigger =mapPoint[modif+character];
if(trigger &&(modif+character) != event.data.combi) {
return;
}
} elseif(mapPoint[modif+hotkeys.shiftNums[character]]) {
trigger =mapPoint[modif+hotkeys.shiftNums[character]];
if(trigger &&(modif+hotkeys.shiftNums[character]) != event.data.combi) {
return;
}
} elseif(modif === 'shift+' &&mapPoint[hotkeys.shiftNums[character]]) {
trigger =mapPoint[hotkeys.shiftNums[character]];
if(trigger &&hotkeys.shiftNums[character] != event.data.combi) {
return;
}
}