New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mousetrap

Package Overview
Dependencies
Maintainers
2
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mousetrap - npm Package Compare versions

Comparing version 1.6.2 to 1.6.3

mousetrap.sublime-project

14

Gruntfile.js

@@ -8,12 +8,2 @@ /*jshint node:true */

mocha: {
options: {
reporter: 'Nyan',
run: true
},
mousetrap: {
src: ['tests/mousetrap.html']
}
},
complexity: {

@@ -42,8 +32,6 @@ options: {

grunt.loadNpmTasks('grunt-complexity');
grunt.loadNpmTasks('grunt-mocha');
grunt.registerTask('default', [
'complexity',
'mocha'
'complexity'
]);
};

@@ -20,3 +20,3 @@ /*global define:false */

*
* @version 1.6.2
* @version 1.6.3
* @url craig.is/killing/mice

@@ -986,2 +986,16 @@ */

// Events originating from a shadow DOM are re-targetted and `e.target` is the shadow host,
// not the initial event target in the shadow tree. Note that not all events cross the
// shadow boundary.
// For shadow trees with `mode: 'open'`, the initial event target is the first element in
// the event’s composed path. For shadow trees with `mode: 'closed'`, the initial event
// target cannot be obtained.
if ('composedPath' in e && typeof e.composedPath === 'function') {
// For open shadow trees, update `element` so that the following check works.
var initialEventTarget = e.composedPath()[0];
if (initialEventTarget !== e.target) {
element = initialEventTarget;
}
}
// stop for input, select, and textarea

@@ -988,0 +1002,0 @@ return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable;

@@ -1,11 +0,11 @@

/* mousetrap v1.6.2 craig.is/killing/mice */
(function(p,t,h){function u(a,b,d){a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}function y(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return m[a.which]?m[a.which]:q[a.which]?q[a.which]:String.fromCharCode(a.which).toLowerCase()}function E(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function v(a){return"shift"==a||"ctrl"==a||"alt"==a||
"meta"==a}function z(a,b){var d,e=[];var c=a;"+"===c?c=["+"]:(c=c.replace(/\+{2}/g,"+plus"),c=c.split("+"));for(d=0;d<c.length;++d){var k=c[d];A[k]&&(k=A[k]);b&&"keypress"!=b&&B[k]&&(k=B[k],e.push("shift"));v(k)&&e.push(k)}c=k;d=b;if(!d){if(!n){n={};for(var h in m)95<h&&112>h||m.hasOwnProperty(h)&&(n[m[h]]=h)}d=n[c]?"keydown":"keypress"}"keypress"==d&&e.length&&(d="keydown");return{key:k,modifiers:e,action:d}}function C(a,b){return null===a||a===t?!1:a===b?!0:C(a.parentNode,b)}function e(a){function b(a){a=
a||{};var b=!1,l;for(l in n)a[l]?b=!0:n[l]=0;b||(w=!1)}function d(a,b,r,g,F,e){var l,D=[],h=r.type;if(!f._callbacks[a])return[];"keyup"==h&&v(a)&&(b=[a]);for(l=0;l<f._callbacks[a].length;++l){var d=f._callbacks[a][l];if((g||!d.seq||n[d.seq]==d.level)&&h==d.action){var c;(c="keypress"==h&&!r.metaKey&&!r.ctrlKey)||(c=d.modifiers,c=b.sort().join(",")===c.sort().join(","));c&&(c=g&&d.seq==g&&d.level==e,(!g&&d.combo==F||c)&&f._callbacks[a].splice(l,1),D.push(d))}}return D}function h(a,b,d,g){f.stopCallback(b,
b.target||b.srcElement,d,g)||!1!==a(b,d)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function c(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=y(a);b&&("keyup"==a.type&&x===b?x=!1:f.handleKey(b,E(a),a))}function k(a,d,r,g){function l(d){return function(){w=d;++n[a];clearTimeout(p);p=setTimeout(b,1E3)}}function e(d){h(r,d,a);"keyup"!==g&&(x=y(d));setTimeout(b,10)}for(var c=n[a]=0;c<d.length;++c){var f=c+1===d.length?e:l(g||
z(d[c+1]).action);m(d[c],f,g,a,c)}}function m(a,b,c,g,e){f._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var h=a.split(" ");1<h.length?k(a,h,b,c):(c=z(a,c),f._callbacks[c.key]=f._callbacks[c.key]||[],d(c.key,c.modifiers,{type:c.action},g,a,e),f._callbacks[c.key][g?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:g,level:e,combo:a}))}var f=this;a=a||t;if(!(f instanceof e))return new e(a);f.target=a;f._callbacks={};f._directMap={};var n={},p,x=!1,q=!1,w=!1;f._handleKey=function(a,
c,e){var g=d(a,c,e),f;c={};var l=0,k=!1;for(f=0;f<g.length;++f)g[f].seq&&(l=Math.max(l,g[f].level));for(f=0;f<g.length;++f)g[f].seq?g[f].level==l&&(k=!0,c[g[f].seq]=1,h(g[f].callback,e,g[f].combo,g[f].seq)):k||h(g[f].callback,e,g[f].combo);g="keypress"==e.type&&q;e.type!=w||v(a)||g||b(c);q=k&&"keydown"==e.type};f._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)m(a[d],b,c)};u(a,"keypress",c);u(a,"keydown",c);u(a,"keyup",c)}if(p){var m={8:"backspace",9:"tab",13:"enter",16:"shift",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",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},q={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},B={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},A={option:"alt",command:"meta","return":"enter",
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},n;for(h=1;20>h;++h)m[111+h]="f"+h;for(h=0;9>=h;++h)m[h+96]=h.toString();e.prototype.bind=function(a,b,d){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,d);return this};e.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};e.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};e.prototype.reset=function(){this._callbacks={};
this._directMap={};return this};e.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||C(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};e.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};e.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(m[b]=a[b]);n=null};e.init=function(){var a=e(t),b;for(b in a)"_"!==b.charAt(0)&&(e[b]=function(b){return function(){return a[b].apply(a,
arguments)}}(b))};e.init();p.Mousetrap=e;"undefined"!==typeof module&&module.exports&&(module.exports=e);"function"===typeof define&&define.amd&&define(function(){return e})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null);
/* mousetrap v1.6.3 craig.is/killing/mice */
(function(q,u,c){function v(a,b,g){a.addEventListener?a.addEventListener(b,g,!1):a.attachEvent("on"+b,g)}function z(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return n[a.which]?n[a.which]:r[a.which]?r[a.which]:String.fromCharCode(a.which).toLowerCase()}function F(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function w(a){return"shift"==a||"ctrl"==a||"alt"==a||
"meta"==a}function A(a,b){var g,d=[];var e=a;"+"===e?e=["+"]:(e=e.replace(/\+{2}/g,"+plus"),e=e.split("+"));for(g=0;g<e.length;++g){var m=e[g];B[m]&&(m=B[m]);b&&"keypress"!=b&&C[m]&&(m=C[m],d.push("shift"));w(m)&&d.push(m)}e=m;g=b;if(!g){if(!p){p={};for(var c in n)95<c&&112>c||n.hasOwnProperty(c)&&(p[n[c]]=c)}g=p[e]?"keydown":"keypress"}"keypress"==g&&d.length&&(g="keydown");return{key:m,modifiers:d,action:g}}function D(a,b){return null===a||a===u?!1:a===b?!0:D(a.parentNode,b)}function d(a){function b(a){a=
a||{};var b=!1,l;for(l in p)a[l]?b=!0:p[l]=0;b||(x=!1)}function g(a,b,t,f,g,d){var l,E=[],h=t.type;if(!k._callbacks[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(l=0;l<k._callbacks[a].length;++l){var c=k._callbacks[a][l];if((f||!c.seq||p[c.seq]==c.level)&&h==c.action){var e;(e="keypress"==h&&!t.metaKey&&!t.ctrlKey)||(e=c.modifiers,e=b.sort().join(",")===e.sort().join(","));e&&(e=f&&c.seq==f&&c.level==d,(!f&&c.combo==g||e)&&k._callbacks[a].splice(l,1),E.push(c))}}return E}function c(a,b,c,f){k.stopCallback(b,
b.target||b.srcElement,c,f)||!1!==a(b,c)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function e(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=z(a);b&&("keyup"==a.type&&y===b?y=!1:k.handleKey(b,F(a),a))}function m(a,g,t,f){function h(c){return function(){x=c;++p[a];clearTimeout(q);q=setTimeout(b,1E3)}}function l(g){c(t,g,a);"keyup"!==f&&(y=z(g));setTimeout(b,10)}for(var d=p[a]=0;d<g.length;++d){var e=d+1===g.length?l:h(f||
A(g[d+1]).action);n(g[d],e,f,a,d)}}function n(a,b,c,f,d){k._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var e=a.split(" ");1<e.length?m(a,e,b,c):(c=A(a,c),k._callbacks[c.key]=k._callbacks[c.key]||[],g(c.key,c.modifiers,{type:c.action},f,a,d),k._callbacks[c.key][f?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:f,level:d,combo:a}))}var k=this;a=a||u;if(!(k instanceof d))return new d(a);k.target=a;k._callbacks={};k._directMap={};var p={},q,y=!1,r=!1,x=!1;k._handleKey=function(a,
d,e){var f=g(a,d,e),h;d={};var k=0,l=!1;for(h=0;h<f.length;++h)f[h].seq&&(k=Math.max(k,f[h].level));for(h=0;h<f.length;++h)f[h].seq?f[h].level==k&&(l=!0,d[f[h].seq]=1,c(f[h].callback,e,f[h].combo,f[h].seq)):l||c(f[h].callback,e,f[h].combo);f="keypress"==e.type&&r;e.type!=x||w(a)||f||b(d);r=l&&"keydown"==e.type};k._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)n(a[d],b,c)};v(a,"keypress",e);v(a,"keydown",e);v(a,"keyup",e)}if(q){var n={8:"backspace",9:"tab",13:"enter",16:"shift",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",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},r={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},C={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},B={option:"alt",command:"meta","return":"enter",
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p;for(c=1;20>c;++c)n[111+c]="f"+c;for(c=0;9>=c;++c)n[c+96]=c.toString();d.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};d.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};d.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};d.prototype.reset=function(){this._callbacks={};
this._directMap={};return this};d.prototype.stopCallback=function(a,b){if(-1<(" "+b.className+" ").indexOf(" mousetrap ")||D(b,this.target))return!1;if("composedPath"in a&&"function"===typeof a.composedPath){var c=a.composedPath()[0];c!==a.target&&(b=c)}return"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};d.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};d.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(n[b]=a[b]);p=null};
d.init=function(){var a=d(u),b;for(b in a)"_"!==b.charAt(0)&&(d[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};d.init();q.Mousetrap=d;"undefined"!==typeof module&&module.exports&&(module.exports=d);"function"===typeof define&&define.amd&&define(function(){return d})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null);
{
"name": "mousetrap",
"version": "1.6.2",
"version": "1.6.3",
"description": "Simple library for handling keyboard shortcuts",

@@ -10,3 +10,3 @@ "main": "mousetrap.js",

"scripts": {
"test": "grunt mocha"
"test": "mocha --reporter=nyan tests/test.mousetrap.js"
},

@@ -27,6 +27,10 @@ "repository": {

"devDependencies": {
"grunt": "~0.4.1",
"grunt-complexity": "~0.1.2",
"grunt-mocha": "~0.3.1"
"chai": "^4.2.0",
"grunt": "~1.0.3",
"grunt-complexity": "~1.1.0",
"jsdom": "^13.1.0",
"jsdom-global": "^3.0.2",
"mocha": "^5.2.0",
"sinon": "^7.2.2"
}
}

@@ -15,7 +15,7 @@ # Mousetrap

It has support for ``keypress``, ``keydown``, and ``keyup`` events on specific keys, keyboard combinations, or key sequences.
It has support for `keypress`, `keydown`, and `keyup` events on specific keys, keyboard combinations, or key sequences.
## Getting started
1. Include mousetrap on your page before the closing ``</body>`` tag
1. Include mousetrap on your page before the closing `</body>` tag

@@ -25,5 +25,5 @@ ```html

```
or install `mousetrap` from `npm` and require it
```js

@@ -33,3 +33,3 @@ var Mousetrap = require('mousetrap');

2. Add some keyboard events to listen for
2. Add some keyboard events to listen for

@@ -71,7 +71,7 @@ ```html

- There are no external dependencies, no framework is required
- You are not limited to ``keydown`` events (You can specify ``keypress``, ``keydown``, or ``keyup`` or let Mousetrap choose for you).
- You can bind key events directly to special keys such as ``?`` or ``*`` without having to specify ``shift+/`` or ``shift+8`` which are not consistent across all keyboards
- You are not limited to `keydown` events (You can specify `keypress`, `keydown`, or `keyup` or let Mousetrap choose for you).
- You can bind key events directly to special keys such as `?` or `*` without having to specify `shift+/` or `shift+8` which are not consistent across all keyboards
- It works with international keyboard layouts
- You can bind Gmail like key sequences in addition to regular keys and key combinations
- You can programatically trigger key events with the ``trigger()`` method
- You can programatically trigger key events with the `trigger()` method
- It works with the numeric keypad on your keyboard

@@ -82,19 +82,13 @@ - The code is well documented/commented

Unit tests run via <a href="http://mochajs.org/" target="_blank">mocha</a>.
Unit tests are run with <a href="https://mochajs.org/">mocha</a>.
### Running in browser
[View it online](http://rawgit.com/ccampbell/mousetrap/master/tests/mousetrap.html) to check your browser compatibility. You may also download the repo and open `tests/mousetrap.html` in your browser.
[View it online](http://rawgit.com/ccampbell/mousetrap/master/tests/mousetrap.html) to check your browser compatibility. You may also download the repo and open `tests/mousetrap.html` in your browser.
### Running with Grunt and PhantomJS
### Running with Node.js
1. Install grunt-cli
1. Install development dependencies
```bash
npm install -g grunt-cli
```
2. Install npm packages
```bash
```sh
cd /path/to/repo

@@ -104,6 +98,6 @@ npm install

3. Run tests
3. Run tests
```bash
grunt mocha
```sh
npm test
```

@@ -110,0 +104,0 @@

@@ -1,2 +0,2 @@

(function() {
(function(window, document) {
var KeyEvent = function(data, type) {

@@ -49,3 +49,3 @@ this.keyCode = 'keyCode' in data ? data.keyCode : 0;

// triggers a keydown, then a keypress, then a keyup
KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat) {
KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat, options) {
if (modifiers === undefined) {

@@ -63,2 +63,19 @@ modifiers = [];

if (options === undefined) {
options = {};
}
// Re-target the element so that `event.target` becomes the shadow host. See:
// https://developers.google.com/web/fundamentals/web-components/shadowdom#events
// This is a bit of a lie because true events would re-target the event target both for
// closed and open shadow trees. `KeyEvent` is not a true event and will fire the event
// directly from the shadow host for closed shadow trees. For open trees, this would make
// the tests fail as the actual event that will be eventually dispatched would have an
// incorrect `Event.composedPath()` starting with the shadow host instead of the
// initial event target.
if (options.shadowHost && options.shadowHost.shadowRoot === null) {
// closed shadow dom
element = options.shadowHost;
}
var modifierToKeyCode = {

@@ -131,2 +148,14 @@ 'shift': 16,

window.KeyEvent = KeyEvent;
}) ();
// expose as a common js module
if (typeof module !== 'undefined' && module.exports) {
module.exports = KeyEvent;
}
// expose KeyEvent as an AMD module
if (typeof define === 'function' && define.amd) {
define(function() {
return KeyEvent;
});
}
}) (typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null);

@@ -1,714 +0,772 @@

/* jshint es5: true, browser: true, expr: true */
/* globals describe, afterEach, chai, it, sinon, Mousetrap, KeyEvent, Event */
/**
* The following strategy of importing modules allows the tests to be run in a browser environment.
* Test libraries like `mocha`, `sinon`, etc. are expected to be loaded before this file.
*/
var sinon = sinon || require('sinon');
var chai = chai || require('chai');
var expect = chai.expect;
afterEach(function() {
Mousetrap.reset();
});
describe('Mousetrap.bind', function() {
describe('basic', function() {
it('z key fires when pressing z', function() {
var spy = sinon.spy();
if (typeof window === 'undefined') {
require('mocha');
require('jsdom-global')();
}
Mousetrap.bind('z', spy);
// Load libraries that require access to the DOM after `jsdom-global`
var Mousetrap = Mousetrap || require('./../mousetrap');
var KeyEvent = KeyEvent || require('./libs/key-event');
KeyEvent.simulate('Z'.charCodeAt(0), 90);
// really slow for some reason
// expect(spy).to.have.been.calledOnce;
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
it('z key fires from keydown', function() {
var spy = sinon.spy();
// Reset Mousetrap after each test
afterEach(function () {
Mousetrap.reset();
});
Mousetrap.bind('z', spy, 'keydown');
describe('Mousetrap.bind', function () {
describe('basic', function () {
it('z key fires when pressing z', function () {
var spy = sinon.spy();
KeyEvent.simulate('Z'.charCodeAt(0), 90);
Mousetrap.bind('z', spy);
// really slow for some reason
// expect(spy).to.have.been.calledOnce;
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
KeyEvent.simulate('Z'.charCodeAt(0), 90);
it('z key does not fire when pressing b', function() {
var spy = sinon.spy();
// really slow for some reason
// expect(spy).to.have.been.calledOnce;
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
Mousetrap.bind('z', spy);
it('z key fires from keydown', function () {
var spy = sinon.spy();
KeyEvent.simulate('B'.charCodeAt(0), 66);
Mousetrap.bind('z', spy, 'keydown');
expect(spy.callCount).to.equal(0);
});
KeyEvent.simulate('Z'.charCodeAt(0), 90);
it('z key does not fire when holding a modifier key', function() {
var spy = sinon.spy();
var modifiers = ['ctrl', 'alt', 'meta', 'shift'];
var charCode;
var modifier;
// really slow for some reason
// expect(spy).to.have.been.calledOnce;
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
Mousetrap.bind('z', spy);
it('z key does not fire when pressing b', function () {
var spy = sinon.spy();
for (var i = 0; i < 4; i++) {
modifier = modifiers[i];
charCode = 'Z'.charCodeAt(0);
Mousetrap.bind('z', spy);
// character code is different when alt is pressed
if (modifier == 'alt') {
charCode = 'Ω'.charCodeAt(0);
}
KeyEvent.simulate('B'.charCodeAt(0), 66);
spy.reset();
expect(spy.callCount).to.equal(0);
});
KeyEvent.simulate(charCode, 90, [modifier]);
it('z key does not fire when holding a modifier key', function () {
var spy = sinon.spy();
var modifiers = ['ctrl', 'alt', 'meta', 'shift'];
var charCode;
var modifier;
expect(spy.callCount).to.equal(0);
}
});
Mousetrap.bind('z', spy);
it('keyup events should fire', function() {
var spy = sinon.spy();
for (var i = 0; i < 4; i++) {
modifier = modifiers[i];
charCode = 'Z'.charCodeAt(0);
Mousetrap.bind('z', spy, 'keyup');
// character code is different when alt is pressed
if (modifier == 'alt') {
charCode = 'Ω'.charCodeAt(0);
}
KeyEvent.simulate('Z'.charCodeAt(0), 90);
spy.resetHistory();
expect(spy.callCount).to.equal(1, 'keyup event for "z" should fire');
KeyEvent.simulate(charCode, 90, [modifier]);
// for key held down we should only get one key up
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], document, 10);
expect(spy.callCount).to.equal(2, 'keyup event for "z" should fire once for held down key');
});
expect(spy.callCount).to.equal(0);
}
});
it('keyup event for 0 should fire', function() {
var spy = sinon.spy();
it('z key does not fire when inside an input element in an open shadow dom', function() {
var spy = sinon.spy();
Mousetrap.bind('0', spy, 'keyup');
var shadowHost = document.createElement('div');
var shadowRoot = shadowHost.attachShadow({ mode: 'open' });
document.body.appendChild(shadowHost);
KeyEvent.simulate(0, 48);
var inputElement = document.createElement('input');
shadowRoot.appendChild(inputElement);
expect(shadowHost.shadowRoot).to.equal(shadowRoot, 'shadow root accessible');
expect(spy.callCount).to.equal(1, 'keyup event for "0" should fire');
});
Mousetrap.bind('z', spy);
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], inputElement, 1, { shadowHost: shadowHost });
document.body.removeChild(shadowHost);
expect(spy.callCount).to.equal(0, 'callback should not have fired');
});
it('rebinding a key overwrites the callback for that key', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
Mousetrap.bind('x', spy1);
Mousetrap.bind('x', spy2);
it('z key does fire when inside an input element in a closed shadow dom', function() {
var spy = sinon.spy();
KeyEvent.simulate('X'.charCodeAt(0), 88);
var shadowHost = document.createElement('div');
var shadowRoot = shadowHost.attachShadow({ mode: 'closed' });
document.body.appendChild(shadowHost);
expect(spy1.callCount).to.equal(0, 'original callback should not fire');
expect(spy2.callCount).to.equal(1, 'new callback should fire');
});
var inputElement = document.createElement('input');
shadowRoot.appendChild(inputElement);
expect(shadowHost.shadowRoot).to.equal(null, 'shadow root unaccessible');
it('binding an array of keys', function() {
var spy = sinon.spy();
Mousetrap.bind(['a', 'b', 'c'], spy);
Mousetrap.bind('z', spy);
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], inputElement, 1, { shadowHost: shadowHost });
document.body.removeChild(shadowHost);
expect(spy.callCount).to.equal(1, 'callback should have fired once');
});
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'new callback was called');
expect(spy.args[0][1]).to.equal('a', 'callback should match "a"');
it('keyup events should fire', function() {
var spy = sinon.spy();
KeyEvent.simulate('B'.charCodeAt(0), 66);
expect(spy.callCount).to.equal(2, 'new callback was called twice');
expect(spy.args[1][1]).to.equal('b', 'callback should match "b"');
Mousetrap.bind('z', spy, 'keyup');
KeyEvent.simulate('C'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(3, 'new callback was called three times');
expect(spy.args[2][1]).to.equal('c', 'callback should match "c"');
});
KeyEvent.simulate('Z'.charCodeAt(0), 90);
it('return false should prevent default and stop propagation', function() {
var spy = sinon.spy(function() {
return false;
});
expect(spy.callCount).to.equal(1, 'keyup event for "z" should fire');
Mousetrap.bind('command+s', spy);
// for key held down we should only get one key up
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], document, 10);
expect(spy.callCount).to.equal(2, 'keyup event for "z" should fire once for held down key');
});
KeyEvent.simulate('S'.charCodeAt(0), 83, ['meta']);
it('keyup event for 0 should fire', function () {
var spy = sinon.spy();
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
Mousetrap.bind('0', spy, 'keyup');
expect(spy.args[0][0].defaultPrevented).to.be.true;
KeyEvent.simulate(0, 48);
// cancelBubble is not correctly set to true in webkit/blink
//
// @see https://code.google.com/p/chromium/issues/detail?id=162270
// expect(spy.args[0][0].cancelBubble).to.be.true;
expect(spy.callCount).to.equal(1, 'keyup event for "0" should fire');
});
// try without return false
spy = sinon.spy();
Mousetrap.bind('command+s', spy);
KeyEvent.simulate('S'.charCodeAt(0), 83, ['meta']);
it('rebinding a key overwrites the callback for that key', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
Mousetrap.bind('x', spy1);
Mousetrap.bind('x', spy2);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][0].cancelBubble).to.be.falsey;
expect(spy.args[0][0].defaultPrevented).to.be.falsey;
});
KeyEvent.simulate('X'.charCodeAt(0), 88);
it('capslock key is ignored', function() {
var spy = sinon.spy();
Mousetrap.bind('a', spy);
expect(spy1.callCount).to.equal(0, 'original callback should not fire');
expect(spy2.callCount).to.equal(1, 'new callback should fire');
});
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback should fire for lowercase a');
it('binding an array of keys', function () {
var spy = sinon.spy();
Mousetrap.bind(['a', 'b', 'c'], spy);
spy.reset();
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback should fire for capslock A');
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'new callback was called');
expect(spy.args[0][1]).to.equal('a', 'callback should match "a"');
spy.reset();
KeyEvent.simulate('A'.charCodeAt(0), 65, ['shift']);
expect(spy.callCount).to.equal(0, 'callback should not fire fort shift+a');
});
KeyEvent.simulate('B'.charCodeAt(0), 66);
expect(spy.callCount).to.equal(2, 'new callback was called twice');
expect(spy.args[1][1]).to.equal('b', 'callback should match "b"');
KeyEvent.simulate('C'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(3, 'new callback was called three times');
expect(spy.args[2][1]).to.equal('c', 'callback should match "c"');
});
describe('special characters', function() {
it('binding special characters', function() {
var spy = sinon.spy();
Mousetrap.bind('*', spy);
it('return false should prevent default and stop propagation', function () {
var spy = sinon.spy(function () {
return false;
});
KeyEvent.simulate('*'.charCodeAt(0), 56, ['shift']);
Mousetrap.bind('command+s', spy);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('*', 'callback should match *');
});
KeyEvent.simulate('S'.charCodeAt(0), 83, ['meta']);
it('binding special characters keyup', function() {
var spy = sinon.spy();
Mousetrap.bind('*', spy, 'keyup');
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
KeyEvent.simulate('*'.charCodeAt(0), 56, ['shift']);
expect(spy.args[0][0].defaultPrevented).to.be.true;
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('*', 'callback should match "*"');
});
// cancelBubble is not correctly set to true in webkit/blink
//
// @see https://code.google.com/p/chromium/issues/detail?id=162270
// expect(spy.args[0][0].cancelBubble).to.be.true;
it('binding keys with no associated charCode', function() {
var spy = sinon.spy();
Mousetrap.bind('left', spy);
// try without return false
spy = sinon.spy();
Mousetrap.bind('command+s', spy);
KeyEvent.simulate('S'.charCodeAt(0), 83, ['meta']);
KeyEvent.simulate(0, 37);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][0].cancelBubble).to.be.false;
expect(spy.args[0][0].defaultPrevented).to.be.false;
});
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('left', 'callback should match "left"');
});
it('capslock key is ignored', function () {
var spy = sinon.spy();
Mousetrap.bind('a', spy);
it('binding plus key alone should work', function() {
var spy = sinon.spy();
Mousetrap.bind('+', spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback should fire for lowercase a');
// fires for regular + character
KeyEvent.simulate('+'.charCodeAt(0), 43);
spy.resetHistory();
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback should fire for capslock A');
// and for shift+=
KeyEvent.simulate(43, 187, ['shift']);
spy.resetHistory();
KeyEvent.simulate('A'.charCodeAt(0), 65, ['shift']);
expect(spy.callCount).to.equal(0, 'callback should not fire fort shift+a');
});
});
expect(spy.callCount).to.equal(2, 'callback should fire');
expect(spy.args[0][1]).to.equal('+', 'callback should match "+"');
});
describe('special characters', function () {
it('binding special characters', function () {
var spy = sinon.spy();
Mousetrap.bind('*', spy);
it('binding plus key as "plus" should work', function() {
var spy = sinon.spy();
Mousetrap.bind('plus', spy);
KeyEvent.simulate('*'.charCodeAt(0), 56, ['shift']);
// fires for regular + character
KeyEvent.simulate('+'.charCodeAt(0), 43);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('*', 'callback should match *');
});
// and for shift+=
KeyEvent.simulate(43, 187, ['shift']);
it('binding special characters keyup', function () {
var spy = sinon.spy();
Mousetrap.bind('*', spy, 'keyup');
expect(spy.callCount).to.equal(2, 'callback should fire');
expect(spy.args[0][1]).to.equal('plus', 'callback should match "plus"');
});
KeyEvent.simulate('*'.charCodeAt(0), 56, ['shift']);
it('binding to alt++ should work', function() {
var spy = sinon.spy();
Mousetrap.bind('alt++', spy);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('*', 'callback should match "*"');
});
KeyEvent.simulate('+'.charCodeAt(0), 43, ['alt']);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('alt++', 'callback should match "alt++"');
});
it('binding keys with no associated charCode', function () {
var spy = sinon.spy();
Mousetrap.bind('left', spy);
it('binding to alt+shift++ should work as well', function() {
var spy = sinon.spy();
Mousetrap.bind('alt+shift++', spy);
KeyEvent.simulate(0, 37);
KeyEvent.simulate('+'.charCodeAt(0), 43, ['shift', 'alt']);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('alt+shift++', 'callback should match "alt++"');
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('left', 'callback should match "left"');
});
})
it('binding plus key alone should work', function () {
var spy = sinon.spy();
Mousetrap.bind('+', spy);
// fires for regular + character
KeyEvent.simulate('+'.charCodeAt(0), 43);
// and for shift+=
KeyEvent.simulate(43, 187, ['shift']);
expect(spy.callCount).to.equal(2, 'callback should fire');
expect(spy.args[0][1]).to.equal('+', 'callback should match "+"');
});
describe('combos with modifiers', function() {
it('binding key combinations', function() {
var spy = sinon.spy();
Mousetrap.bind('command+o', spy);
it('binding plus key as "plus" should work', function () {
var spy = sinon.spy();
Mousetrap.bind('plus', spy);
KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta']);
// fires for regular + character
KeyEvent.simulate('+'.charCodeAt(0), 43);
expect(spy.callCount).to.equal(1, 'command+o callback should fire');
expect(spy.args[0][1]).to.equal('command+o', 'keyboard string returned is correct');
});
// and for shift+=
KeyEvent.simulate(43, 187, ['shift']);
it('binding key combos with multiple modifiers', function() {
var spy = sinon.spy();
Mousetrap.bind('command+shift+o', spy);
KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta']);
expect(spy.callCount).to.equal(0, 'command+o callback should not fire');
expect(spy.callCount).to.equal(2, 'callback should fire');
expect(spy.args[0][1]).to.equal('plus', 'callback should match "plus"');
});
KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta', 'shift']);
expect(spy.callCount).to.equal(1, 'command+o callback should fire');
});
it('binding to alt++ should work', function () {
var spy = sinon.spy();
Mousetrap.bind('alt++', spy);
it('should fire callback when ctrl+numpad 0 is pressed', function() {
var spy = sinon.spy();
KeyEvent.simulate('+'.charCodeAt(0), 43, ['alt']);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('alt++', 'callback should match "alt++"');
});
Mousetrap.bind('ctrl+0', spy);
it('binding to alt+shift++ should work as well', function () {
var spy = sinon.spy();
Mousetrap.bind('alt+shift++', spy);
// numpad 0 keycode
KeyEvent.simulate(96, 96, ['ctrl']);
KeyEvent.simulate('+'.charCodeAt(0), 43, ['shift', 'alt']);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.args[0][1]).to.equal('alt+shift++', 'callback should match "alt++"');
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('ctrl+0', 'second argument should be key combo');
});
});
});
describe('sequences', function() {
it('binding sequences', function() {
var spy = sinon.spy();
Mousetrap.bind('g i', spy);
describe('combos with modifiers', function () {
it('binding key combinations', function () {
var spy = sinon.spy();
Mousetrap.bind('command+o', spy);
KeyEvent.simulate('G'.charCodeAt(0), 71);
expect(spy.callCount).to.equal(0, 'callback should not fire');
KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta']);
KeyEvent.simulate('I'.charCodeAt(0), 73);
expect(spy.callCount).to.equal(1, 'callback should fire');
});
expect(spy.callCount).to.equal(1, 'command+o callback should fire');
expect(spy.args[0][1]).to.equal('command+o', 'keyboard string returned is correct');
});
it('binding sequences with mixed types', function() {
var spy = sinon.spy();
Mousetrap.bind('g o enter', spy);
it('binding key combos with multiple modifiers', function () {
var spy = sinon.spy();
Mousetrap.bind('command+shift+o', spy);
KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta']);
expect(spy.callCount).to.equal(0, 'command+o callback should not fire');
KeyEvent.simulate('G'.charCodeAt(0), 71);
expect(spy.callCount).to.equal(0, 'callback should not fire');
KeyEvent.simulate('O'.charCodeAt(0), 79, ['meta', 'shift']);
expect(spy.callCount).to.equal(1, 'command+o callback should fire');
});
KeyEvent.simulate('O'.charCodeAt(0), 79);
expect(spy.callCount).to.equal(0, 'callback should not fire');
it('should fire callback when ctrl+numpad 0 is pressed', function () {
var spy = sinon.spy();
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
});
Mousetrap.bind('ctrl+0', spy);
it('binding sequences starting with modifier keys', function() {
var spy = sinon.spy();
Mousetrap.bind('option enter', spy);
KeyEvent.simulate(0, 18, ['alt']);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
// numpad 0 keycode
KeyEvent.simulate(96, 96, ['ctrl']);
spy = sinon.spy();
Mousetrap.bind('command enter', spy);
KeyEvent.simulate(0, 91, ['meta']);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('ctrl+0', 'second argument should be key combo');
});
});
spy = sinon.spy();
Mousetrap.bind('escape enter', spy);
KeyEvent.simulate(0, 27);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
});
describe('sequences', function () {
it('binding sequences', function () {
var spy = sinon.spy();
Mousetrap.bind('g i', spy);
it('key within sequence should not fire', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
Mousetrap.bind('a', spy1);
Mousetrap.bind('c a t', spy2);
KeyEvent.simulate('G'.charCodeAt(0), 71);
expect(spy.callCount).to.equal(0, 'callback should not fire');
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy1.callCount).to.equal(1, 'callback 1 should fire');
spy1.reset();
KeyEvent.simulate('I'.charCodeAt(0), 73);
expect(spy.callCount).to.equal(1, 'callback should fire');
});
KeyEvent.simulate('C'.charCodeAt(0), 67);
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate('T'.charCodeAt(0), 84);
expect(spy1.callCount).to.equal(0, 'callback for "a" key should not fire');
expect(spy2.callCount).to.equal(1, 'callback for "c a t" sequence should fire');
});
it('binding sequences with mixed types', function () {
var spy = sinon.spy();
Mousetrap.bind('g o enter', spy);
it('keyup at end of sequence should not fire', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
KeyEvent.simulate('G'.charCodeAt(0), 71);
expect(spy.callCount).to.equal(0, 'callback should not fire');
Mousetrap.bind('t', spy1, 'keyup');
Mousetrap.bind('b a t', spy2);
KeyEvent.simulate('O'.charCodeAt(0), 79);
expect(spy.callCount).to.equal(0, 'callback should not fire');
KeyEvent.simulate('B'.charCodeAt(0), 66);
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate('T'.charCodeAt(0), 84);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
});
expect(spy1.callCount).to.equal(0, 'callback for "t" keyup should not fire');
expect(spy2.callCount).to.equal(1, 'callback for "b a t" sequence should fire');
});
it('binding sequences starting with modifier keys', function () {
var spy = sinon.spy();
Mousetrap.bind('option enter', spy);
KeyEvent.simulate(0, 18, ['alt']);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
it('keyup sequences should work', function() {
var spy = sinon.spy();
Mousetrap.bind('b a t', spy, 'keyup');
spy = sinon.spy();
Mousetrap.bind('command enter', spy);
KeyEvent.simulate(0, 91, ['meta']);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('a'.charCodeAt(0), 65);
spy = sinon.spy();
Mousetrap.bind('escape enter', spy);
KeyEvent.simulate(0, 27);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'callback should fire');
});
// hold the last key down for a while
KeyEvent.simulate('t'.charCodeAt(0), 84, [], document, 10);
it('key within sequence should not fire', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
Mousetrap.bind('a', spy1);
Mousetrap.bind('c a t', spy2);
expect(spy.callCount).to.equal(1, 'callback for "b a t" sequence should fire on keyup');
});
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy1.callCount).to.equal(1, 'callback 1 should fire');
spy1.resetHistory();
it('extra spaces in sequences should be ignored', function() {
var spy = sinon.spy();
Mousetrap.bind('b a t', spy);
KeyEvent.simulate('C'.charCodeAt(0), 67);
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate('T'.charCodeAt(0), 84);
expect(spy1.callCount).to.equal(0, 'callback for "a" key should not fire');
expect(spy2.callCount).to.equal(1, 'callback for "c a t" sequence should fire');
});
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('t'.charCodeAt(0), 84);
it('keyup at end of sequence should not fire', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
expect(spy.callCount).to.equal(1, 'callback for "b a t" sequence should fire');
});
Mousetrap.bind('t', spy1, 'keyup');
Mousetrap.bind('b a t', spy2);
it('modifiers and sequences play nicely', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
KeyEvent.simulate('B'.charCodeAt(0), 66);
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate('T'.charCodeAt(0), 84);
Mousetrap.bind('ctrl a', spy1);
Mousetrap.bind('ctrl+b', spy2);
expect(spy1.callCount).to.equal(0, 'callback for "t" keyup should not fire');
expect(spy2.callCount).to.equal(1, 'callback for "b a t" sequence should fire');
});
KeyEvent.simulate(0, 17, ['ctrl']);
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy1.callCount).to.equal(1, '"ctrl a" should fire');
it('keyup sequences should work', function () {
var spy = sinon.spy();
Mousetrap.bind('b a t', spy, 'keyup');
KeyEvent.simulate('B'.charCodeAt(0), 66, ['ctrl']);
expect(spy2.callCount).to.equal(1, '"ctrl+b" should fire');
});
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('a'.charCodeAt(0), 65);
it('sequences that start the same work', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
// hold the last key down for a while
KeyEvent.simulate('t'.charCodeAt(0), 84, [], document, 10);
Mousetrap.bind('g g l', spy2);
Mousetrap.bind('g g o', spy1);
expect(spy.callCount).to.equal(1, 'callback for "b a t" sequence should fire on keyup');
});
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('o'.charCodeAt(0), 79);
expect(spy1.callCount).to.equal(1, '"g g o" should fire');
expect(spy2.callCount).to.equal(0, '"g g l" should not fire');
it('extra spaces in sequences should be ignored', function () {
var spy = sinon.spy();
Mousetrap.bind('b a t', spy);
spy1.reset();
spy2.reset();
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('l'.charCodeAt(0), 76);
expect(spy1.callCount).to.equal(0, '"g g o" should not fire');
expect(spy2.callCount).to.equal(1, '"g g l" should fire');
});
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('t'.charCodeAt(0), 84);
it('sequences should not fire subsequences', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
expect(spy.callCount).to.equal(1, 'callback for "b a t" sequence should fire');
});
Mousetrap.bind('a b c', spy1);
Mousetrap.bind('b c', spy2);
it('modifiers and sequences play nicely', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate('B'.charCodeAt(0), 66);
KeyEvent.simulate('C'.charCodeAt(0), 67);
Mousetrap.bind('ctrl a', spy1);
Mousetrap.bind('ctrl+b', spy2);
expect(spy1.callCount).to.equal(1, '"a b c" should fire');
expect(spy2.callCount).to.equal(0, '"b c" should not fire');
KeyEvent.simulate(0, 17, ['ctrl']);
KeyEvent.simulate('A'.charCodeAt(0), 65);
expect(spy1.callCount).to.equal(1, '"ctrl a" should fire');
spy1.reset();
spy2.reset();
Mousetrap.bind('option b', spy1);
Mousetrap.bind('a option b', spy2);
KeyEvent.simulate('B'.charCodeAt(0), 66, ['ctrl']);
expect(spy2.callCount).to.equal(1, '"ctrl+b" should fire');
});
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate(0, 18, ['alt']);
KeyEvent.simulate('B'.charCodeAt(0), 66);
it('sequences that start the same work', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
expect(spy1.callCount).to.equal(0, '"option b" should not fire');
expect(spy2.callCount).to.equal(1, '"a option b" should fire');
});
Mousetrap.bind('g g l', spy2);
Mousetrap.bind('g g o', spy1);
it('rebinding same sequence should override previous', function() {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
Mousetrap.bind('a b c', spy1);
Mousetrap.bind('a b c', spy2);
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('o'.charCodeAt(0), 79);
expect(spy1.callCount).to.equal(1, '"g g o" should fire');
expect(spy2.callCount).to.equal(0, '"g g l" should not fire');
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
spy1.resetHistory();
spy2.resetHistory();
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('g'.charCodeAt(0), 71);
KeyEvent.simulate('l'.charCodeAt(0), 76);
expect(spy1.callCount).to.equal(0, '"g g o" should not fire');
expect(spy2.callCount).to.equal(1, '"g g l" should fire');
});
expect(spy1.callCount).to.equal(0, 'first callback should not fire');
expect(spy2.callCount).to.equal(1, 'second callback should fire');
});
it('sequences should not fire subsequences', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
it('broken sequences', function() {
var spy = sinon.spy();
Mousetrap.bind('h a t', spy);
Mousetrap.bind('a b c', spy1);
Mousetrap.bind('b c', spy2);
KeyEvent.simulate('h'.charCodeAt(0), 72);
KeyEvent.simulate('e'.charCodeAt(0), 69);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('r'.charCodeAt(0), 82);
KeyEvent.simulate('t'.charCodeAt(0), 84);
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate('B'.charCodeAt(0), 66);
KeyEvent.simulate('C'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(0, 'sequence for "h a t" should not fire for "h e a r t"');
});
expect(spy1.callCount).to.equal(1, '"a b c" should fire');
expect(spy2.callCount).to.equal(0, '"b c" should not fire');
it('sequences containing combos should work', function() {
var spy = sinon.spy();
Mousetrap.bind('a ctrl+b', spy);
spy1.resetHistory();
spy2.resetHistory();
Mousetrap.bind('option b', spy1);
Mousetrap.bind('a option b', spy2);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('B'.charCodeAt(0), 66, ['ctrl']);
KeyEvent.simulate('A'.charCodeAt(0), 65);
KeyEvent.simulate(0, 18, ['alt']);
KeyEvent.simulate('B'.charCodeAt(0), 66);
expect(spy.callCount).to.equal(1, '"a ctrl+b" should fire');
expect(spy1.callCount).to.equal(0, '"option b" should not fire');
expect(spy2.callCount).to.equal(1, '"a option b" should fire');
});
Mousetrap.unbind('a ctrl+b');
it('rebinding same sequence should override previous', function () {
var spy1 = sinon.spy();
var spy2 = sinon.spy();
Mousetrap.bind('a b c', spy1);
Mousetrap.bind('a b c', spy2);
spy = sinon.spy();
Mousetrap.bind('ctrl+b a', spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
KeyEvent.simulate('b'.charCodeAt(0), 66, ['ctrl']);
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy1.callCount).to.equal(0, 'first callback should not fire');
expect(spy2.callCount).to.equal(1, 'second callback should fire');
});
expect(spy.callCount).to.equal(1, '"ctrl+b a" should fire');
});
it('broken sequences', function () {
var spy = sinon.spy();
Mousetrap.bind('h a t', spy);
it('sequences starting with spacebar should work', function() {
var spy = sinon.spy();
Mousetrap.bind('a space b c', spy);
KeyEvent.simulate('h'.charCodeAt(0), 72);
KeyEvent.simulate('e'.charCodeAt(0), 69);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('r'.charCodeAt(0), 82);
KeyEvent.simulate('t'.charCodeAt(0), 84);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate(32, 32);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(0, 'sequence for "h a t" should not fire for "h e a r t"');
});
expect(spy.callCount).to.equal(1, '"a space b c" should fire');
});
it('sequences containing combos should work', function () {
var spy = sinon.spy();
Mousetrap.bind('a ctrl+b', spy);
it('konami code', function() {
var spy = sinon.spy();
Mousetrap.bind('up up down down left right left right b a enter', spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('B'.charCodeAt(0), 66, ['ctrl']);
KeyEvent.simulate(0, 38);
KeyEvent.simulate(0, 38);
KeyEvent.simulate(0, 40);
KeyEvent.simulate(0, 40);
KeyEvent.simulate(0, 37);
KeyEvent.simulate(0, 39);
KeyEvent.simulate(0, 37);
KeyEvent.simulate(0, 39);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, '"a ctrl+b" should fire');
expect(spy.callCount).to.equal(1, 'konami code should fire');
});
Mousetrap.unbind('a ctrl+b');
it('sequence timer resets', function() {
var spy = sinon.spy();
var clock = sinon.useFakeTimers();
spy = sinon.spy();
Mousetrap.bind('ctrl+b a', spy);
Mousetrap.bind('h a t', spy);
KeyEvent.simulate('b'.charCodeAt(0), 66, ['ctrl']);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('h'.charCodeAt(0), 72);
clock.tick(600);
KeyEvent.simulate('a'.charCodeAt(0), 65);
clock.tick(900);
KeyEvent.simulate('t'.charCodeAt(0), 84);
expect(spy.callCount).to.equal(1, '"ctrl+b a" should fire');
});
expect(spy.callCount).to.equal(1, 'sequence should fire after waiting');
clock.restore();
});
it('sequences starting with spacebar should work', function () {
var spy = sinon.spy();
Mousetrap.bind('a space b c', spy);
it('sequences timeout', function() {
var spy = sinon.spy();
var clock = sinon.useFakeTimers();
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate(32, 32);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
Mousetrap.bind('g t', spy);
KeyEvent.simulate('g'.charCodeAt(0), 71);
clock.tick(1000);
KeyEvent.simulate('t'.charCodeAt(0), 84);
expect(spy.callCount).to.equal(1, '"a space b c" should fire');
});
expect(spy.callCount).to.equal(0, 'sequence callback should not fire');
clock.restore();
});
it('konami code', function () {
var spy = sinon.spy();
Mousetrap.bind('up up down down left right left right b a enter', spy);
KeyEvent.simulate(0, 38);
KeyEvent.simulate(0, 38);
KeyEvent.simulate(0, 40);
KeyEvent.simulate(0, 40);
KeyEvent.simulate(0, 37);
KeyEvent.simulate(0, 39);
KeyEvent.simulate(0, 37);
KeyEvent.simulate(0, 39);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate(0, 13);
expect(spy.callCount).to.equal(1, 'konami code should fire');
});
describe('default actions', function() {
var keys = {
keypress: [
['a', 65],
['A', 65, ['shift']],
['7', 55],
['?', 191],
['*', 56],
['+', 187],
['$', 52],
['[', 219],
['.', 190]
],
keydown: [
['shift+\'', 222, ['shift']],
['shift+a', 65, ['shift']],
['shift+5', 53, ['shift']],
['command+shift+p', 80, ['meta', 'shift']],
['space', 32],
['left', 37]
]
};
it('sequence timer resets', function () {
var spy = sinon.spy();
var clock = sinon.useFakeTimers();
function getCallback(key, keyCode, type, modifiers) {
return function() {
var spy = sinon.spy();
Mousetrap.bind(key, spy);
Mousetrap.bind('h a t', spy);
KeyEvent.simulate(key.charCodeAt(0), keyCode, modifiers);
expect(spy.callCount).to.equal(1);
expect(spy.args[0][0].type).to.equal(type);
};
}
KeyEvent.simulate('h'.charCodeAt(0), 72);
clock.tick(600);
KeyEvent.simulate('a'.charCodeAt(0), 65);
clock.tick(900);
KeyEvent.simulate('t'.charCodeAt(0), 84);
for (var type in keys) {
for (var i = 0; i < keys[type].length; i++) {
var key = keys[type][i][0];
var keyCode = keys[type][i][1];
var modifiers = keys[type][i][2] || [];
it('"' + key + '" uses "' + type + '"', getCallback(key, keyCode, type, modifiers));
}
}
expect(spy.callCount).to.equal(1, 'sequence should fire after waiting');
clock.restore();
});
});
describe('Mousetrap.unbind', function() {
it('unbind works', function() {
var spy = sinon.spy();
Mousetrap.bind('a', spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback for a should fire');
it('sequences timeout', function () {
var spy = sinon.spy();
var clock = sinon.useFakeTimers();
Mousetrap.unbind('a');
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback for a should not fire after unbind');
Mousetrap.bind('g t', spy);
KeyEvent.simulate('g'.charCodeAt(0), 71);
clock.tick(1000);
KeyEvent.simulate('t'.charCodeAt(0), 84);
expect(spy.callCount).to.equal(0, 'sequence callback should not fire');
clock.restore();
});
});
it('unbind accepts an array', function() {
describe('default actions', function () {
var keys = {
keypress: [
['a', 65],
['A', 65, ['shift']],
['7', 55],
['?', 191],
['*', 56],
['+', 187],
['$', 52],
['[', 219],
['.', 190]
],
keydown: [
['shift+\'', 222, ['shift']],
['shift+a', 65, ['shift']],
['shift+5', 53, ['shift']],
['command+shift+p', 80, ['meta', 'shift']],
['space', 32],
['left', 37]
]
};
function getCallback(key, keyCode, type, modifiers) {
return function () {
var spy = sinon.spy();
Mousetrap.bind(['a', 'b', 'c'], spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(3, 'callback should have fired 3 times');
Mousetrap.bind(key, spy);
Mousetrap.unbind(['a', 'b', 'c']);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(3, 'callback should not fire after unbind');
});
KeyEvent.simulate(key.charCodeAt(0), keyCode, modifiers);
expect(spy.callCount).to.equal(1);
expect(spy.args[0][0].type).to.equal(type);
};
}
for (var type in keys) {
for (var i = 0; i < keys[type].length; i++) {
var key = keys[type][i][0];
var keyCode = keys[type][i][1];
var modifiers = keys[type][i][2] || [];
it('"' + key + '" uses "' + type + '"', getCallback(key, keyCode, type, modifiers));
}
}
});
});
describe('wrapping a specific element', function() {
var form = document.querySelector('form');
var textarea = form.querySelector('textarea');
describe('Mousetrap.unbind', function () {
it('unbind works', function () {
var spy = sinon.spy();
Mousetrap.bind('a', spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback for a should fire');
it('z key fires when pressing z in the target element', function() {
var spy = sinon.spy();
Mousetrap.unbind('a');
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback for a should not fire after unbind');
});
Mousetrap(form).bind('z', spy);
it('unbind accepts an array', function () {
var spy = sinon.spy();
Mousetrap.bind(['a', 'b', 'c'], spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(3, 'callback should have fired 3 times');
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], form);
Mousetrap.unbind(['a', 'b', 'c']);
KeyEvent.simulate('a'.charCodeAt(0), 65);
KeyEvent.simulate('b'.charCodeAt(0), 66);
KeyEvent.simulate('c'.charCodeAt(0), 67);
expect(spy.callCount).to.equal(3, 'callback should not fire after unbind');
});
});
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
describe('wrapping a specific element', function () {
// Prepare the DOM for these tests.
document.body.insertAdjacentHTML('afterbegin', `
<form style="display: none;">
<textarea></textarea>
</form>
`);
it('z key fires when pressing z in a child of the target element', function() {
var spy = sinon.spy();
var form = document.querySelector('form');
var textarea = form.querySelector('textarea');
Mousetrap(form).bind('z', spy);
it('z key fires when pressing z in the target element', function () {
var spy = sinon.spy();
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], textarea);
Mousetrap(form).bind('z', spy);
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], form);
it('z key does not fire when pressing z outside the target element', function() {
var spy = sinon.spy();
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
Mousetrap(textarea).bind('z', spy);
it('z key fires when pressing z in a child of the target element', function () {
var spy = sinon.spy();
KeyEvent.simulate('Z'.charCodeAt(0), 90);
Mousetrap(form).bind('z', spy);
expect(spy.callCount).to.equal(0, 'callback should not have fired');
});
KeyEvent.simulate('Z'.charCodeAt(0), 90, [], textarea);
it('should work when constructing a new mousetrap object', function() {
var spy = sinon.spy();
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('z', 'second argument should be key combo');
});
var mousetrap = new Mousetrap(form);
mousetrap.bind('a', spy);
it('z key does not fire when pressing z outside the target element', function () {
var spy = sinon.spy();
KeyEvent.simulate('a'.charCodeAt(0), 65, [], textarea);
Mousetrap(textarea).bind('z', spy);
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('a', 'second argument should be key combo');
});
KeyEvent.simulate('Z'.charCodeAt(0), 90);
it('should allow you to create an empty mousetrap constructor', function() {
var spy = sinon.spy();
expect(spy.callCount).to.equal(0, 'callback should not have fired');
});
var mousetrap = new Mousetrap();
mousetrap.bind('a', spy);
it('should work when constructing a new mousetrap object', function () {
var spy = sinon.spy();
KeyEvent.simulate('a'.charCodeAt(0), 65);
var mousetrap = new Mousetrap(form);
mousetrap.bind('a', spy);
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('a', 'second argument should be key combo');
});
KeyEvent.simulate('a'.charCodeAt(0), 65, [], textarea);
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('a', 'second argument should be key combo');
});
it('should allow you to create an empty mousetrap constructor', function () {
var spy = sinon.spy();
var mousetrap = new Mousetrap();
mousetrap.bind('a', spy);
KeyEvent.simulate('a'.charCodeAt(0), 65);
expect(spy.callCount).to.equal(1, 'callback should fire once');
expect(spy.args[0][0]).to.be.an.instanceOf(Event, 'first argument should be Event');
expect(spy.args[0][1]).to.equal('a', 'second argument should be key combo');
});
});
describe('Mouestrap.addKeycodes', function() {
it('should properly recognize non-default mapping', function() {
var spy = sinon.spy();
describe('Mouestrap.addKeycodes', function () {
it('should properly recognize non-default mapping', function () {
const spy = sinon.spy();
Mousetrap.addKeycodes({
144: 'num',
});
Mousetrap.addKeycodes({
144: 'num',
});
Mousetrap.bind('num', spy);
Mousetrap.bind('num', spy);
KeyEvent.simulate(144, 144);
expect(spy.callCount).to.equal(1, 'callback should fire for num');
KeyEvent.simulate(144, 144);
expect(spy.callCount).to.equal(1, 'callback should fire for num');
spy.reset();
});
spy.resetHistory();
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc