Comparing version 1.6.2 to 1.6.3
@@ -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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
0
1
195837
7
27
2398
102