mousetrapjs 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  module Mousetrapjs
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -1,7 +1,760 @@
1
- /* mousetrap v1.1 craig.is/killing/mice */
2
- window.Mousetrap=function(){function m(a,e,b){if(a.addEventListener)return a.addEventListener(e,b,!1);a.attachEvent("on"+e,b)}function s(a){return"keypress"!=a.type&&h[a.which]?h[a.which]:"keypress"==a.type?String.fromCharCode(a.which):String.fromCharCode(a.which).toLowerCase()}function n(a){var a=a||{},e=!1,b;for(b in i)a[b]?e=!0:i[b]=0;e||(k=!1)}function t(a,e,b,c,z){var g,d,f=[];if(!j[a])return[];"keyup"==b&&o(a)&&(e=[a]);for(g=0;g<j[a].length;++g)if(d=j[a][g],!(d.seq&&i[d.seq]!=d.level)&&b==d.action&&
3
- ("keypress"===b||e.sort().join(",")===d.modifiers.sort().join(",")))c&&d.combo==z&&j[a].splice(g,1),f.push(d);return f}function p(a){a.which="number"==typeof a.which?a.which:a.keyCode;var e=s(a);if(e)if("keyup"===a.type&&q===e)q=!1;else{var b=a.target||a.srcElement,c=b.tagName;if(!(-1<(" "+b.className+" ").indexOf(" mousetrap ")?0:"INPUT"==c||"SELECT"==c||"TEXTAREA"==c)){b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");for(var b=t(e,b,a.type),
4
- f={},g=!1,c=0;c<b.length;++c)b[c].seq?(g=!0,f[b[c].seq]=1,b[c].callback(a)):!g&&!k&&b[c].callback(a);a.type==k&&!o(e)&&n(f)}}}function o(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function u(a,e,b){if(!b){if(!l){l={};for(var c in h)95<c&&112>c||h.hasOwnProperty(c)&&(l[h[c]]=c)}b=l[a]?"keydown":"keypress"}"keypress"===b&&e.length&&(b="keydown");return b}function A(a,e,b,c){i[a]=0;c||(c=u(e[0],[]));var f=function(){k=c;++i[a];clearTimeout(v);v=setTimeout(n,1E3)},g=function(a){b(a);"keyup"!==
5
- c&&(q=s(a));setTimeout(n,10)},d;for(d=0;d<e.length;++d)w(e[d],d<e.length-1?f:g,c,a,d)}function w(a,e,b,c,f){var a=a.replace(/\s+/g," "),g=a.split(" "),d,h,i=[];if(1<g.length)return A(a,g,e,b);h="+"===a?["+"]:a.split("+");for(g=0;g<h.length;++g)d=h[g],x[d]&&(d=x[d]),b&&("keypress"!=b&&y[d])&&(d=y[d],i.push("shift")),o(d)&&i.push(d);b=u(d,i,b);j[d]||(j[d]=[]);t(d,i,b,!c,a);j[d][c?"unshift":"push"]({callback:e,modifiers:i,action:b,seq:c,level:f,combo:a})}for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",
6
- 17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",46:"del",91:"meta",93:"meta",224:"meta",106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},y={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},x={option:"alt",command:"meta","return":"enter",
7
- escape:"esc"},l,j={},r={},i={},v,q=!1,k=!1,f=1;20>f;++f)h[111+f]="f"+f;for(f=96;106>f;++f)h[f]=f-96;m(document,"keydown",p);m(document,"keyup",p);m(document,"keypress",p);return{bind:function(a,e,b){for(var c=a instanceof Array?a:[a],f=0;f<c.length;++f)w(c[f],e,b);r[a+":"+b]=e},trigger:function(a,e){r[a+":"+e]()},reset:function(){j={};r={}}}}();
1
+ /**
2
+ * Copyright 2012 Craig Campbell
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * Mousetrap is a simple keyboard shortcut library for Javascript with
17
+ * no external dependencies
18
+ *
19
+ * @preserve @version 1.1
20
+ * @url craig.is/killing/mice
21
+ */
22
+ window.Mousetrap = (function() {
23
+
24
+ /**
25
+ * mapping of special keycodes to their corresponding keys
26
+ *
27
+ * @type {Object}
28
+ */
29
+ var _MAP = {
30
+ 8: 'backspace',
31
+ 9: 'tab',
32
+ 13: 'enter',
33
+ 16: 'shift',
34
+ 17: 'ctrl',
35
+ 18: 'alt',
36
+ 20: 'capslock',
37
+ 27: 'esc',
38
+ 32: 'space',
39
+ 33: 'pageup',
40
+ 34: 'pagedown',
41
+ 35: 'end',
42
+ 36: 'home',
43
+ 37: 'left',
44
+ 38: 'up',
45
+ 39: 'right',
46
+ 40: 'down',
47
+ 45: 'ins',
48
+ 46: 'del',
49
+ 91: 'meta',
50
+ 93: 'meta',
51
+ 224: 'meta'
52
+ },
53
+
54
+ /**
55
+ * mapping for special characters so they can support
56
+ * keydown and keyup events
57
+ *
58
+ * @type {Object}
59
+ */
60
+ _KEYCODE_MAP = {
61
+ 106: '*',
62
+ 107: '+',
63
+ 109: '-',
64
+ 110: '.',
65
+ 111 : '/',
66
+ 186: ';',
67
+ 187: '=',
68
+ 188: ',',
69
+ 189: '-',
70
+ 190: '.',
71
+ 191: '/',
72
+ 192: '`',
73
+ 219: '[',
74
+ 220: '\\',
75
+ 221: ']',
76
+ 222: '\''
77
+ },
78
+
79
+ /**
80
+ * this is a mapping of keys that require shift on a US keypad
81
+ * back to the non shift equivelents
82
+ *
83
+ * this is so you can use keyup events with these keys
84
+ *
85
+ * @type {Object}
86
+ */
87
+ _SHIFT_MAP = {
88
+ '~': '`',
89
+ '!': '1',
90
+ '@': '2',
91
+ '#': '3',
92
+ '$': '4',
93
+ '%': '5',
94
+ '^': '6',
95
+ '&': '7',
96
+ '*': '8',
97
+ '(': '9',
98
+ ')': '0',
99
+ '_': '-',
100
+ '+': '=',
101
+ ':': ';',
102
+ '\"': '\'',
103
+ '<': ',',
104
+ '>': '.',
105
+ '?': '/',
106
+ '|': '\\'
107
+ },
108
+
109
+ /**
110
+ * this is a list of special strings you can use to map
111
+ * to modifier keys when you specify your keyboard shortcuts
112
+ *
113
+ * @type {Object}
114
+ */
115
+ _SPECIAL_ALIASES = {
116
+ 'option': 'alt',
117
+ 'command': 'meta',
118
+ 'return': 'enter',
119
+ 'escape': 'esc'
120
+ },
121
+
122
+ /**
123
+ * variable to store the flipped version of _MAP from above
124
+ * needed to check if we should use keypress or not when no action
125
+ * is specified
126
+ *
127
+ * @type {Object|undefined}
128
+ */
129
+ _REVERSE_MAP,
130
+
131
+ /**
132
+ * a list of all the callbacks setup via Mousetrap.bind()
133
+ *
134
+ * @type {Object}
135
+ */
136
+ _callbacks = {},
137
+
138
+ /**
139
+ * direct map of string combinations to callbacks used for trigger()
140
+ *
141
+ * @type {Object}
142
+ */
143
+ _direct_map = {},
144
+
145
+ /**
146
+ * keeps track of what level each sequence is at since multiple
147
+ * sequences can start out with the same sequence
148
+ *
149
+ * @type {Object}
150
+ */
151
+ _sequence_levels = {},
152
+
153
+ /**
154
+ * variable to store the setTimeout call
155
+ *
156
+ * @type {null|number}
157
+ */
158
+ _reset_timer,
159
+
160
+ /**
161
+ * temporary state where we will ignore the next keyup
162
+ *
163
+ * @type {boolean|string}
164
+ */
165
+ _ignore_next_keyup = false,
166
+
167
+ /**
168
+ * are we currently inside of a sequence?
169
+ * type of action ("keyup" or "keydown" or "keypress") or false
170
+ *
171
+ * @type {boolean|string}
172
+ */
173
+ _inside_sequence = false;
174
+
175
+ /**
176
+ * loop through the f keys, f1 to f19 and add them to the map
177
+ * programatically
178
+ */
179
+ for (var i = 1; i < 20; ++i) {
180
+ _MAP[111 + i] = 'f' + i;
181
+ }
182
+
183
+ /**
184
+ * loop through to map numbers on the numeric keypad
185
+ */
186
+ for (i = 96; i < 106; ++i) {
187
+ _MAP[i] = i - 96;
188
+ }
189
+
190
+ /**
191
+ * cross browser add event method
192
+ *
193
+ * @param {Element|HTMLDocument} object
194
+ * @param {string} type
195
+ * @param {Function} callback
196
+ * @returns void
197
+ */
198
+ function _addEvent(object, type, callback) {
199
+ if (object.addEventListener) {
200
+ return object.addEventListener(type, callback, false);
201
+ }
202
+
203
+ object.attachEvent('on' + type, callback);
204
+ }
205
+
206
+ /**
207
+ * takes the event and returns the keycode
208
+ *
209
+ * @param {Event} e
210
+ * @return {string}
211
+ */
212
+ function _characterFromEvent(e) {
213
+
214
+ // for keypress events we should return the character as is
215
+ if (e.type == 'keypress') {
216
+ return String.fromCharCode(e.which);
217
+ }
218
+
219
+ // for non keypress events the special maps are needed
220
+ if (_MAP[e.which]) {
221
+ return _MAP[e.which];
222
+ }
223
+
224
+ if (_KEYCODE_MAP[e.which]) {
225
+ return _KEYCODE_MAP[e.which];
226
+ }
227
+
228
+ // if it is not in the special map
229
+ return String.fromCharCode(e.which).toLowerCase();
230
+ }
231
+
232
+ /**
233
+ * should we stop this event before firing off callbacks
234
+ *
235
+ * @param {Event} e
236
+ * @return {boolean}
237
+ */
238
+ function _stop(e) {
239
+ var element = e.target || e.srcElement,
240
+ tag_name = element.tagName;
241
+
242
+ // if the element has the class "mousetrap" then no need to stop
243
+ if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {
244
+ return false;
245
+ }
246
+
247
+ // stop for input, select, and textarea
248
+ return tag_name == 'INPUT' || tag_name == 'SELECT' || tag_name == 'TEXTAREA'/* || element.getAttribute('contenteditable')*/;
249
+ }
250
+
251
+ /**
252
+ * checks if two arrays are equal
253
+ *
254
+ * @param {Array} modifiers1
255
+ * @param {Array} modifiers2
256
+ * @returns {boolean}
257
+ */
258
+ function _modifiersMatch(modifiers1, modifiers2) {
259
+ return modifiers1.sort().join(',') === modifiers2.sort().join(',');
260
+ }
261
+
262
+ /**
263
+ * resets all sequence counters except for the ones passed in
264
+ *
265
+ * @param {Object} do_not_reset
266
+ * @returns void
267
+ */
268
+ function _resetSequences(do_not_reset) {
269
+ do_not_reset = do_not_reset || {};
270
+
271
+ var active_sequences = false;
272
+
273
+ for (var key in _sequence_levels) {
274
+ if (!do_not_reset[key]) {
275
+ _sequence_levels[key] = 0;
276
+ continue;
277
+ }
278
+ active_sequences = true;
279
+ }
280
+
281
+ if (!active_sequences) {
282
+ _inside_sequence = false;
283
+ }
284
+ }
285
+
286
+ /**
287
+ * finds all callbacks that match based on the keycode, modifiers,
288
+ * and action
289
+ *
290
+ * @param {string} character
291
+ * @param {Array} modifiers
292
+ * @param {string} action
293
+ * @param {boolean=} remove - should we remove any matches
294
+ * @param {string=} combination
295
+ * @returns {Array}
296
+ */
297
+ function _getMatches(character, modifiers, action, remove, combination) {
298
+ var i,
299
+ callback,
300
+ matches = [];
301
+
302
+ // if there are no events related to this keycode
303
+ if (!_callbacks[character]) {
304
+ return [];
305
+ }
306
+
307
+ // if a modifier key is coming up on its own we should allow it
308
+ if (action == 'keyup' && _isModifier(character)) {
309
+ modifiers = [character];
310
+ }
311
+
312
+ // loop through all callbacks for the key that was pressed
313
+ // and see if any of them match
314
+ for (i = 0; i < _callbacks[character].length; ++i) {
315
+ callback = _callbacks[character][i];
316
+
317
+ // if this is a sequence but it is not at the right level
318
+ // then move onto the next match
319
+ if (callback['seq'] && _sequence_levels[callback['seq']] != callback['level']) {
320
+ continue;
321
+ }
322
+
323
+ // if the action we are looking for doesn't match the action we got
324
+ // then we should keep going
325
+ if (action != callback.action) {
326
+ continue;
327
+ }
328
+
329
+ // if this is a keypress event that means that we need to only
330
+ // look at the character, otherwise check the modifiers as
331
+ // well
332
+ if (action === 'keypress' || _modifiersMatch(modifiers, callback.modifiers)) {
333
+
334
+ // remove is used so if you change your mind and call bind a
335
+ // second time with a new function the first one is overwritten
336
+ if (remove && callback['combo'] == combination) {
337
+ _callbacks[character].splice(i, 1);
338
+ }
339
+
340
+ matches.push(callback);
341
+ }
342
+ }
343
+
344
+ return matches;
345
+ }
346
+
347
+ /**
348
+ * takes a key event and figures out what the modifiers are
349
+ *
350
+ * @param {Event} e
351
+ * @returns {Array}
352
+ */
353
+ function _eventModifiers(e) {
354
+ var modifiers = [];
355
+
356
+ if (e.shiftKey) {
357
+ modifiers.push('shift');
358
+ }
359
+
360
+ if (e.altKey) {
361
+ modifiers.push('alt');
362
+ }
363
+
364
+ if (e.ctrlKey) {
365
+ modifiers.push('ctrl');
366
+ }
367
+
368
+ if (e.metaKey) {
369
+ modifiers.push('meta');
370
+ }
371
+
372
+ return modifiers;
373
+ }
374
+
375
+ /**
376
+ * fires a callback for a matching keycode
377
+ *
378
+ * @param {string} character
379
+ * @param {Event} e
380
+ * @returns void
381
+ */
382
+ function _fireCallback(character, e) {
383
+
384
+ // if this event should not happen stop here
385
+ if (_stop(e)) {
386
+ return;
387
+ }
388
+
389
+ var callbacks = _getMatches(character, _eventModifiers(e), e.type),
390
+ i,
391
+ do_not_reset = {},
392
+ processed_sequence_callback = false;
393
+
394
+ // loop through matching callbacks for this key event
395
+ for (i = 0; i < callbacks.length; ++i) {
396
+
397
+ // fire for all sequence callbacks
398
+ // this is because if for example you have multiple sequences
399
+ // bound such as "g i" and "g t" they both need to fire the
400
+ // callback for matching g cause otherwise you can only ever
401
+ // match the first one
402
+ if (callbacks[i]['seq']) {
403
+ processed_sequence_callback = true;
404
+
405
+ // keep a list of which sequences were matches for later
406
+ do_not_reset[callbacks[i]['seq']] = 1;
407
+ callbacks[i].callback(e);
408
+ continue;
409
+ }
410
+
411
+ // if there were no sequence matches but we are still here
412
+ // that means this is a regular match so we should fire then break
413
+ if (!processed_sequence_callback && !_inside_sequence) {
414
+ callbacks[i].callback(e);
415
+ }
416
+ }
417
+
418
+ // if you are inside of a sequence and the key you are pressing
419
+ // is not a modifier key then we should reset all sequences
420
+ // that were not matched by this key event
421
+ if (e.type == _inside_sequence && !_isModifier(character)) {
422
+ _resetSequences(do_not_reset);
423
+ }
424
+ }
425
+
426
+ /**
427
+ * handles a keydown event
428
+ *
429
+ * @param {Event} e
430
+ * @returns void
431
+ */
432
+ function _handleKey(e) {
433
+
434
+ // add which for key events
435
+ // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion
436
+ e.which = typeof e.which == "number" ? e.which : e.keyCode;
437
+
438
+ var character = _characterFromEvent(e);
439
+
440
+ // no character found then stop
441
+ if (!character) {
442
+ return;
443
+ }
444
+
445
+ if (e.type === 'keyup' && _ignore_next_keyup === character) {
446
+ _ignore_next_keyup = false;
447
+ return;
448
+ }
449
+
450
+ _fireCallback(character, e);
451
+ }
452
+
453
+ /**
454
+ * determines if the keycode specified is a modifier key or not
455
+ *
456
+ * @param {string} key
457
+ * @returns {boolean}
458
+ */
459
+ function _isModifier(key) {
460
+ return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta';
461
+ }
462
+
463
+ /**
464
+ * called to set a 1 second timeout on the specified sequence
465
+ *
466
+ * this is so after each key press in the sequence you have 1 second
467
+ * to press the next key before you have to start over
468
+ *
469
+ * @returns void
470
+ */
471
+ function _resetSequence() {
472
+ clearTimeout(_reset_timer);
473
+ _reset_timer = setTimeout(_resetSequences, 1000);
474
+ }
475
+
476
+ /**
477
+ * reverses the map lookup so that we can look for specific keys
478
+ * to see what can and can't use keypress
479
+ *
480
+ * @return {Object}
481
+ */
482
+ function _getReverseMap() {
483
+ if (!_REVERSE_MAP) {
484
+ _REVERSE_MAP = {};
485
+ for (var key in _MAP) {
486
+
487
+ // pull out the numberic keypad from here cause keypress should
488
+ // be able to detect the keys from the character
489
+ if (key > 95 && key < 112) {
490
+ continue;
491
+ }
492
+
493
+ if (_MAP.hasOwnProperty(key)) {
494
+ _REVERSE_MAP[_MAP[key]] = key;
495
+ }
496
+ }
497
+ }
498
+ return _REVERSE_MAP;
499
+ }
500
+
501
+ /**
502
+ * picks the best action based on the key combination
503
+ *
504
+ * @param {string} key - character for key
505
+ * @param {Array} modifiers
506
+ * @param {string=} action passed in
507
+ */
508
+ function _pickBestAction(key, modifiers, action) {
509
+
510
+ // if no action was picked in we should try to pick the one
511
+ // that we think would work best for this key
512
+ if (!action) {
513
+ action = _getReverseMap()[key] ? 'keydown' : 'keypress';
514
+ }
515
+
516
+ // modifier keys don't work as expected with keypress,
517
+ // switch to keydown
518
+ if (action === 'keypress' && modifiers.length) {
519
+ action = 'keydown';
520
+ }
521
+
522
+ return action;
523
+ }
524
+
525
+ /**
526
+ * binds a key sequence to an event
527
+ *
528
+ * @param {string} combo - combo specified in bind call
529
+ * @param {Array} keys
530
+ * @param {Function} callback
531
+ * @param {string=} action
532
+ * @returns void
533
+ */
534
+ function _bindSequence(combo, keys, callback, action) {
535
+
536
+ // start off by adding a sequence level record for this combination
537
+ // and setting the level to 0
538
+ _sequence_levels[combo] = 0;
539
+
540
+ // if there is no action pick the best one for the first key
541
+ // in the sequence
542
+ if (!action) {
543
+ action = _pickBestAction(keys[0], []);
544
+ }
545
+
546
+ /**
547
+ * callback to increase the sequence level for this sequence and reset
548
+ * all other sequences that were active
549
+ *
550
+ * @param {Event} e
551
+ * @returns void
552
+ */
553
+ var _increaseSequence = function(e) {
554
+ _inside_sequence = action;
555
+ ++_sequence_levels[combo];
556
+ _resetSequence();
557
+ },
558
+
559
+ /**
560
+ * wraps the specified callback inside of another function in order
561
+ * to reset all sequence counters as soon as this sequence is done
562
+ *
563
+ * @param {Event} e
564
+ * @returns void
565
+ */
566
+ _callbackAndReset = function(e) {
567
+ callback(e);
568
+
569
+ // we should ignore the next key up if the action is key down
570
+ // or keypress. this is so if you finish a sequence and
571
+ // release the key the final key will not trigger a keyup
572
+ if (action !== 'keyup') {
573
+ _ignore_next_keyup = _characterFromEvent(e);
574
+ }
575
+
576
+ // weird race condition if a sequence ends with the key
577
+ // another sequence begins with
578
+ setTimeout(_resetSequences, 10);
579
+ },
580
+ i;
581
+
582
+ // loop through keys one at a time and bind the appropriate callback
583
+ // function. for any key leading up to the final one it should
584
+ // increase the sequence. after the final, it should reset all sequences
585
+ for (i = 0; i < keys.length; ++i) {
586
+ _bindSingle(keys[i], i < keys.length - 1 ? _increaseSequence : _callbackAndReset, action, combo, i);
587
+ }
588
+ }
589
+
590
+ /**
591
+ * binds a single keyboard combination
592
+ *
593
+ * @param {string} combination
594
+ * @param {Function} callback
595
+ * @param {string=} action
596
+ * @param {string=} sequence_name - name of sequence if part of sequence
597
+ * @param {number=} level - what part of the sequence the command is
598
+ * @returns void
599
+ */
600
+ function _bindSingle(combination, callback, action, sequence_name, level) {
601
+
602
+ // make sure multiple spaces in a row become a single space
603
+ combination = combination.replace(/\s+/g, ' ');
604
+
605
+ var sequence = combination.split(' '),
606
+ i,
607
+ key,
608
+ keys,
609
+ modifiers = [];
610
+
611
+ // if this pattern is a sequence of keys then run through this method
612
+ // to reprocess each pattern one key at a time
613
+ if (sequence.length > 1) {
614
+ return _bindSequence(combination, sequence, callback, action);
615
+ }
616
+
617
+ // take the keys from this pattern and figure out what the actual
618
+ // pattern is all about
619
+ keys = combination === '+' ? ['+'] : combination.split('+');
620
+
621
+ for (i = 0; i < keys.length; ++i) {
622
+ key = keys[i];
623
+
624
+ // normalize key names
625
+ if (_SPECIAL_ALIASES[key]) {
626
+ key = _SPECIAL_ALIASES[key];
627
+ }
628
+
629
+ // if this is not a keypress event then we should
630
+ // be smart about using shift keys
631
+ // this will only work for US keyboards however
632
+ if (action && action != 'keypress' && _SHIFT_MAP[key]) {
633
+ key = _SHIFT_MAP[key];
634
+ modifiers.push('shift');
635
+ }
636
+
637
+ // if this key is a modifier then add it to the list of modifiers
638
+ if (_isModifier(key)) {
639
+ modifiers.push(key);
640
+ }
641
+ }
642
+
643
+ // depending on what the key combination is
644
+ // we will try to pick the best event for it
645
+ action = _pickBestAction(key, modifiers, action);
646
+
647
+ // make sure to initialize array if this is the first time
648
+ // a callback is added for this key
649
+ if (!_callbacks[key]) {
650
+ _callbacks[key] = [];
651
+ }
652
+
653
+ // remove an existing match if there is one
654
+ _getMatches(key, modifiers, action, !sequence_name, combination);
655
+
656
+ // add this call back to the array
657
+ // if it is a sequence put it at the beginning
658
+ // if not put it at the end
659
+ //
660
+ // this is important because the way these are processed expects
661
+ // the sequence ones to come first
662
+ _callbacks[key][sequence_name ? 'unshift' : 'push']({
663
+ callback: callback,
664
+ modifiers: modifiers,
665
+ action: action,
666
+ seq: sequence_name,
667
+ level: level,
668
+ combo: combination
669
+ });
670
+ }
671
+
672
+ /**
673
+ * binds multiple combinations to the same callback
674
+ *
675
+ * @param {Array} combinations
676
+ * @param {Function} callback
677
+ * @param {string|undefined} action
678
+ * @returns void
679
+ */
680
+ function _bindMultiple(combinations, callback, action) {
681
+ for (var i = 0; i < combinations.length; ++i) {
682
+ _bindSingle(combinations[i], callback, action);
683
+ }
684
+ }
685
+
686
+ // start!
687
+ _addEvent(document, 'keydown', _handleKey);
688
+ _addEvent(document, 'keyup', _handleKey);
689
+ _addEvent(document, 'keypress', _handleKey);
690
+
691
+ return {
692
+
693
+ /**
694
+ * binds an event to mousetrap
695
+ *
696
+ * can be a single key, a combination of keys separated with +,
697
+ * a comma separated list of keys, an array of keys, or
698
+ * a sequence of keys separated by spaces
699
+ *
700
+ * be sure to list the modifier keys first to make sure that the
701
+ * correct key ends up getting bound (the last key in the pattern)
702
+ *
703
+ * @param {string|Array} keys
704
+ * @param {Function} callback
705
+ * @param {string=} action - 'keypress', 'keydown', or 'keyup'
706
+ * @returns void
707
+ */
708
+ bind: function(keys, callback, action) {
709
+ _bindMultiple(keys instanceof Array ? keys : [keys], callback, action);
710
+ _direct_map[keys + ':' + action] = callback;
711
+ },
712
+
713
+ /**
714
+ * unbinds an event to mousetrap
715
+ *
716
+ * the unbinding sets the callback function of the specified key combo
717
+ * to an empty function and deletes the corresponding key in the
718
+ * _direct_map dict.
719
+ *
720
+ * the keycombo+action has to be exactly the same as
721
+ * it was defined in the bind method
722
+ *
723
+ * @todo actually remove this from the _callbacks dictionary instead
724
+ * of binding an empty function
725
+ *
726
+ * @param {string|Array} keys
727
+ * @param {string} action
728
+ * @returns void
729
+ */
730
+ unbind: function(keys, action) {
731
+ if (_direct_map[keys + ':' + action]) {
732
+ delete _direct_map[keys + ':' + action];
733
+ this.bind(keys, function() {}, action);
734
+ }
735
+ },
736
+
737
+ /**
738
+ * triggers an event that has already been bound
739
+ *
740
+ * @param {string} keys
741
+ * @param {string=} action
742
+ * @returns void
743
+ */
744
+ trigger: function(keys, action) {
745
+ _direct_map[keys + ':' + action]();
746
+ },
747
+
748
+ /**
749
+ * resets the library back to its initial state. this is useful
750
+ * if you want to clear out the current keyboard shortcuts and bind
751
+ * new ones - for example if you switch to another page
752
+ *
753
+ * @returns void
754
+ */
755
+ reset: function() {
756
+ _callbacks = {};
757
+ _direct_map = {};
758
+ }
759
+ };
760
+ }) ();
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mousetrapjs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-09 00:00:00.000000000 Z
12
+ date: 2012-07-11 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Gem for Mousetrap js lib
15
15
  email:
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
47
47
  version: '0'
48
48
  requirements: []
49
49
  rubyforge_project:
50
- rubygems_version: 1.8.23
50
+ rubygems_version: 1.8.22
51
51
  signing_key:
52
52
  specification_version: 3
53
53
  summary: Gem for Mousetrap js lib