@ntlab/ntjs-assets 2.0.1 → 2.0.2

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.
Files changed (29) hide show
  1. package/assets/js/mousetrap/Gruntfile.js +35 -0
  2. package/assets/js/mousetrap/LICENSE +193 -0
  3. package/assets/js/mousetrap/README.md +101 -0
  4. package/assets/js/mousetrap/mousetrap.js +1058 -0
  5. package/assets/js/mousetrap/mousetrap.min.js +11 -0
  6. package/assets/js/mousetrap/mousetrap.sublime-project +20 -0
  7. package/assets/js/mousetrap/package-lock.json +1979 -0
  8. package/assets/js/mousetrap/package.json +34 -0
  9. package/assets/js/mousetrap/plugins/README.md +24 -0
  10. package/assets/js/mousetrap/plugins/bind-dictionary/README.md +16 -0
  11. package/assets/js/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.js +39 -0
  12. package/assets/js/mousetrap/plugins/bind-dictionary/mousetrap-bind-dictionary.min.js +1 -0
  13. package/assets/js/mousetrap/plugins/global-bind/README.md +15 -0
  14. package/assets/js/mousetrap/plugins/global-bind/mousetrap-global-bind.js +46 -0
  15. package/assets/js/mousetrap/plugins/global-bind/mousetrap-global-bind.min.js +1 -0
  16. package/assets/js/mousetrap/plugins/pause/README.md +13 -0
  17. package/assets/js/mousetrap/plugins/pause/mousetrap-pause.js +31 -0
  18. package/assets/js/mousetrap/plugins/pause/mousetrap-pause.min.js +1 -0
  19. package/assets/js/mousetrap/plugins/record/README.md +16 -0
  20. package/assets/js/mousetrap/plugins/record/mousetrap-record.js +205 -0
  21. package/assets/js/mousetrap/plugins/record/mousetrap-record.min.js +2 -0
  22. package/assets/js/mousetrap/plugins/record/tests/index.html +29 -0
  23. package/assets/js/mousetrap/plugins/record/tests/jelly.css +18 -0
  24. package/assets/js/mousetrap/plugins/record/tests/jelly.js +53 -0
  25. package/assets/js/mousetrap/tests/libs/jquery-1.7.2.min.js +4 -0
  26. package/assets/js/mousetrap/tests/libs/key-event.js +158 -0
  27. package/assets/js/mousetrap/tests/mousetrap.html +24 -0
  28. package/assets/js/mousetrap/tests/test.mousetrap.js +772 -0
  29. package/package.json +1 -1
