1

I am trying to write a Javascript/jQuery function that will automatically bind keyboard shortcuts to my webpage. The method I have in mind is something like the following:

  1. Loop through all elements with a class beginning with 'key-'
  2. For each of these elements, retrieve the key combinations from the class, e.g. 'key-ctrl-s' will return Ctrl+S
  3. Bind the event for the combination of these particular keys to the document

Pretty basic algorithm, or so I thought... issue coming...

So for example, I can enter the following:

<a href="javascript:void(0)" class="some_other_class ctrl+s">Save</a>
<a href="javascript:void(0)" class="ctrl+shift+s">Save As</a>

The above code will generate the following keyboard shortcuts: Ctrl+S and Ctrl+Shift+S

And when these keys are pressed, the click event will be triggered for the relevant html element...

The Issue

As stated above, the algorithm here is pretty darn simple, however, as usual, the problem comes when trying to write it.

I cannot see how I am going to know which keycode (e.which) to listen for when automatically binding the event.

For example:

Using the above HTML and the following jQuery, we can get thus far (ignore things like the regex):

function keyboardShortcuts(){
    // Loop through all elements with a class containing 'key-'
    $("[class*='key-']").each(function(){
        // Using a regular expression here, separate the class into individual keys
        // whilst ignoring other classes and the 'key-' prefix
        var keys = $(this).attr('class').match(/REGEX HERE/);

        // THIS IS WHERE THE CODE GETS A LITTLE MESSY
        // I AM VERY UNSURE ABOUT THE FOLLOWING

        // Define all special characters and set them to false
        var ctrl = false, alt = false, shift = false;

        // First test for special characters
        // Test for ctrl key
        if(keys.indexOf('ctrl')!=-1){
            ctrl = true;
            // Remove ctrl from the keys array
            keys.splice(keys.indexOf('ctrl'),1)
        }
        // Test for alt key
        if(keys.indexOf('alt')!=-1){
            alt = true;
            // Remove alt from the keys array
            keys.splice(keys.indexOf('alt'),1)
        }
        // Test for shift key
        if(keys.indexOf('shift')!=-1){
            shift = true;
            // Remove shift from the keys array
            keys.splice(keys.indexOf('shift'),1)
        }

        // Determine special characters to test for
        if(ctrl&&alt&&shift){

            // Bind the keypress event to the document

            $(document).keypress(function(e) {
                if((e.ctrlKey||e.metaKey)&&e.altKey&&shiftKey) {

                    var continue = true;

                    // Test for other characters in keys array
                    for(var i=0;i<keys.length;i++){

                        // THIS IS WHAT I AM REALLY UNSURE ABOUT
                        if(keys.indexOf(charCodeAt(e.which))==-1){
                            // Correct key was not pressed so do not continue
                            continue = false;
                        }
                    }

                    if(continue){
                        e.preventDefault();
                        // Proceed to triggering the click event
                        // No more help needed from here...
                    }
                }
                return true;
            });
        }else if(ctrl&&alt){

        }else if(ctrl&&shift){

        }else if(shift&&alt){

        }else if(ctrl){

        }else if(alt){

        }else if(shift){

        }
    });
}

As you can see from the above, the code is quite long winded, but I simply cannot see another way of writing it... Other than maybe a few tidy ups with arrays here and there, but even so the nested if statements are pretty much a necessity aren't they?

Finally, My Question

Excluding the fact that the code is pretty untidy and could probably be written a little/a lot better (if you do have views on this please provide them), my actual question is in reference to the line that reads:

keys.indexOf(charCodeAt(e.which))==-1

Is this a reliable method of retrieving the character from the character code across all browsers? If not, is there a better way to do it?

Anybody that has any opinions on the rest of the code, please post, would love to have some feedback.

4

1 回答 1

1

当我开始做这件事时,我并不打算重写整个事情。但我做到了,你可以看到它在这个 jsfiddle上工作。

该技术是找到所有目标元素并构建一个列表,其中列出了每个元素映射到的组合键。我们将这些存储在数组keybindings中,每次有人按下一个键时,我们都会查看整个列表以寻找匹配项。如果我们找到一个,我们会在元素上触发一个点击事件。

我使用keydown而不是keypress因为您实际上可以使用它获得修饰符信息。我还改进了类字符串解析,但我敢肯定它可以做得更干净一些。

这是JS代码。

var keybindings = [];

$('[class*="key-"]').each(function (idx, val) {
    var keyspec = {
        which: 0,
        altKey: false,
        shiftKey: false,
        ctrlKey: false,
        element: val
    };

    var keystring = $(val).attr('class').toLowerCase();
    var match = /key-\S+/.exec(keystring);
    var parts = match.toString().split('-');
    keyspec.which = parts[ parts.length-1 ].toUpperCase().charCodeAt(0);
    for (var jdx in parts) {
        if (parts[jdx] == 'alt') keyspec.altKey = true;
        else if (parts[jdx] == 'shift') keyspec.shiftKey = true;
        else if (parts[jdx] == 'ctrl') keyspec.ctrlKey = true;
    }
    keybindings.push( keyspec );
});

$(document).keydown( function(evt) {
    $.each(keybindings, function(idx, oneBind) {
       if (evt.which == oneBind.which
           && evt.altKey == oneBind.altKey
           && evt.shiftKey == oneBind.shiftKey
           && evt.ctrlKey == oneBind.ctrlKey)
           $(oneBind.element).click();
    });
});

当然,我现在想到可能已经有一个 jquery 插件,我们可以使用它。

于 2013-01-30T04:47:46.883 回答