21 | | USAGE: |
22 | | $.hotkeys.add('Ctrl+c', function(){ alert('copy anyone?');}); |
23 | | $.hotkeys.add('Ctrl+c', {target:'div#editor', type:'keyup', propagate: true},function(){ alert('copy anyone?');});> |
24 | | $.hotkeys.remove('Ctrl+c'); |
25 | | $.hotkeys.remove('Ctrl+c', {target:'div#editor', type:'keypress'}); |
26 | | |
27 | | ******************************************************************************************************************************/ |
28 | | (function (jQuery){ |
29 | | this.version = '(beta)(0.0.3)'; |
30 | | this.all = {}; |
31 | | this.special_keys = { |
32 | | 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll', 20: 'capslock', |
33 | | 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',35:'end', 33: 'pageup', |
34 | | 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down', 112:'f1',113:'f2', 114:'f3', |
35 | | 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8', 120:'f9', 121:'f10', 122:'f11', 123:'f12'}; |
36 | | |
37 | | this.shift_nums = { "`":"~", "1":"!", "2":"@", "3":"#", "4":"$", "5":"%", "6":"^", "7":"&", |
38 | | "8":"*", "9":"(", "0":")", "-":"_", "=":"+", ";":":", "'":"\"", ",":"<", |
39 | | ".":">", "/":"?", "\\":"|" }; |
40 | | |
41 | | this.add = function(combi, options, callback) { |
42 | | if (jQuery.isFunction(options)){ |
43 | | callback = options; |
44 | | options = {}; |
45 | | } |
46 | | var opt = {}, |
47 | | defaults = {type: 'keydown', propagate: false, disableInInput: false, target: jQuery('html')[0]}, |
48 | | that = this; |
49 | | opt = jQuery.extend( opt , defaults, options || {} ); |
50 | | combi = combi.toLowerCase(); |
51 | | |
52 | | // inspect if keystroke matches |
53 | | var inspector = function(event) { |
54 | | event = jQuery.event.fix(event); // jQuery event normalization. |
55 | | var element = event.target; |
56 | | // @ TextNode -> nodeType == 3 |
57 | | element = (element.nodeType==3) ? element.parentNode : element; |
58 | | |
59 | | if(opt['disableInInput']) { // Disable shortcut keys in Input, Textarea fields |
60 | | var target = jQuery(element); |
61 | | if( target.is("input") || target.is("textarea")){ |
62 | | return; |
63 | | } |
64 | | } |
65 | | var code = event.which, |
66 | | type = event.type, |
67 | | character = String.fromCharCode(code).toLowerCase(), |
68 | | special = that.special_keys[code], |
69 | | shift = event.shiftKey, |
70 | | ctrl = event.ctrlKey, |
71 | | alt= event.altKey, |
72 | | meta = event.metaKey, |
73 | | propagate = true, // default behaivour |
74 | | mapPoint = null; |
75 | | |
76 | | // in opera + safari, the event.target is unpredictable. |
77 | | // for example: 'keydown' might be associated with HtmlBodyElement |
78 | | // or the element where you last clicked with your mouse. |
79 | | if (jQuery.browser.opera || jQuery.browser.safari){ |
80 | | while (!that.all[element] && element.parentNode){ |
81 | | element = element.parentNode; |
82 | | } |
83 | | } |
84 | | var cbMap = that.all[element].events[type].callbackMap; |
85 | | if(!shift && !ctrl && !alt && !meta) { // No Modifiers |
86 | | mapPoint = cbMap[special] || cbMap[character] |
| 15 | jQuery.hotkeys = { |
| 16 | version: "0.8+", |
| 17 | |
| 18 | specialKeys: { |
| 19 | 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", |
| 20 | 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", |
| 21 | 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", |
| 22 | 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", |
| 23 | 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", |
| 24 | 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", |
| 25 | 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 188: ",", 190: ".", |
| 26 | 191: "/", 224: "meta" |
| 27 | }, |
| 28 | |
| 29 | shiftNums: { |
| 30 | "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", |
| 31 | "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", |
| 32 | ".": ">", "/": "?", "\\": "|" |
| 33 | } |
| 34 | }; |
| 35 | |
| 36 | function keyHandler( handleObj ) { |
| 37 | |
| 38 | var origHandler = handleObj.handler, |
| 39 | //use namespace as keys so it works with event delegation as well |
| 40 | //will also allow removing listeners of a specific key combination |
| 41 | //and support data objects |
| 42 | keys = (handleObj.namespace || "").toLowerCase().split(" "); |
| 43 | keys = jQuery.map(keys, function(key) { return key.split("."); }); |
| 44 | |
| 45 | //no need to modify handler if no keys specified |
| 46 | if (keys.length === 1 && (keys[0] === "" || keys[0] === "autocomplete")) { |
| 47 | return; |
| 48 | } |
| 49 | |
| 50 | handleObj.handler = function( event ) { |
| 51 | // Don't fire in text-accepting inputs that we didn't directly bind to |
| 52 | // important to note that $.fn.prop is only available on jquery 1.6+ |
| 53 | if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || |
| 54 | event.target.type === "text" || jQuery(event.target).prop('contenteditable') == 'true' )) { |
| 55 | return; |
88 | | // deals with combinaitons (alt|ctrl|shift+anything) |
89 | | else{ |
90 | | var modif = ''; |
91 | | if(alt) modif +='alt+'; |
92 | | if(ctrl) modif+= 'ctrl+'; |
93 | | if(shift) modif += 'shift+'; |
94 | | if(meta) modif += 'meta+'; |
95 | | // modifiers + special keys or modifiers + characters or modifiers + shift characters |
96 | | mapPoint = cbMap[modif+special] || cbMap[modif+character] || cbMap[modif+that.shift_nums[character]] |
97 | | } |
98 | | if (mapPoint){ |
99 | | mapPoint.cb(event); |
100 | | if(!mapPoint.propagate) { |
101 | | event.stopPropagation(); |
102 | | event.preventDefault(); |
103 | | return false; |
104 | | } |
105 | | } |
106 | | }; |
107 | | // first hook for this element |
108 | | if (!this.all[opt.target]){ |
109 | | this.all[opt.target] = {events:{}}; |
110 | | } |
111 | | if (!this.all[opt.target].events[opt.type]){ |
112 | | this.all[opt.target].events[opt.type] = {callbackMap: {}} |
113 | | jQuery.event.add(opt.target, opt.type, inspector); |
114 | | } |
115 | | this.all[opt.target].events[opt.type].callbackMap[combi] = {cb: callback, propagate:opt.propagate}; |
116 | | return jQuery; |
117 | | }; |
118 | | this.remove = function(exp, opt) { |
119 | | opt = opt || {}; |
120 | | target = opt.target || jQuery('html')[0]; |
121 | | type = opt.type || 'keydown'; |
122 | | exp = exp.toLowerCase(); |
123 | | delete this.all[target].events[type].callbackMap[exp] |
124 | | return jQuery; |
125 | | }; |
126 | | jQuery.hotkeys = this; |
127 | | return jQuery; |
128 | | })(jQuery); |
129 | | No newline at end of file |
| 57 | |
| 58 | // Keypress represents characters, not special keys |
| 59 | var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ], |
| 60 | character = String.fromCharCode( event.which ).toLowerCase(), |
| 61 | key, modif = "", possible = {}; |
| 62 | |
| 63 | // check combinations (alt|ctrl|shift+anything) |
| 64 | if ( event.altKey && special !== "alt" ) { |
| 65 | modif += "alt_"; |
| 66 | } |
| 67 | |
| 68 | if ( event.ctrlKey && special !== "ctrl" ) { |
| 69 | modif += "ctrl_"; |
| 70 | } |
| 71 | |
| 72 | // TODO: Need to make sure this works consistently across platforms |
| 73 | if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { |
| 74 | modif += "meta_"; |
| 75 | } |
| 76 | |
| 77 | if ( event.shiftKey && special !== "shift" ) { |
| 78 | modif += "shift_"; |
| 79 | } |
| 80 | |
| 81 | if ( special ) { |
| 82 | possible[ modif + special ] = true; |
| 83 | |
| 84 | } else { |
| 85 | possible[ modif + character ] = true; |
| 86 | possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; |
| 87 | |
| 88 | // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" |
| 89 | if ( modif === "shift_" ) { |
| 90 | possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | for ( var i = 0, l = keys.length; i < l; i++ ) { |
| 95 | if ( possible[ keys[i] ] ) { |
| 96 | return origHandler.apply( this, arguments ); |
| 97 | } |
| 98 | } |
| 99 | }; |
| 100 | } |
| 101 | |
| 102 | jQuery.each([ "keydown", "keyup", "keypress" ], function() { |
| 103 | jQuery.event.special[ this ] = { add: keyHandler }; |
| 104 | }); |
| 105 | |
| 106 | })( jQuery ); |