@@ -0,0 +1,1058 @@
1
+ /*global define:false */
2
+ /**
3
+ * Copyright 2012-2017 Craig Campbell
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ *
17
+ * Mousetrap is a simple keyboard shortcut library for Javascript with
18
+ * no external dependencies
19
+ *
20
+ * @version 1.6.5
21
+ * @url craig.is/killing/mice
22
+ */
23
+ (function(window, document, undefined) {
24
+
25
+ // Check if mousetrap is used inside browser, if not, return
26
+ if (!window) {
27
+ return;
28
+ }
29
+
30
+ /**
31
+ * mapping of special keycodes to their corresponding keys
32
+ *
33
+ * everything in this dictionary cannot use keypress events
34
+ * so it has to be here to map to the correct keycodes for
35
+ * keyup/keydown events
36
+ *
37
+ * @type {Object}
38
+ */
39
+ var _MAP = {
40
+ 8: 'backspace',
41
+ 9: 'tab',
42
+ 13: 'enter',
43
+ 16: 'shift',
44
+ 17: 'ctrl',
45
+ 18: 'alt',
46
+ 20: 'capslock',
47
+ 27: 'esc',
48
+ 32: 'space',
49
+ 33: 'pageup',
50
+ 34: 'pagedown',
51
+ 35: 'end',
52
+ 36: 'home',
53
+ 37: 'left',
54
+ 38: 'up',
55
+ 39: 'right',
56
+ 40: 'down',
57
+ 45: 'ins',
58
+ 46: 'del',
59
+ 91: 'meta',
60
+ 93: 'meta',
61
+ 224: 'meta'
62
+ };
63
+
64
+ /**
65
+ * mapping for special characters so they can support
66
+ *
67
+ * this dictionary is only used incase you want to bind a
68
+ * keyup or keydown event to one of these keys
69
+ *
70
+ * @type {Object}
71
+ */
72
+ var _KEYCODE_MAP = {
73
+ 106: '*',
74
+ 107: '+',
75
+ 109: '-',
76
+ 110: '.',
77
+ 111 : '/',
78
+ 186: ';',
79
+ 187: '=',
80
+ 188: ',',
81
+ 189: '-',
82
+ 190: '.',
83
+ 191: '/',
84
+ 192: '`',
85
+ 219: '[',
86
+ 220: '\\',
87
+ 221: ']',
88
+ 222: '\''
89
+ };
90
+
91
+ /**
92
+ * this is a mapping of keys that require shift on a US keypad
93
+ * back to the non shift equivelents
94
+ *
95
+ * this is so you can use keyup events with these keys
96
+ *
97
+ * note that this will only work reliably on US keyboards
98
+ *
99
+ * @type {Object}
100
+ */
101
+ var _SHIFT_MAP = {
102
+ '~': '`',
103
+ '!': '1',
104
+ '@': '2',
105
+ '#': '3',
106
+ '$': '4',
107
+ '%': '5',
108
+ '^': '6',
109
+ '&': '7',
110
+ '*': '8',
111
+ '(': '9',
112
+ ')': '0',
113
+ '_': '-',
114
+ '+': '=',
115
+ ':': ';',
116
+ '\"': '\'',
117
+ '<': ',',
118
+ '>': '.',
119
+ '?': '/',
120
+ '|': '\\'
121
+ };
122
+
123
+ /**
124
+ * this is a list of special strings you can use to map
125
+ * to modifier keys when you specify your keyboard shortcuts
126
+ *
127
+ * @type {Object}
128
+ */
129
+ var _SPECIAL_ALIASES = {
130
+ 'option': 'alt',
131
+ 'command': 'meta',
132
+ 'return': 'enter',
133
+ 'escape': 'esc',
134
+ 'plus': '+',
135
+ 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl'
136
+ };
137
+
138
+ /**
139
+ * variable to store the flipped version of _MAP from above
140
+ * needed to check if we should use keypress or not when no action
141
+ * is specified
142
+ *
143
+ * @type {Object|undefined}
144
+ */
145
+ var _REVERSE_MAP;
146
+
147
+ /**
148
+ * loop through the f keys, f1 to f19 and add them to the map
149
+ * programatically
150
+ */
151
+ for (var i = 1; i < 20; ++i) {
152
+ _MAP[111 + i] = 'f' + i;
153
+ }
154
+
155
+ /**
156
+ * loop through to map numbers on the numeric keypad
157
+ */
158
+ for (i = 0; i <= 9; ++i) {
159
+
160
+ // This needs to use a string cause otherwise since 0 is falsey
161
+ // mousetrap will never fire for numpad 0 pressed as part of a keydown
162
+ // event.
163
+ //
164
+ // @see https://github.com/ccampbell/mousetrap/pull/258
165
+ _MAP[i + 96] = i.toString();
166
+ }
167
+
168
+ /**
169
+ * cross browser add event method
170
+ *
171
+ * @param {Element|HTMLDocument} object
172
+ * @param {string} type
173
+ * @param {Function} callback
174
+ * @returns void
175
+ */
176
+ function _addEvent(object, type, callback) {
177
+ if (object.addEventListener) {
178
+ object.addEventListener(type, callback, false);
179
+ return;
180
+ }
181
+
182
+ object.attachEvent('on' + type, callback);
183
+ }
184
+
185
+ /**
186
+ * takes the event and returns the key character
187
+ *
188
+ * @param {Event} e
189
+ * @return {string}
190
+ */
191
+ function _characterFromEvent(e) {
192
+
193
+ // for keypress events we should return the character as is
194
+ if (e.type == 'keypress') {
195
+ var character = String.fromCharCode(e.which);
196
+
197
+ // if the shift key is not pressed then it is safe to assume
198
+ // that we want the character to be lowercase. this means if
199
+ // you accidentally have caps lock on then your key bindings
200
+ // will continue to work
201
+ //
202
+ // the only side effect that might not be desired is if you
203
+ // bind something like 'A' cause you want to trigger an
204
+ // event when capital A is pressed caps lock will no longer
205
+ // trigger the event. shift+a will though.
206
+ if (!e.shiftKey) {
207
+ character = character.toLowerCase();
208
+ }
209
+
210
+ return character;
211
+ }
212
+
213
+ // for non keypress events the special maps are needed
214
+ if (_MAP[e.which]) {
215
+ return _MAP[e.which];
216
+ }
217
+
218
+ if (_KEYCODE_MAP[e.which]) {
219
+ return _KEYCODE_MAP[e.which];
220
+ }
221
+
222
+ // if it is not in the special map
223
+
224
+ // with keydown and keyup events the character seems to always
225
+ // come in as an uppercase character whether you are pressing shift
226
+ // or not. we should make sure it is always lowercase for comparisons
227
+ return String.fromCharCode(e.which).toLowerCase();
228
+ }
229
+
230
+ /**
231
+ * checks if two arrays are equal
232
+ *
233
+ * @param {Array} modifiers1
234
+ * @param {Array} modifiers2
235
+ * @returns {boolean}
236
+ */
237
+ function _modifiersMatch(modifiers1, modifiers2) {
238
+ return modifiers1.sort().join(',') === modifiers2.sort().join(',');
239
+ }
240
+
241
+ /**
242
+ * takes a key event and figures out what the modifiers are
243
+ *
244
+ * @param {Event} e
245
+ * @returns {Array}
246
+ */
247
+ function _eventModifiers(e) {
248
+ var modifiers = [];
249
+
250
+ if (e.shiftKey) {
251
+ modifiers.push('shift');
252
+ }
253
+
254
+ if (e.altKey) {
255
+ modifiers.push('alt');
256
+ }
257
+
258
+ if (e.ctrlKey) {
259
+ modifiers.push('ctrl');
260
+ }
261
+
262
+ if (e.metaKey) {
263
+ modifiers.push('meta');
264
+ }
265
+
266
+ return modifiers;
267
+ }
268
+
269
+ /**
270
+ * prevents default for this event
271
+ *
272
+ * @param {Event} e
273
+ * @returns void
274
+ */
275
+ function _preventDefault(e) {
276
+ if (e.preventDefault) {
277
+ e.preventDefault();
278
+ return;
279
+ }
280
+
281
+ e.returnValue = false;
282
+ }
283
+
284
+ /**
285
+ * stops propogation for this event
286
+ *
287
+ * @param {Event} e
288
+ * @returns void
289
+ */
290
+ function _stopPropagation(e) {
291
+ if (e.stopPropagation) {
292
+ e.stopPropagation();
293
+ return;
294
+ }
295
+
296
+ e.cancelBubble = true;
297
+ }
298
+
299
+ /**
300
+ * determines if the keycode specified is a modifier key or not
301
+ *
302
+ * @param {string} key
303
+ * @returns {boolean}
304
+ */
305
+ function _isModifier(key) {
306
+ return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta';
307
+ }
308
+
309
+ /**
310
+ * reverses the map lookup so that we can look for specific keys
311
+ * to see what can and can't use keypress
312
+ *
313
+ * @return {Object}
314
+ */
315
+ function _getReverseMap() {
316
+ if (!_REVERSE_MAP) {
317
+ _REVERSE_MAP = {};
318
+ for (var key in _MAP) {
319
+
320
+ // pull out the numeric keypad from here cause keypress should
321
+ // be able to detect the keys from the character
322
+ if (key > 95 && key < 112) {
323
+ continue;
324
+ }
325
+
326
+ if (_MAP.hasOwnProperty(key)) {
327
+ _REVERSE_MAP[_MAP[key]] = key;
328
+ }
329
+ }
330
+ }
331
+ return _REVERSE_MAP;
332
+ }
333
+
334
+ /**
335
+ * picks the best action based on the key combination
336
+ *
337
+ * @param {string} key - character for key
338
+ * @param {Array} modifiers
339
+ * @param {string=} action passed in
340
+ */
341
+ function _pickBestAction(key, modifiers, action) {
342
+
343
+ // if no action was picked in we should try to pick the one
344
+ // that we think would work best for this key
345
+ if (!action) {
346
+ action = _getReverseMap()[key] ? 'keydown' : 'keypress';
347
+ }
348
+
349
+ // modifier keys don't work as expected with keypress,
350
+ // switch to keydown
351
+ if (action == 'keypress' && modifiers.length) {
352
+ action = 'keydown';
353
+ }
354
+
355
+ return action;
356
+ }
357
+
358
+ /**
359
+ * Converts from a string key combination to an array
360
+ *
361
+ * @param {string} combination like "command+shift+l"
362
+ * @return {Array}
363
+ */
364
+ function _keysFromString(combination) {
365
+ if (combination === '+') {
366
+ return ['+'];
367
+ }
368
+
369
+ combination = combination.replace(/\+{2}/g, '+plus');
370
+ return combination.split('+');
371
+ }
372
+
373
+ /**
374
+ * Gets info for a specific key combination
375
+ *
376
+ * @param {string} combination key combination ("command+s" or "a" or "*")
377
+ * @param {string=} action
378
+ * @returns {Object}
379
+ */
380
+ function _getKeyInfo(combination, action) {
381
+ var keys;
382
+ var key;
383
+ var i;
384
+ var modifiers = [];
385
+
386
+ // take the keys from this pattern and figure out what the actual
387
+ // pattern is all about
388
+ keys = _keysFromString(combination);
389
+
390
+ for (i = 0; i < keys.length; ++i) {
391
+ key = keys[i];
392
+
393
+ // normalize key names
394
+ if (_SPECIAL_ALIASES[key]) {
395
+ key = _SPECIAL_ALIASES[key];
396
+ }
397
+
398
+ // if this is not a keypress event then we should
399
+ // be smart about using shift keys
400
+ // this will only work for US keyboards however
401
+ if (action && action != 'keypress' && _SHIFT_MAP[key]) {
402
+ key = _SHIFT_MAP[key];
403
+ modifiers.push('shift');
404
+ }
405
+
406
+ // if this key is a modifier then add it to the list of modifiers
407
+ if (_isModifier(key)) {
408
+ modifiers.push(key);
409
+ }
410
+ }
411
+
412
+ // depending on what the key combination is
413
+ // we will try to pick the best event for it
414
+ action = _pickBestAction(key, modifiers, action);
415
+
416
+ return {
417
+ key: key,
418
+ modifiers: modifiers,
419
+ action: action
420
+ };
421
+ }
422
+
423
+ function _belongsTo(element, ancestor) {
424
+ if (element === null || element === document) {
425
+ return false;
426
+ }
427
+
428
+ if (element === ancestor) {
429
+ return true;
430
+ }
431
+
432
+ return _belongsTo(element.parentNode, ancestor);
433
+ }
434
+
435
+ function Mousetrap(targetElement) {
436
+ var self = this;
437
+
438
+ targetElement = targetElement || document;
439
+
440
+ if (!(self instanceof Mousetrap)) {
441
+ return new Mousetrap(targetElement);
442
+ }
443
+
444
+ /**
445
+ * element to attach key events to
446
+ *
447
+ * @type {Element}
448
+ */
449
+ self.target = targetElement;
450
+
451
+ /**
452
+ * a list of all the callbacks setup via Mousetrap.bind()
453
+ *
454
+ * @type {Object}
455
+ */
456
+ self._callbacks = {};
457
+
458
+ /**
459
+ * direct map of string combinations to callbacks used for trigger()
460
+ *
461
+ * @type {Object}
462
+ */
463
+ self._directMap = {};
464
+
465
+ /**
466
+ * keeps track of what level each sequence is at since multiple
467
+ * sequences can start out with the same sequence
468
+ *
469
+ * @type {Object}
470
+ */
471
+ var _sequenceLevels = {};
472
+
473
+ /**
474
+ * variable to store the setTimeout call
475
+ *
476
+ * @type {null|number}
477
+ */
478
+ var _resetTimer;
479
+
480
+ /**
481
+ * temporary state where we will ignore the next keyup
482
+ *
483
+ * @type {boolean|string}
484
+ */
485
+ var _ignoreNextKeyup = false;
486
+
487
+ /**
488
+ * temporary state where we will ignore the next keypress
489
+ *
490
+ * @type {boolean}
491
+ */
492
+ var _ignoreNextKeypress = false;
493
+
494
+ /**
495
+ * are we currently inside of a sequence?
496
+ * type of action ("keyup" or "keydown" or "keypress") or false
497
+ *
498
+ * @type {boolean|string}
499
+ */
500
+ var _nextExpectedAction = false;
501
+
502
+ /**
503
+ * resets all sequence counters except for the ones passed in
504
+ *
505
+ * @param {Object} doNotReset
506
+ * @returns void
507
+ */
508
+ function _resetSequences(doNotReset) {
509
+ doNotReset = doNotReset || {};
510
+
511
+ var activeSequences = false,
512
+ key;
513
+
514
+ for (key in _sequenceLevels) {
515
+ if (doNotReset[key]) {
516
+ activeSequences = true;
517
+ continue;
518
+ }
519
+ _sequenceLevels[key] = 0;
520
+ }
521
+
522
+ if (!activeSequences) {
523
+ _nextExpectedAction = false;
524
+ }
525
+ }
526
+
527
+ /**
528
+ * finds all callbacks that match based on the keycode, modifiers,
529
+ * and action
530
+ *
531
+ * @param {string} character
532
+ * @param {Array} modifiers
533
+ * @param {Event|Object} e
534
+ * @param {string=} sequenceName - name of the sequence we are looking for
535
+ * @param {string=} combination
536
+ * @param {number=} level
537
+ * @returns {Array}
538
+ */
539
+ function _getMatches(character, modifiers, e, sequenceName, combination, level) {
540
+ var i;
541
+ var callback;
542
+ var matches = [];
543
+ var action = e.type;
544
+
545
+ // if there are no events related to this keycode
546
+ if (!self._callbacks[character]) {
547
+ return [];
548
+ }
549
+
550
+ // if a modifier key is coming up on its own we should allow it
551
+ if (action == 'keyup' && _isModifier(character)) {
552
+ modifiers = [character];
553
+ }
554
+
555
+ // loop through all callbacks for the key that was pressed
556
+ // and see if any of them match
557
+ for (i = 0; i < self._callbacks[character].length; ++i) {
558
+ callback = self._callbacks[character][i];
559
+
560
+ // if a sequence name is not specified, but this is a sequence at
561
+ // the wrong level then move onto the next match
562
+ if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) {
563
+ continue;
564
+ }
565
+
566
+ // if the action we are looking for doesn't match the action we got
567
+ // then we should keep going
568
+ if (action != callback.action) {
569
+ continue;
570
+ }
571
+
572
+ // if this is a keypress event and the meta key and control key
573
+ // are not pressed that means that we need to only look at the
574
+ // character, otherwise check the modifiers as well
575
+ //
576
+ // chrome will not fire a keypress if meta or control is down
577
+ // safari will fire a keypress if meta or meta+shift is down
578
+ // firefox will fire a keypress if meta or control is down
579
+ if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) {
580
+
581
+ // when you bind a combination or sequence a second time it
582
+ // should overwrite the first one. if a sequenceName or
583
+ // combination is specified in this call it does just that
584
+ //
585
+ // @todo make deleting its own method?
586
+ var deleteCombo = !sequenceName && callback.combo == combination;
587
+ var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level;
588
+ if (deleteCombo || deleteSequence) {
589
+ self._callbacks[character].splice(i, 1);
590
+ }
591
+
592
+ matches.push(callback);
593
+ }
594
+ }
595
+
596
+ return matches;
597
+ }
598
+
599
+ /**
600
+ * actually calls the callback function
601
+ *
602
+ * if your callback function returns false this will use the jquery
603
+ * convention - prevent default and stop propogation on the event
604
+ *
605
+ * @param {Function} callback
606
+ * @param {Event} e
607
+ * @returns void
608
+ */
609
+ function _fireCallback(callback, e, combo, sequence) {
610
+
611
+ // if this event should not happen stop here
612
+ if (self.stopCallback(e, e.target || e.srcElement, combo, sequence)) {
613
+ return;
614
+ }
615
+
616
+ if (callback(e, combo) === false) {
617
+ _preventDefault(e);
618
+ _stopPropagation(e);
619
+ }
620
+ }
621
+
622
+ /**
623
+ * handles a character key event
624
+ *
625
+ * @param {string} character
626
+ * @param {Array} modifiers
627
+ * @param {Event} e
628
+ * @returns void
629
+ */
630
+ self._handleKey = function(character, modifiers, e) {
631
+ var callbacks = _getMatches(character, modifiers, e);
632
+ var i;
633
+ var doNotReset = {};
634
+ var maxLevel = 0;
635
+ var processedSequenceCallback = false;
636
+
637
+ // Calculate the maxLevel for sequences so we can only execute the longest callback sequence
638
+ for (i = 0; i < callbacks.length; ++i) {
639
+ if (callbacks[i].seq) {
640
+ maxLevel = Math.max(maxLevel, callbacks[i].level);
641
+ }
642
+ }
643
+
644
+ // loop through matching callbacks for this key event
645
+ for (i = 0; i < callbacks.length; ++i) {
646
+
647
+ // fire for all sequence callbacks
648
+ // this is because if for example you have multiple sequences
649
+ // bound such as "g i" and "g t" they both need to fire the
650
+ // callback for matching g cause otherwise you can only ever
651
+ // match the first one
652
+ if (callbacks[i].seq) {
653
+
654
+ // only fire callbacks for the maxLevel to prevent
655
+ // subsequences from also firing
656
+ //
657
+ // for example 'a option b' should not cause 'option b' to fire
658
+ // even though 'option b' is part of the other sequence
659
+ //
660
+ // any sequences that do not match here will be discarded
661
+ // below by the _resetSequences call
662
+ if (callbacks[i].level != maxLevel) {
663
+ continue;
664
+ }
665
+
666
+ processedSequenceCallback = true;
667
+
668
+ // keep a list of which sequences were matches for later
669
+ doNotReset[callbacks[i].seq] = 1;
670
+ _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq);
671
+ continue;
672
+ }
673
+
674
+ // if there were no sequence matches but we are still here
675
+ // that means this is a regular match so we should fire that
676
+ if (!processedSequenceCallback) {
677
+ _fireCallback(callbacks[i].callback, e, callbacks[i].combo);
678
+ }
679
+ }
680
+
681
+ // if the key you pressed matches the type of sequence without
682
+ // being a modifier (ie "keyup" or "keypress") then we should
683
+ // reset all sequences that were not matched by this event
684
+ //
685
+ // this is so, for example, if you have the sequence "h a t" and you
686
+ // type "h e a r t" it does not match. in this case the "e" will
687
+ // cause the sequence to reset
688
+ //
689
+ // modifier keys are ignored because you can have a sequence
690
+ // that contains modifiers such as "enter ctrl+space" and in most
691
+ // cases the modifier key will be pressed before the next key
692
+ //
693
+ // also if you have a sequence such as "ctrl+b a" then pressing the
694
+ // "b" key will trigger a "keypress" and a "keydown"
695
+ //
696
+ // the "keydown" is expected when there is a modifier, but the
697
+ // "keypress" ends up matching the _nextExpectedAction since it occurs
698
+ // after and that causes the sequence to reset
699
+ //
700
+ // we ignore keypresses in a sequence that directly follow a keydown
701
+ // for the same character
702
+ var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress;
703
+ if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) {
704
+ _resetSequences(doNotReset);
705
+ }
706
+
707
+ _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown';
708
+ };
709
+
710
+ /**
711
+ * handles a keydown event
712
+ *
713
+ * @param {Event} e
714
+ * @returns void
715
+ */
716
+ function _handleKeyEvent(e) {
717
+
718
+ // normalize e.which for key events
719
+ // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion
720
+ if (typeof e.which !== 'number') {
721
+ e.which = e.keyCode;
722
+ }
723
+
724
+ var character = _characterFromEvent(e);
725
+
726
+ // no character found then stop
727
+ if (!character) {
728
+ return;
729
+ }
730
+
731
+ // need to use === for the character check because the character can be 0
732
+ if (e.type == 'keyup' && _ignoreNextKeyup === character) {
733
+ _ignoreNextKeyup = false;
734
+ return;
735
+ }
736
+
737
+ self.handleKey(character, _eventModifiers(e), e);
738
+ }
739
+
740
+ /**
741
+ * called to set a 1 second timeout on the specified sequence
742
+ *
743
+ * this is so after each key press in the sequence you have 1 second
744
+ * to press the next key before you have to start over
745
+ *
746
+ * @returns void
747
+ */
748
+ function _resetSequenceTimer() {
749
+ clearTimeout(_resetTimer);
750
+ _resetTimer = setTimeout(_resetSequences, 1000);
751
+ }
752
+
753
+ /**
754
+ * binds a key sequence to an event
755
+ *
756
+ * @param {string} combo - combo specified in bind call
757
+ * @param {Array} keys
758
+ * @param {Function} callback
759
+ * @param {string=} action
760
+ * @returns void
761
+ */
762
+ function _bindSequence(combo, keys, callback, action) {
763
+
764
+ // start off by adding a sequence level record for this combination
765
+ // and setting the level to 0
766
+ _sequenceLevels[combo] = 0;
767
+
768
+ /**
769
+ * callback to increase the sequence level for this sequence and reset
770
+ * all other sequences that were active
771
+ *
772
+ * @param {string} nextAction
773
+ * @returns {Function}
774
+ */
775
+ function _increaseSequence(nextAction) {
776
+ return function() {
777
+ _nextExpectedAction = nextAction;
778
+ ++_sequenceLevels[combo];
779
+ _resetSequenceTimer();
780
+ };
781
+ }
782
+
783
+ /**
784
+ * wraps the specified callback inside of another function in order
785
+ * to reset all sequence counters as soon as this sequence is done
786
+ *
787
+ * @param {Event} e
788
+ * @returns void
789
+ */
790
+ function _callbackAndReset(e) {
791
+ _fireCallback(callback, e, combo);
792
+
793
+ // we should ignore the next key up if the action is key down
794
+ // or keypress. this is so if you finish a sequence and
795
+ // release the key the final key will not trigger a keyup
796
+ if (action !== 'keyup') {
797
+ _ignoreNextKeyup = _characterFromEvent(e);
798
+ }
799
+
800
+ // weird race condition if a sequence ends with the key
801
+ // another sequence begins with
802
+ setTimeout(_resetSequences, 10);
803
+ }
804
+
805
+ // loop through keys one at a time and bind the appropriate callback
806
+ // function. for any key leading up to the final one it should
807
+ // increase the sequence. after the final, it should reset all sequences
808
+ //
809
+ // if an action is specified in the original bind call then that will
810
+ // be used throughout. otherwise we will pass the action that the
811
+ // next key in the sequence should match. this allows a sequence
812
+ // to mix and match keypress and keydown events depending on which
813
+ // ones are better suited to the key provided
814
+ for (var i = 0; i < keys.length; ++i) {
815
+ var isFinal = i + 1 === keys.length;
816
+ var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action);
817
+ _bindSingle(keys[i], wrappedCallback, action, combo, i);
818
+ }
819
+ }
820
+
821
+ /**
822
+ * binds a single keyboard combination
823
+ *
824
+ * @param {string} combination
825
+ * @param {Function} callback
826
+ * @param {string=} action
827
+ * @param {string=} sequenceName - name of sequence if part of sequence
828
+ * @param {number=} level - what part of the sequence the command is
829
+ * @returns void
830
+ */
831
+ function _bindSingle(combination, callback, action, sequenceName, level) {
832
+
833
+ // store a direct mapped reference for use with Mousetrap.trigger
834
+ self._directMap[combination + ':' + action] = callback;
835
+
836
+ // make sure multiple spaces in a row become a single space
837
+ combination = combination.replace(/\s+/g, ' ');
838
+
839
+ var sequence = combination.split(' ');
840
+ var info;
841
+
842
+ // if this pattern is a sequence of keys then run through this method
843
+ // to reprocess each pattern one key at a time
844
+ if (sequence.length > 1) {
845
+ _bindSequence(combination, sequence, callback, action);
846
+ return;
847
+ }
848
+
849
+ info = _getKeyInfo(combination, action);
850
+
851
+ // make sure to initialize array if this is the first time
852
+ // a callback is added for this key
853
+ self._callbacks[info.key] = self._callbacks[info.key] || [];
854
+
855
+ // remove an existing match if there is one
856
+ _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level);
857
+
858
+ // add this call back to the array
859
+ // if it is a sequence put it at the beginning
860
+ // if not put it at the end
861
+ //
862
+ // this is important because the way these are processed expects
863
+ // the sequence ones to come first
864
+ self._callbacks[info.key][sequenceName ? 'unshift' : 'push']({
865
+ callback: callback,
866
+ modifiers: info.modifiers,
867
+ action: info.action,
868
+ seq: sequenceName,
869
+ level: level,
870
+ combo: combination
871
+ });
872
+ }
873
+
874
+ /**
875
+ * binds multiple combinations to the same callback
876
+ *
877
+ * @param {Array} combinations
878
+ * @param {Function} callback
879
+ * @param {string|undefined} action
880
+ * @returns void
881
+ */
882
+ self._bindMultiple = function(combinations, callback, action) {
883
+ for (var i = 0; i < combinations.length; ++i) {
884
+ _bindSingle(combinations[i], callback, action);
885
+ }
886
+ };
887
+
888
+ // start!
889
+ _addEvent(targetElement, 'keypress', _handleKeyEvent);
890
+ _addEvent(targetElement, 'keydown', _handleKeyEvent);
891
+ _addEvent(targetElement, 'keyup', _handleKeyEvent);
892
+ }
893
+
894
+ /**
895
+ * binds an event to mousetrap
896
+ *
897
+ * can be a single key, a combination of keys separated with +,
898
+ * an array of keys, or a sequence of keys separated by spaces
899
+ *
900
+ * be sure to list the modifier keys first to make sure that the
901
+ * correct key ends up getting bound (the last key in the pattern)
902
+ *
903
+ * @param {string|Array} keys
904
+ * @param {Function} callback
905
+ * @param {string=} action - 'keypress', 'keydown', or 'keyup'
906
+ * @returns void
907
+ */
908
+ Mousetrap.prototype.bind = function(keys, callback, action) {
909
+ var self = this;
910
+ keys = keys instanceof Array ? keys : [keys];
911
+ self._bindMultiple.call(self, keys, callback, action);
912
+ return self;
913
+ };
914
+
915
+ /**
916
+ * unbinds an event to mousetrap
917
+ *
918
+ * the unbinding sets the callback function of the specified key combo
919
+ * to an empty function and deletes the corresponding key in the
920
+ * _directMap dict.
921
+ *
922
+ * TODO: actually remove this from the _callbacks dictionary instead
923
+ * of binding an empty function
924
+ *
925
+ * the keycombo+action has to be exactly the same as
926
+ * it was defined in the bind method
927
+ *
928
+ * @param {string|Array} keys
929
+ * @param {string} action
930
+ * @returns void
931
+ */
932
+ Mousetrap.prototype.unbind = function(keys, action) {
933
+ var self = this;
934
+ return self.bind.call(self, keys, function() {}, action);
935
+ };
936
+
937
+ /**
938
+ * triggers an event that has already been bound
939
+ *
940
+ * @param {string} keys
941
+ * @param {string=} action
942
+ * @returns void
943
+ */
944
+ Mousetrap.prototype.trigger = function(keys, action) {
945
+ var self = this;
946
+ if (self._directMap[keys + ':' + action]) {
947
+ self._directMap[keys + ':' + action]({}, keys);
948
+ }
949
+ return self;
950
+ };
951
+
952
+ /**
953
+ * resets the library back to its initial state. this is useful
954
+ * if you want to clear out the current keyboard shortcuts and bind
955
+ * new ones - for example if you switch to another page
956
+ *
957
+ * @returns void
958
+ */
959
+ Mousetrap.prototype.reset = function() {
960
+ var self = this;
961
+ self._callbacks = {};
962
+ self._directMap = {};
963
+ return self;
964
+ };
965
+
966
+ /**
967
+ * should we stop this event before firing off callbacks
968
+ *
969
+ * @param {Event} e
970
+ * @param {Element} element
971
+ * @return {boolean}
972
+ */
973
+ Mousetrap.prototype.stopCallback = function(e, element) {
974
+ var self = this;
975
+
976
+ // if the element has the class "mousetrap" then no need to stop
977
+ if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {
978
+ return false;
979
+ }
980
+
981
+ if (_belongsTo(element, self.target)) {
982
+ return false;
983
+ }
984
+
985
+ // Events originating from a shadow DOM are re-targetted and `e.target` is the shadow host,
986
+ // not the initial event target in the shadow tree. Note that not all events cross the
987
+ // shadow boundary.
988
+ // For shadow trees with `mode: 'open'`, the initial event target is the first element in
989
+ // the event’s composed path. For shadow trees with `mode: 'closed'`, the initial event
990
+ // target cannot be obtained.
991
+ if ('composedPath' in e && typeof e.composedPath === 'function') {
992
+ // For open shadow trees, update `element` so that the following check works.
993
+ var initialEventTarget = e.composedPath()[0];
994
+ if (initialEventTarget !== e.target) {
995
+ element = initialEventTarget;
996
+ }
997
+ }
998
+
999
+ // stop for input, select, and textarea
1000
+ return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable;
1001
+ };
1002
+
1003
+ /**
1004
+ * exposes _handleKey publicly so it can be overwritten by extensions
1005
+ */
1006
+ Mousetrap.prototype.handleKey = function() {
1007
+ var self = this;
1008
+ return self._handleKey.apply(self, arguments);
1009
+ };
1010
+
1011
+ /**
1012
+ * allow custom key mappings
1013
+ */
1014
+ Mousetrap.addKeycodes = function(object) {
1015
+ for (var key in object) {
1016
+ if (object.hasOwnProperty(key)) {
1017
+ _MAP[key] = object[key];
1018
+ }
1019
+ }
1020
+ _REVERSE_MAP = null;
1021
+ };
1022
+
1023
+ /**
1024
+ * Init the global mousetrap functions
1025
+ *
1026
+ * This method is needed to allow the global mousetrap functions to work
1027
+ * now that mousetrap is a constructor function.
1028
+ */
1029
+ Mousetrap.init = function() {
1030
+ var documentMousetrap = Mousetrap(document);
1031
+ for (var method in documentMousetrap) {
1032
+ if (method.charAt(0) !== '_') {
1033
+ Mousetrap[method] = (function(method) {
1034
+ return function() {
1035
+ return documentMousetrap[method].apply(documentMousetrap, arguments);
1036
+ };
1037
+ } (method));
1038
+ }
1039
+ }
1040
+ };
1041
+
1042
+ Mousetrap.init();
1043
+
1044
+ // expose mousetrap to the global object
1045
+ window.Mousetrap = Mousetrap;
1046
+
1047
+ // expose as a common js module
1048
+ if (typeof module !== 'undefined' && module.exports) {
1049
+ module.exports = Mousetrap;
1050
+ }
1051
+
1052
+ // expose mousetrap as an AMD module
1053
+ if (typeof define === 'function' && define.amd) {
1054
+ define(function() {
1055
+ return Mousetrap;
1056
+ });
1057
+ }
1058
+ }) (typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null);