ultimix

- Main Page
- Data Structures
- Files
- Examples

- File List
- Globals

jquery.hotkeys.js
Go to the documentation of this file.
1 /*
2 (c) Copyrights 2007 - 2008
3
4 Original idea by by Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
5
6 jQuery Plugin by Tzury Bar Yochay
7 tzury.by@gmail.com
8 http://evalinux.wordpress.com
9 http://facebook.com/profile.php?id=513676303
10
11 Project's sites:
12 http://code.google.com/p/js-hotkeys/
13 http://github.com/tzuryby/hotkeys/tree/master
14
15 License: same as jQuery license.
16
17 USAGE:
18 // simple usage
19 $(document).bind('keydown', 'Ctrl+c', function(){ alert('copy anyone?');});
20
21 // special options such as disableInIput
22 $(document).bind('keydown', {combi:'Ctrl+x', disableInInput: true} , function() {});
23
24 Note:
25 This plugin wraps the following jQuery methods: $.fn.find, $.fn.bind and $.fn.unbind
26
27 */
28
29
30 (function (jQuery){
31 // keep reference to the original $.fn.bind and $.fn.unbind
32 jQuery.fn.__bind__ = jQuery.fn.bind;
33 jQuery.fn.__unbind__ = jQuery.fn.unbind;
34 jQuery.fn.__find__ = jQuery.fn.find;
35
36 var hotkeys = {
37 version: '0.7.8',
38 override: /keydown|keypress|keyup/g,
39 triggersMap: {},
40
41 specialKeys: { 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll',
42 20: 'capslock', 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',
43 35:'end', 33: 'pageup', 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down',
44 112:'f1',113:'f2', 114:'f3', 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8',
45 120:'f9', 121:'f10', 122:'f11', 123:'f12' },
46
47 shiftNums: { "`":"~", "1":"!", "2":"@", "3":"#", "4":"$", "5":"%", "6":"^", "7":"&",
48 "8":"*", "9":"(", "0":")", "-":"_", "=":"+", ";":":", "'":"\"", ",":"<",
49 ".":">", "/":"?", "\\":"|" },
50
51 newTrigger: function (type, combi, callback) {
52 // i.e. {'keyup': {'ctrl': {cb: callback, disableInInput: false}}}
53 var result = {};
54 result[type] = {};
55 result[type][combi] = {cb: callback, disableInInput: false};
56 return result;
57 }
58 };
59 // add firefox num pad char codes
60 if (jQuery.browser.mozilla){
61 hotkeys.specialKeys = jQuery.extend(hotkeys.specialKeys, { 96: '0', 97:'1', 98: '2', 99:
62 '3', 100: '4', 101: '5', 102: '6', 103: '7', 104: '8', 105: '9' });
63 }
64
65 // a wrapper around of $.fn.find
66 // see more at: http://groups.google.com/group/jquery-en/browse_thread/thread/18f9825e8d22f18d
67 jQuery.fn.find = function( selector ) {
68 this.query=selector;
69 return jQuery.fn.__find__.apply(this, arguments);
70 };
71
72 jQuery.fn.unbind = function (type, combi, fn){
73 if (jQuery.isFunction(combi)){
74 fn = combi;
75 combi = null;
76 }
77 if (combi && typeof combi === 'string'){
78 var selectorId = ((this.prevObject && this.prevObject.query) || (this[0].id && this[0].id) || this[0]).toString();
79 var hkTypes = type.split(' ');
80 for (var x=0; x<hkTypes.length; x++){
81 delete hotkeys.triggersMap[selectorId][hkTypes[x]][combi];
82 }
83 }
84 // call jQuery original unbind
85 return this.__unbind__(type, fn);
86 };
87
88 jQuery.fn.bind = function(type, data, fn){
89 // grab keyup,keydown,keypress
90 var handle = type.match(hotkeys.override);
91
92 if (jQuery.isFunction(data) || !handle){
93 // call jQuery.bind only
94 return this.__bind__(type, data, fn);
95 }
96 else{
97 // split the job
98 var result = null,
99 // pass the rest to the original $.fn.bind
100 pass2jq = jQuery.trim(type.replace(hotkeys.override, ''));
101
102 // see if there are other types, pass them to the original $.fn.bind
103 if (pass2jq){
104 // call original jQuery.bind()
105 result = this.__bind__(pass2jq, data, fn);
106 }
107
108 if (typeof data === "string"){
109 data = {'combi': data};
110 }
111 if(data.combi){
112 for (var x=0; x < handle.length; x++){
113 var eventType = handle[x];
114 var combi = data.combi.toLowerCase(),
115 trigger = hotkeys.newTrigger(eventType, combi, fn),
116 selectorId = ((this.prevObject && this.prevObject.query) || (this[0].id && this[0].id) || this[0]).toString();
117
118 //trigger[eventType][combi].propagate = data.propagate;
119 trigger[eventType][combi].disableInInput = data.disableInInput;
120
121 // first time selector is bounded
122 if (!hotkeys.triggersMap[selectorId]) {
123 hotkeys.triggersMap[selectorId] = trigger;
124 }
125 // first time selector is bounded with this type
126 else if (!hotkeys.triggersMap[selectorId][eventType]) {
127 hotkeys.triggersMap[selectorId][eventType] = trigger[eventType];
128 }
129 // make trigger point as array so more than one handler can be bound
130 var mapPoint = hotkeys.triggersMap[selectorId][eventType][combi];
131 if (!mapPoint){
132 hotkeys.triggersMap[selectorId][eventType][combi] = [trigger[eventType][combi]];
133 }
134 else if (mapPoint.constructor !== Array){
135 hotkeys.triggersMap[selectorId][eventType][combi] = [mapPoint];
136 }
137 else {
138 hotkeys.triggersMap[selectorId][eventType][combi][mapPoint.length] = trigger[eventType][combi];
139 }
140
141 // add attribute and call $.event.add per matched element
142 this.each(function(){
143 // jQuery wrapper for the current element
144 var jqElem = jQuery(this);
145
146 // element already associated with another collection
147 if (jqElem.attr('hkId') && jqElem.attr('hkId') !== selectorId){
148 selectorId = jqElem.attr('hkId') + ";" + selectorId;
149 }
150 jqElem.attr('hkId', selectorId);
151 });
152 result = this.__bind__(handle.join(' '), data, hotkeys.handler)
153 }
154 }
155 return result;
156 }
157 };
158 // work-around for opera and safari where (sometimes) the target is the element which was last
159 // clicked with the mouse and not the document event it would make sense to get the document
160 hotkeys.findElement = function (elem){
161 if (!jQuery(elem).attr('hkId')){
162 if (jQuery.browser.opera || jQuery.browser.safari){
163 while (!jQuery(elem).attr('hkId') && elem.parentNode){
164 elem = elem.parentNode;
165 }
166 }
167 }
168 return elem;
169 };
170 // the event handler
171 hotkeys.handler = function(event) {
172 var target = hotkeys.findElement(event.currentTarget),
173 jTarget = jQuery(target),
174 ids = jTarget.attr('hkId');
175
176 if(ids){
177 ids = ids.split(';');
178 var code = event.which,
179 type = event.type,
180 special = hotkeys.specialKeys[code],
181 // prevent f5 overlapping with 't' (or f4 with 's', etc.)
182 character = !special && String.fromCharCode(code).toLowerCase(),
183 shift = event.shiftKey,
184 ctrl = event.ctrlKey,
185 // patch for jquery 1.2.5 && 1.2.6 see more at:
186 // http://groups.google.com/group/jquery-en/browse_thread/thread/83e10b3bb1f1c32b
187 alt = event.altKey || event.originalEvent.altKey,
188 mapPoint = null;
189
190 for (var x=0; x < ids.length; x++){
191 if (hotkeys.triggersMap[ids[x]][type]){
192 mapPoint = hotkeys.triggersMap[ids[x]][type];
193 break;
194 }
195 }
196
197 //find by: id.type.combi.options
198 if (mapPoint){
199 var trigger;
200 // event type is associated with the hkId
201 if(!shift && !ctrl && !alt) { // No Modifiers
202 trigger = mapPoint[special] || (character && mapPoint[character]);
203 }
204 else{
205 // check combinations (alt|ctrl|shift+anything)
206 var modif = '';
207 if(alt) modif +='alt+';
208 if(ctrl) modif+= 'ctrl+';
209 if(shift) modif += 'shift+';
210
211 // modifiers + special keys or modifiers + character or modifiers + shift character or just shift character
212 trigger = mapPoint[modif+special];
213 if (!trigger){
214 if (character){
215 trigger = mapPoint[modif+character]
216 || mapPoint[modif+hotkeys.shiftNums[character]]
217 // '$' can be triggered as 'Shift+4' or 'Shift+$' or just '$'
218 || (modif === 'shift+' && mapPoint[hotkeys.shiftNums[character]]);
219 }
220 }
221 }
222 if (trigger){
223 var result = false;
224 for (var x=0; x < trigger.length; x++){
225 if(trigger[x].disableInInput){
226 // double check event.currentTarget and event.target
227 var elem = jQuery(event.target);
228 if (jTarget.is("input") || jTarget.is("textarea")
229 || elem.is("input") || elem.is("textarea")) {
230 return true;
231 }
232 }
233 // call the registered callback function
234 result = result || trigger[x].cb.apply(this, [event]);
235 }
236 return result;
237 }
238 }
239 }
240 };
241 // place it under window so it can be extended and overridden by others
242 window.hotkeys = hotkeys;
243 return jQuery;
244 })(jQuery);