/*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);