/*jslint browser: true*/
/*jslint jquery: true*/

/*
 * 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:
 * https://github.com/tzuryby/jquery.hotkeys
 *
 * Original idea by:
 * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
 */

/*
 * One small change is: now keys are passed by object { keys: '...' }
 * Might be useful, when you want to pass some other data to your handler
 */

(function(jQuery) {

    jQuery.hotkeys = {
        version: `0.2.0`,

        specialKeys: {
            8: `backspace`,
            9: `tab`,
            10: `return`,
            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`,
            59: `;`,
            61: `=`,
            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`,
            173: `-`,
            186: `;`,
            187: `=`,
            188: `,`,
            189: `-`,
            190: `.`,
            191: `/`,
            192: `\``,
            219: `[`,
            220: `\\`,
            221: `]`,
            222: `'`
        },

        shiftNums: {
            "`": `~`,
            "1": `!`,
            "2": `@`,
            "3": `#`,
            "4": `$`,
            "5": `%`,
            "6": `^`,
            "7": `&`,
            "8": `*`,
            "9": `(`,
            "0": `)`,
            "-": `_`,
            "=": `+`,
            ";": `: `,
            "'": `"`,
            ",": `<`,
            ".": `>`,
            "/": `?`,
            "\\": `|`
        },

    // excludes: button, checkbox, file, hidden, image, password, radio, reset, search, submit, url
        textAcceptingInputTypes: [
            `text`, `password`, `number`, `email`, `url`, `range`, `date`, `month`, `week`, `time`, `datetime`,
            `datetime-local`, `search`, `color`, `tel`],

    // default input types not to bind to unless bound directly
        textInputTypes: /textarea|input|select/i,

        options: {
            filterInputAcceptingElements: true,
            filterTextInputs: true,
            filterContentEditable: true
        }
    };

    function keyHandler(handleObj) {
        if (typeof handleObj.data === `string`) {
            handleObj.data = {
                keys: handleObj.data
            };
        }

    // Only care when a possible input has been specified
        if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== `string`) {
            return;
        }

        var origHandler = handleObj.handler,
            keys = handleObj.data.keys.toLowerCase().split(` `);

        handleObj.handler = function(event) {
      //      Don't fire in text-accepting inputs that we didn't directly bind to
            if (this !== event.target &&
        (jQuery.hotkeys.options.filterInputAcceptingElements &&
          jQuery.hotkeys.textInputTypes.test(event.target.nodeName) ||
          (jQuery.hotkeys.options.filterContentEditable && jQuery(event.target).attr(`contenteditable`)) ||
          (jQuery.hotkeys.options.filterTextInputs &&
            jQuery.inArray(event.target.type, jQuery.hotkeys.textAcceptingInputTypes) > -1))) {
                return;
            }

            var special = event.type !== `keypress` && jQuery.hotkeys.specialKeys[event.which],
                character = String.fromCharCode(event.which).toLowerCase(),
                modif = ``,
                possible = {};

            jQuery.each([`alt`, `ctrl`, `shift`], function(index, specialKey) {

                if (event[specialKey + `Key`] && special !== specialKey) {
                    modif += specialKey + `+`;
                }
            });

      // metaKey is triggered off ctrlKey erronously
            if (event.metaKey && !event.ctrlKey && special !== `meta`) {
                modif += `meta+`;
            }

            if (event.metaKey && special !== `meta` && modif.indexOf(`alt+ctrl+shift+`) > -1) {
                modif = modif.replace(`alt+ctrl+shift+`, `hyper+`);
            }

            if (special) {
                possible[modif + special] = true;
            }
            else {
                possible[modif + character] = true;
                possible[modif + jQuery.hotkeys.shiftNums[character]] = true;

        // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
                if (modif === `shift+`) {
                    possible[jQuery.hotkeys.shiftNums[character]] = true;
                }
            }

            for (var i = 0, l = keys.length; i < l; i++) {
                if (possible[keys[i]]) {
                    return origHandler.apply(this, arguments);
                }
            }
        };
    }

    jQuery.each([`keydown`, `keyup`, `keypress`], function() {
        jQuery.event.special[this] = {
            add: keyHandler
        };
    });

})(jQuery || this.jQuery || window.jQuery);
