@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,772 @@
1
+ /**
2
+ * The following strategy of importing modules allows the tests to be run in a browser environment.
3
+ * Test libraries like `mocha`, `sinon`, etc. are expected to be loaded before this file.
4
+ */
5
+ var sinon = sinon || require('sinon');
6
+ var chai = chai || require('chai');
7
+ var expect = chai.expect;
8
+
9
+ if (typeof window === 'undefined') {
10
+ require('mocha');
11
+ require('jsdom-global')();
12
+ }
13
+
14
+ // Load libraries that require access to the DOM after `jsdom-global`
15
+ var Mousetrap = Mousetrap || require('./../mousetrap');
16
+ var KeyEvent = KeyEvent || require('./libs/key-event');
17
+
18
+
19
+
20
+ // Reset Mousetrap after each test
21
+ afterEach(function () {
22
+ Mousetrap.reset();
23
+ });
24
+
25
+ describe('Mousetrap.bind', function () {
26
+ describe('basic', function () {
27
+ it('z key fires when pressing z', function () {
28
+ var spy = sinon.spy();
29
+
30
+ Mousetrap.bind('z', spy);
31
+
32
+ KeyEvent.simulate('Z'.charCodeAt(0), 90);
33
+
34
+ // really slow for some reason
35
+ // expect(spy).to.have.been.calledOnce;
36
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
37
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
38
+ expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
39
+ });
40
+
41
+ it('z key fires from keydown', function () {
42
+ var spy = sinon.spy();
43
+
44
+ Mousetrap.bind('z', spy, 'keydown');
45
+
46
+ KeyEvent.simulate('Z'.charCodeAt(0), 90);
47
+
48
+ // really slow for some reason
49
+ // expect(spy).to.have.been.calledOnce;
50
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
51
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
52
+ expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
53
+ });
54
+
55
+ it('z key does not fire when pressing b', function () {
56
+ var spy = sinon.spy();
57
+
58
+ Mousetrap.bind('z', spy);
59
+
60
+ KeyEvent.simulate('B'.charCodeAt(0), 66);
61
+
62
+ expect(spy.callCount).to.equal(0);
63
+ });
64
+
65
+ it('z key does not fire when holding a modifier key', function () {
66
+ var spy = sinon.spy();
67
+ var modifiers = ['ctrl', 'alt', 'meta', 'shift'];
68
+ var charCode;
69
+ var modifier;
70
+
71
+ Mousetrap.bind('z', spy);
72
+
73
+ for (var i = 0; i < 4; i++) {
74
+ modifier = modifiers[i];
75
+ charCode = 'Z'.charCodeAt(0);
76
+
77
+ // character code is different when alt is pressed
78
+ if (modifier == 'alt') {
79
+ charCode = 'Ω'.charCodeAt(0);
80
+ }
81
+
82
+ spy.resetHistory();
83
+
84
+ KeyEvent.simulate(charCode, 90, [modifier]);
85
+
86
+ expect(spy.callCount).to.equal(0);
87
+ }
88
+ });
89
+
90
+ it('z key does not fire when inside an input element in an open shadow dom', function() {
91
+ var spy = sinon.spy();
92
+
93
+ var shadowHost = document.createElement('div');
94
+ var shadowRoot = shadowHost.attachShadow({ mode: 'open' });
95
+ document.body.appendChild(shadowHost);
96
+
97
+ var inputElement = document.createElement('input');
98
+ shadowRoot.appendChild(inputElement);
99
+ expect(shadowHost.shadowRoot).to.equal(shadowRoot, 'shadow root accessible');
100
+
101
+ Mousetrap.bind('z', spy);
102
+ KeyEvent.simulate('Z'.charCodeAt(0), 90, [], inputElement, 1, { shadowHost: shadowHost });
103
+ document.body.removeChild(shadowHost);
104
+ expect(spy.callCount).to.equal(0, 'callback should not have fired');
105
+ });
106
+
107
+ it('z key does fire when inside an input element in a closed shadow dom', function() {
108
+ var spy = sinon.spy();
109
+
110
+ var shadowHost = document.createElement('div');
111
+ var shadowRoot = shadowHost.attachShadow({ mode: 'closed' });
112
+ document.body.appendChild(shadowHost);
113
+
114
+ var inputElement = document.createElement('input');
115
+ shadowRoot.appendChild(inputElement);
116
+ expect(shadowHost.shadowRoot).to.equal(null, 'shadow root unaccessible');
117
+
118
+ Mousetrap.bind('z', spy);
119
+ KeyEvent.simulate('Z'.charCodeAt(0), 90, [], inputElement, 1, { shadowHost: shadowHost });
120
+ document.body.removeChild(shadowHost);
121
+ expect(spy.callCount).to.equal(1, 'callback should have fired once');
122
+ });
123
+
124
+ it('keyup events should fire', function() {
125
+ var spy = sinon.spy();
126
+
127
+ Mousetrap.bind('z', spy, 'keyup');
128
+
129
+ KeyEvent.simulate('Z'.charCodeAt(0), 90);
130
+
131
+ expect(spy.callCount).to.equal(1, 'keyup event for "z" should fire');
132
+
133
+ // for key held down we should only get one key up
134
+ KeyEvent.simulate('Z'.charCodeAt(0), 90, [], document, 10);
135
+ expect(spy.callCount).to.equal(2, 'keyup event for "z" should fire once for held down key');
136
+ });
137
+
138
+ it('keyup event for 0 should fire', function () {
139
+ var spy = sinon.spy();
140
+
141
+ Mousetrap.bind('0', spy, 'keyup');
142
+
143
+ KeyEvent.simulate(0, 48);
144
+
145
+ expect(spy.callCount).to.equal(1, 'keyup event for "0" should fire');
146
+ });
147
+
148
+ it('rebinding a key overwrites the callback for that key', function () {
149
+ var spy1 = sinon.spy();
150
+ var spy2 = sinon.spy();
151
+ Mousetrap.bind('x', spy1);
152
+ Mousetrap.bind('x', spy2);
153
+
154
+ KeyEvent.simulate('X'.charCodeAt(0), 88);
155
+
156
+ expect(spy1.callCount).to.equal(0, 'original callback should not fire');
157
+ expect(spy2.callCount).to.equal(1, 'new callback should fire');
158
+ });
159
+
160
+ it('binding an array of keys', function () {
161
+ var spy = sinon.spy();
162
+ Mousetrap.bind(['a', 'b', 'c'], spy);
163
+
164
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
165
+ expect(spy.callCount).to.equal(1, 'new callback was called');
166
+ expect(spy.args[0][1]).to.equal('a', 'callback should match "a"');
167
+
168
+ KeyEvent.simulate('B'.charCodeAt(0), 66);
169
+ expect(spy.callCount).to.equal(2, 'new callback was called twice');
170
+ expect(spy.args[1][1]).to.equal('b', 'callback should match "b"');
171
+
172
+ KeyEvent.simulate('C'.charCodeAt(0), 67);
173
+ expect(spy.callCount).to.equal(3, 'new callback was called three times');
174
+ expect(spy.args[2][1]).to.equal('c', 'callback should match "c"');
175
+ });
176
+
177
+ it('return false should prevent default and stop propagation', function () {
178
+ var spy = sinon.spy(function () {
179
+ return false;
180
+ });
181
+
182
+ Mousetrap.bind('command+s', spy);
183
+
184
+ KeyEvent.simulate('S'.charCodeAt(0), 83, ['meta']);
185
+
186
+ expect(spy.callCount).to.equal(1, 'callback should fire');
187
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
188
+
189
+ expect(spy.args[0][0].defaultPrevented).to.be.true;
190
+
191
+ // cancelBubble is not correctly set to true in webkit/blink
192
+ //
193
+ // @see https://code.google.com/p/chromium/issues/detail?id=162270
194
+ // expect(spy.args[0][0].cancelBubble).to.be.true;
195
+
196
+ // try without return false
197
+ spy = sinon.spy();
198
+ Mousetrap.bind('command+s', spy);
199
+ KeyEvent.simulate('S'.charCodeAt(0), 83, ['meta']);
200
+
201
+ expect(spy.callCount).to.equal(1, 'callback should fire');
202
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
203
+ expect(spy.args[0][0].cancelBubble).to.be.false;
204
+ expect(spy.args[0][0].defaultPrevented).to.be.false;
205
+ });
206
+
207
+ it('capslock key is ignored', function () {
208
+ var spy = sinon.spy();
209
+ Mousetrap.bind('a', spy);
210
+
211
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
212
+ expect(spy.callCount).to.equal(1, 'callback should fire for lowercase a');
213
+
214
+ spy.resetHistory();
215
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
216
+ expect(spy.callCount).to.equal(1, 'callback should fire for capslock A');
217
+
218
+ spy.resetHistory();
219
+ KeyEvent.simulate('A'.charCodeAt(0), 65, ['shift']);
220
+ expect(spy.callCount).to.equal(0, 'callback should not fire fort shift+a');
221
+ });
222
+ });
223
+
224
+ describe('special characters', function () {
225
+ it('binding special characters', function () {
226
+ var spy = sinon.spy();
227
+ Mousetrap.bind('*', spy);
228
+
229
+ KeyEvent.simulate('*'.charCodeAt(0), 56, ['shift']);
230
+
231
+ expect(spy.callCount).to.equal(1, 'callback should fire');
232
+ expect(spy.args[0][1]).to.equal('*', 'callback should match *');
233
+ });
234
+
235
+ it('binding special characters keyup', function () {
236
+ var spy = sinon.spy();
237
+ Mousetrap.bind('*', spy, 'keyup');
238
+
239
+ KeyEvent.simulate('*'.charCodeAt(0), 56, ['shift']);
240
+
241
+ expect(spy.callCount).to.equal(1, 'callback should fire');
242
+ expect(spy.args[0][1]).to.equal('*', 'callback should match "*"');
243
+ });
244
+
245
+ it('binding keys with no associated charCode', function () {
246
+ var spy = sinon.spy();
247
+ Mousetrap.bind('left', spy);
248
+
249
+ KeyEvent.simulate(0, 37);
250
+
251
+ expect(spy.callCount).to.equal(1, 'callback should fire');
252
+ expect(spy.args[0][1]).to.equal('left', 'callback should match "left"');
253
+ });
254
+
255
+ it('binding plus key alone should work', function () {
256
+ var spy = sinon.spy();
257
+ Mousetrap.bind('+', spy);
258
+
259
+ // fires for regular + character
260
+ KeyEvent.simulate('+'.charCodeAt(0), 43);
261
+
262
+ // and for shift+=
263
+ KeyEvent.simulate(43, 187, ['shift']);
264
+
265
+ expect(spy.callCount).to.equal(2, 'callback should fire');
266
+ expect(spy.args[0][1]).to.equal('+', 'callback should match "+"');
267
+ });
268
+
269
+ it('binding plus key as "plus" should work', function () {
270
+ var spy = sinon.spy();
271
+ Mousetrap.bind('plus', spy);
272
+
273
+ // fires for regular + character
274
+ KeyEvent.simulate('+'.charCodeAt(0), 43);
275
+
276
+ // and for shift+=
277
+ KeyEvent.simulate(43, 187, ['shift']);
278
+
279
+ expect(spy.callCount).to.equal(2, 'callback should fire');
280
+ expect(spy.args[0][1]).to.equal('plus', 'callback should match "plus"');
281
+ });
282
+
283
+ it('binding to alt++ should work', function () {
284
+ var spy = sinon.spy();
285
+ Mousetrap.bind('alt++', spy);
286
+
287
+ KeyEvent.simulate('+'.charCodeAt(0), 43, ['alt']);
288
+ expect(spy.callCount).to.equal(1, 'callback should fire');
289
+ expect(spy.args[0][1]).to.equal('alt++', 'callback should match "alt++"');
290
+ });
291
+
292
+ it('binding to alt+shift++ should work as well', function () {
293
+ var spy = sinon.spy();
294
+ Mousetrap.bind('alt+shift++', spy);
295
+
296
+ KeyEvent.simulate('+'.charCodeAt(0), 43, ['shift', 'alt']);
297
+ expect(spy.callCount).to.equal(1, 'callback should fire');
298
+ expect(spy.args[0][1]).to.equal('alt+shift++', 'callback should match "alt++"');
299
+
300
+ });
301
+ });
302
+
303
+ describe('combos with modifiers', function () {
304
+ it('binding key combinations', function () {
305
+ var spy = sinon.spy();
306
+ Mousetrap.bind('command+o', spy);
307
+
308
+ KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta']);
309
+
310
+ expect(spy.callCount).to.equal(1, 'command+o callback should fire');
311
+ expect(spy.args[0][1]).to.equal('command+o', 'keyboard string returned is correct');
312
+ });
313
+
314
+ it('binding key combos with multiple modifiers', function () {
315
+ var spy = sinon.spy();
316
+ Mousetrap.bind('command+shift+o', spy);
317
+ KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta']);
318
+ expect(spy.callCount).to.equal(0, 'command+o callback should not fire');
319
+
320
+ KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta', 'shift']);
321
+ expect(spy.callCount).to.equal(1, 'command+o callback should fire');
322
+ });
323
+
324
+ it('should fire callback when ctrl+numpad 0 is pressed', function () {
325
+ var spy = sinon.spy();
326
+
327
+ Mousetrap.bind('ctrl+0', spy);
328
+
329
+ // numpad 0 keycode
330
+ KeyEvent.simulate(96, 96, ['ctrl']);
331
+
332
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
333
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
334
+ expect(spy.args[0][1]).to.equal('ctrl+0', 'second argument should be key combo');
335
+ });
336
+ });
337
+
338
+ describe('sequences', function () {
339
+ it('binding sequences', function () {
340
+ var spy = sinon.spy();
341
+ Mousetrap.bind('g i', spy);
342
+
343
+ KeyEvent.simulate('G'.charCodeAt(0), 71);
344
+ expect(spy.callCount).to.equal(0, 'callback should not fire');
345
+
346
+ KeyEvent.simulate('I'.charCodeAt(0), 73);
347
+ expect(spy.callCount).to.equal(1, 'callback should fire');
348
+ });
349
+
350
+ it('binding sequences with mixed types', function () {
351
+ var spy = sinon.spy();
352
+ Mousetrap.bind('g o enter', spy);
353
+
354
+ KeyEvent.simulate('G'.charCodeAt(0), 71);
355
+ expect(spy.callCount).to.equal(0, 'callback should not fire');
356
+
357
+ KeyEvent.simulate('O'.charCodeAt(0), 79);
358
+ expect(spy.callCount).to.equal(0, 'callback should not fire');
359
+
360
+ KeyEvent.simulate(0, 13);
361
+ expect(spy.callCount).to.equal(1, 'callback should fire');
362
+ });
363
+
364
+ it('binding sequences starting with modifier keys', function () {
365
+ var spy = sinon.spy();
366
+ Mousetrap.bind('option enter', spy);
367
+ KeyEvent.simulate(0, 18, ['alt']);
368
+ KeyEvent.simulate(0, 13);
369
+ expect(spy.callCount).to.equal(1, 'callback should fire');
370
+
371
+ spy = sinon.spy();
372
+ Mousetrap.bind('command enter', spy);
373
+ KeyEvent.simulate(0, 91, ['meta']);
374
+ KeyEvent.simulate(0, 13);
375
+ expect(spy.callCount).to.equal(1, 'callback should fire');
376
+
377
+ spy = sinon.spy();
378
+ Mousetrap.bind('escape enter', spy);
379
+ KeyEvent.simulate(0, 27);
380
+ KeyEvent.simulate(0, 13);
381
+ expect(spy.callCount).to.equal(1, 'callback should fire');
382
+ });
383
+
384
+ it('key within sequence should not fire', function () {
385
+ var spy1 = sinon.spy();
386
+ var spy2 = sinon.spy();
387
+ Mousetrap.bind('a', spy1);
388
+ Mousetrap.bind('c a t', spy2);
389
+
390
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
391
+ expect(spy1.callCount).to.equal(1, 'callback 1 should fire');
392
+ spy1.resetHistory();
393
+
394
+ KeyEvent.simulate('C'.charCodeAt(0), 67);
395
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
396
+ KeyEvent.simulate('T'.charCodeAt(0), 84);
397
+ expect(spy1.callCount).to.equal(0, 'callback for "a" key should not fire');
398
+ expect(spy2.callCount).to.equal(1, 'callback for "c a t" sequence should fire');
399
+ });
400
+
401
+ it('keyup at end of sequence should not fire', function () {
402
+ var spy1 = sinon.spy();
403
+ var spy2 = sinon.spy();
404
+
405
+ Mousetrap.bind('t', spy1, 'keyup');
406
+ Mousetrap.bind('b a t', spy2);
407
+
408
+ KeyEvent.simulate('B'.charCodeAt(0), 66);
409
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
410
+ KeyEvent.simulate('T'.charCodeAt(0), 84);
411
+
412
+ expect(spy1.callCount).to.equal(0, 'callback for "t" keyup should not fire');
413
+ expect(spy2.callCount).to.equal(1, 'callback for "b a t" sequence should fire');
414
+ });
415
+
416
+ it('keyup sequences should work', function () {
417
+ var spy = sinon.spy();
418
+ Mousetrap.bind('b a t', spy, 'keyup');
419
+
420
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
421
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
422
+
423
+ // hold the last key down for a while
424
+ KeyEvent.simulate('t'.charCodeAt(0), 84, [], document, 10);
425
+
426
+ expect(spy.callCount).to.equal(1, 'callback for "b a t" sequence should fire on keyup');
427
+ });
428
+
429
+ it('extra spaces in sequences should be ignored', function () {
430
+ var spy = sinon.spy();
431
+ Mousetrap.bind('b a t', spy);
432
+
433
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
434
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
435
+ KeyEvent.simulate('t'.charCodeAt(0), 84);
436
+
437
+ expect(spy.callCount).to.equal(1, 'callback for "b a t" sequence should fire');
438
+ });
439
+
440
+ it('modifiers and sequences play nicely', function () {
441
+ var spy1 = sinon.spy();
442
+ var spy2 = sinon.spy();
443
+
444
+ Mousetrap.bind('ctrl a', spy1);
445
+ Mousetrap.bind('ctrl+b', spy2);
446
+
447
+ KeyEvent.simulate(0, 17, ['ctrl']);
448
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
449
+ expect(spy1.callCount).to.equal(1, '"ctrl a" should fire');
450
+
451
+ KeyEvent.simulate('B'.charCodeAt(0), 66, ['ctrl']);
452
+ expect(spy2.callCount).to.equal(1, '"ctrl+b" should fire');
453
+ });
454
+
455
+ it('sequences that start the same work', function () {
456
+ var spy1 = sinon.spy();
457
+ var spy2 = sinon.spy();
458
+
459
+ Mousetrap.bind('g g l', spy2);
460
+ Mousetrap.bind('g g o', spy1);
461
+
462
+ KeyEvent.simulate('g'.charCodeAt(0), 71);
463
+ KeyEvent.simulate('g'.charCodeAt(0), 71);
464
+ KeyEvent.simulate('o'.charCodeAt(0), 79);
465
+ expect(spy1.callCount).to.equal(1, '"g g o" should fire');
466
+ expect(spy2.callCount).to.equal(0, '"g g l" should not fire');
467
+
468
+ spy1.resetHistory();
469
+ spy2.resetHistory();
470
+ KeyEvent.simulate('g'.charCodeAt(0), 71);
471
+ KeyEvent.simulate('g'.charCodeAt(0), 71);
472
+ KeyEvent.simulate('l'.charCodeAt(0), 76);
473
+ expect(spy1.callCount).to.equal(0, '"g g o" should not fire');
474
+ expect(spy2.callCount).to.equal(1, '"g g l" should fire');
475
+ });
476
+
477
+ it('sequences should not fire subsequences', function () {
478
+ var spy1 = sinon.spy();
479
+ var spy2 = sinon.spy();
480
+
481
+ Mousetrap.bind('a b c', spy1);
482
+ Mousetrap.bind('b c', spy2);
483
+
484
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
485
+ KeyEvent.simulate('B'.charCodeAt(0), 66);
486
+ KeyEvent.simulate('C'.charCodeAt(0), 67);
487
+
488
+ expect(spy1.callCount).to.equal(1, '"a b c" should fire');
489
+ expect(spy2.callCount).to.equal(0, '"b c" should not fire');
490
+
491
+ spy1.resetHistory();
492
+ spy2.resetHistory();
493
+ Mousetrap.bind('option b', spy1);
494
+ Mousetrap.bind('a option b', spy2);
495
+
496
+ KeyEvent.simulate('A'.charCodeAt(0), 65);
497
+ KeyEvent.simulate(0, 18, ['alt']);
498
+ KeyEvent.simulate('B'.charCodeAt(0), 66);
499
+
500
+ expect(spy1.callCount).to.equal(0, '"option b" should not fire');
501
+ expect(spy2.callCount).to.equal(1, '"a option b" should fire');
502
+ });
503
+
504
+ it('rebinding same sequence should override previous', function () {
505
+ var spy1 = sinon.spy();
506
+ var spy2 = sinon.spy();
507
+ Mousetrap.bind('a b c', spy1);
508
+ Mousetrap.bind('a b c', spy2);
509
+
510
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
511
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
512
+ KeyEvent.simulate('c'.charCodeAt(0), 67);
513
+
514
+ expect(spy1.callCount).to.equal(0, 'first callback should not fire');
515
+ expect(spy2.callCount).to.equal(1, 'second callback should fire');
516
+ });
517
+
518
+ it('broken sequences', function () {
519
+ var spy = sinon.spy();
520
+ Mousetrap.bind('h a t', spy);
521
+
522
+ KeyEvent.simulate('h'.charCodeAt(0), 72);
523
+ KeyEvent.simulate('e'.charCodeAt(0), 69);
524
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
525
+ KeyEvent.simulate('r'.charCodeAt(0), 82);
526
+ KeyEvent.simulate('t'.charCodeAt(0), 84);
527
+
528
+ expect(spy.callCount).to.equal(0, 'sequence for "h a t" should not fire for "h e a r t"');
529
+ });
530
+
531
+ it('sequences containing combos should work', function () {
532
+ var spy = sinon.spy();
533
+ Mousetrap.bind('a ctrl+b', spy);
534
+
535
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
536
+ KeyEvent.simulate('B'.charCodeAt(0), 66, ['ctrl']);
537
+
538
+ expect(spy.callCount).to.equal(1, '"a ctrl+b" should fire');
539
+
540
+ Mousetrap.unbind('a ctrl+b');
541
+
542
+ spy = sinon.spy();
543
+ Mousetrap.bind('ctrl+b a', spy);
544
+
545
+ KeyEvent.simulate('b'.charCodeAt(0), 66, ['ctrl']);
546
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
547
+
548
+ expect(spy.callCount).to.equal(1, '"ctrl+b a" should fire');
549
+ });
550
+
551
+ it('sequences starting with spacebar should work', function () {
552
+ var spy = sinon.spy();
553
+ Mousetrap.bind('a space b c', spy);
554
+
555
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
556
+ KeyEvent.simulate(32, 32);
557
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
558
+ KeyEvent.simulate('c'.charCodeAt(0), 67);
559
+
560
+ expect(spy.callCount).to.equal(1, '"a space b c" should fire');
561
+ });
562
+
563
+ it('konami code', function () {
564
+ var spy = sinon.spy();
565
+ Mousetrap.bind('up up down down left right left right b a enter', spy);
566
+
567
+ KeyEvent.simulate(0, 38);
568
+ KeyEvent.simulate(0, 38);
569
+ KeyEvent.simulate(0, 40);
570
+ KeyEvent.simulate(0, 40);
571
+ KeyEvent.simulate(0, 37);
572
+ KeyEvent.simulate(0, 39);
573
+ KeyEvent.simulate(0, 37);
574
+ KeyEvent.simulate(0, 39);
575
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
576
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
577
+ KeyEvent.simulate(0, 13);
578
+
579
+ expect(spy.callCount).to.equal(1, 'konami code should fire');
580
+ });
581
+
582
+ it('sequence timer resets', function () {
583
+ var spy = sinon.spy();
584
+ var clock = sinon.useFakeTimers();
585
+
586
+ Mousetrap.bind('h a t', spy);
587
+
588
+ KeyEvent.simulate('h'.charCodeAt(0), 72);
589
+ clock.tick(600);
590
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
591
+ clock.tick(900);
592
+ KeyEvent.simulate('t'.charCodeAt(0), 84);
593
+
594
+ expect(spy.callCount).to.equal(1, 'sequence should fire after waiting');
595
+ clock.restore();
596
+ });
597
+
598
+ it('sequences timeout', function () {
599
+ var spy = sinon.spy();
600
+ var clock = sinon.useFakeTimers();
601
+
602
+ Mousetrap.bind('g t', spy);
603
+ KeyEvent.simulate('g'.charCodeAt(0), 71);
604
+ clock.tick(1000);
605
+ KeyEvent.simulate('t'.charCodeAt(0), 84);
606
+
607
+ expect(spy.callCount).to.equal(0, 'sequence callback should not fire');
608
+ clock.restore();
609
+ });
610
+ });
611
+
612
+ describe('default actions', function () {
613
+ var keys = {
614
+ keypress: [
615
+ ['a', 65],
616
+ ['A', 65, ['shift']],
617
+ ['7', 55],
618
+ ['?', 191],
619
+ ['*', 56],
620
+ ['+', 187],
621
+ ['$', 52],
622
+ ['[', 219],
623
+ ['.', 190]
624
+ ],
625
+ keydown: [
626
+ ['shift+\'', 222, ['shift']],
627
+ ['shift+a', 65, ['shift']],
628
+ ['shift+5', 53, ['shift']],
629
+ ['command+shift+p', 80, ['meta', 'shift']],
630
+ ['space', 32],
631
+ ['left', 37]
632
+ ]
633
+ };
634
+
635
+ function getCallback(key, keyCode, type, modifiers) {
636
+ return function () {
637
+ var spy = sinon.spy();
638
+ Mousetrap.bind(key, spy);
639
+
640
+ KeyEvent.simulate(key.charCodeAt(0), keyCode, modifiers);
641
+ expect(spy.callCount).to.equal(1);
642
+ expect(spy.args[0][0].type).to.equal(type);
643
+ };
644
+ }
645
+
646
+ for (var type in keys) {
647
+ for (var i = 0; i < keys[type].length; i++) {
648
+ var key = keys[type][i][0];
649
+ var keyCode = keys[type][i][1];
650
+ var modifiers = keys[type][i][2] || [];
651
+ it('"' + key + '" uses "' + type + '"', getCallback(key, keyCode, type, modifiers));
652
+ }
653
+ }
654
+ });
655
+ });
656
+
657
+ describe('Mousetrap.unbind', function () {
658
+ it('unbind works', function () {
659
+ var spy = sinon.spy();
660
+ Mousetrap.bind('a', spy);
661
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
662
+ expect(spy.callCount).to.equal(1, 'callback for a should fire');
663
+
664
+ Mousetrap.unbind('a');
665
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
666
+ expect(spy.callCount).to.equal(1, 'callback for a should not fire after unbind');
667
+ });
668
+
669
+ it('unbind accepts an array', function () {
670
+ var spy = sinon.spy();
671
+ Mousetrap.bind(['a', 'b', 'c'], spy);
672
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
673
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
674
+ KeyEvent.simulate('c'.charCodeAt(0), 67);
675
+ expect(spy.callCount).to.equal(3, 'callback should have fired 3 times');
676
+
677
+ Mousetrap.unbind(['a', 'b', 'c']);
678
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
679
+ KeyEvent.simulate('b'.charCodeAt(0), 66);
680
+ KeyEvent.simulate('c'.charCodeAt(0), 67);
681
+ expect(spy.callCount).to.equal(3, 'callback should not fire after unbind');
682
+ });
683
+ });
684
+
685
+ describe('wrapping a specific element', function () {
686
+ // Prepare the DOM for these tests.
687
+ document.body.insertAdjacentHTML('afterbegin', `
688
+ <form style="display: none;">
689
+ <textarea></textarea>
690
+ </form>
691
+ `);
692
+
693
+ var form = document.querySelector('form');
694
+ var textarea = form.querySelector('textarea');
695
+
696
+ it('z key fires when pressing z in the target element', function () {
697
+ var spy = sinon.spy();
698
+
699
+ Mousetrap(form).bind('z', spy);
700
+
701
+ KeyEvent.simulate('Z'.charCodeAt(0), 90, [], form);
702
+
703
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
704
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
705
+ expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
706
+ });
707
+
708
+ it('z key fires when pressing z in a child of the target element', function () {
709
+ var spy = sinon.spy();
710
+
711
+ Mousetrap(form).bind('z', spy);
712
+
713
+ KeyEvent.simulate('Z'.charCodeAt(0), 90, [], textarea);
714
+
715
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
716
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
717
+ expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
718
+ });
719
+
720
+ it('z key does not fire when pressing z outside the target element', function () {
721
+ var spy = sinon.spy();
722
+
723
+ Mousetrap(textarea).bind('z', spy);
724
+
725
+ KeyEvent.simulate('Z'.charCodeAt(0), 90);
726
+
727
+ expect(spy.callCount).to.equal(0, 'callback should not have fired');
728
+ });
729
+
730
+ it('should work when constructing a new mousetrap object', function () {
731
+ var spy = sinon.spy();
732
+
733
+ var mousetrap = new Mousetrap(form);
734
+ mousetrap.bind('a', spy);
735
+
736
+ KeyEvent.simulate('a'.charCodeAt(0), 65, [], textarea);
737
+
738
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
739
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
740
+ expect(spy.args[0][1]).to.equal('a', 'second argument should be key combo');
741
+ });
742
+
743
+ it('should allow you to create an empty mousetrap constructor', function () {
744
+ var spy = sinon.spy();
745
+
746
+ var mousetrap = new Mousetrap();
747
+ mousetrap.bind('a', spy);
748
+
749
+ KeyEvent.simulate('a'.charCodeAt(0), 65);
750
+
751
+ expect(spy.callCount).to.equal(1, 'callback should fire once');
752
+ expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
753
+ expect(spy.args[0][1]).to.equal('a', 'second argument should be key combo');
754
+ });
755
+ });
756
+
757
+ describe('Mouestrap.addKeycodes', function () {
758
+ it('should properly recognize non-default mapping', function () {
759
+ const spy = sinon.spy();
760
+
761
+ Mousetrap.addKeycodes({
762
+ 144: 'num',
763
+ });
764
+
765
+ Mousetrap.bind('num', spy);
766
+
767
+ KeyEvent.simulate(144, 144);
768
+ expect(spy.callCount).to.equal(1, 'callback should fire for num');
769
+
770
+ spy.resetHistory();
771
+ });
772
+ });