From 59a2d7504adf96b6469b2fc7d70ebf673747e6e8 Mon Sep 17 00:00:00 2001 From: Or Bin Date: Mon, 14 Jan 2019 23:06:45 +0200 Subject: [PATCH] Added support for 'keydown' and 'keyup' events (#6421) * Added support for 'keydown' and 'keyup' events, as requested in issue #5734 * Added tests for 'keydown', 'keypress' and 'keyup' events binding and constified the key codes used in the test file --- spec/suites/map/handler/Map.KeyboardSpec.js | 117 +++++++++++++++----- src/map/Map.js | 14 ++- 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/spec/suites/map/handler/Map.KeyboardSpec.js b/spec/suites/map/handler/Map.KeyboardSpec.js index 21942560a8e..4c0c43df40e 100644 --- a/spec/suites/map/handler/Map.KeyboardSpec.js +++ b/spec/suites/map/handler/Map.KeyboardSpec.js @@ -1,5 +1,14 @@ describe("Map.Keyboard", function () { + const KEYCODE_LOWERCASE_A = 65; + const KEYCODE_ARROW_LEFT = 37; + const KEYCODE_ARROW_UP = 38; + const KEYCODE_ARROW_RIGHT = 39; + const KEYCODE_ARROW_DOWN = 40; + const KEYCODE_PLUS = 171; + const KEYCODE_MINUS = 173; + const KEYCODE_ESC = 27; + var map, container; beforeEach(function () { @@ -25,12 +34,12 @@ describe("Map.Keyboard", function () { document.body.removeChild(container); }); - describe("cursor keys", function () { + describe("arrow keys", function () { it("move the map north", function (done) { - happen.keydown(document, {keyCode: 38}); // 38 = cursor up - happen.keypress(document, {keyCode: 38}); - happen.keyup(document, {keyCode: 38}); + happen.keydown(document, {keyCode: KEYCODE_ARROW_UP}); + happen.keypress(document, {keyCode: KEYCODE_ARROW_UP}); + happen.keyup(document, {keyCode: KEYCODE_ARROW_UP}); setTimeout(function () { expect(map.getCenter().lat).to.be.greaterThan(0); @@ -40,9 +49,9 @@ describe("Map.Keyboard", function () { it("move the map south", function (done) { - happen.keydown(document, {keyCode: 40}); // 40 = cursor down - happen.keypress(document, {keyCode: 40}); - happen.keyup(document, {keyCode: 40}); + happen.keydown(document, {keyCode: KEYCODE_ARROW_DOWN}); + happen.keypress(document, {keyCode: KEYCODE_ARROW_DOWN}); + happen.keyup(document, {keyCode: KEYCODE_ARROW_DOWN}); setTimeout(function () { expect(map.getCenter().lat).to.be.lessThan(0); @@ -52,9 +61,9 @@ describe("Map.Keyboard", function () { it("move the map west", function (done) { - happen.keydown(document, {keyCode: 37}); // 37 = cursor left - happen.keypress(document, {keyCode: 37}); - happen.keyup(document, {keyCode: 37}); + happen.keydown(document, {keyCode: KEYCODE_ARROW_LEFT}); + happen.keypress(document, {keyCode: KEYCODE_ARROW_LEFT}); + happen.keyup(document, {keyCode: KEYCODE_ARROW_LEFT}); setTimeout(function () { expect(map.getCenter().lng).to.be.lessThan(0); @@ -64,9 +73,9 @@ describe("Map.Keyboard", function () { it("move the map east", function (done) { - happen.keydown(document, {keyCode: 39}); // 39 = cursor right - happen.keypress(document, {keyCode: 39}); - happen.keyup(document, {keyCode: 39}); + happen.keydown(document, {keyCode: KEYCODE_ARROW_RIGHT}); + happen.keypress(document, {keyCode: KEYCODE_ARROW_RIGHT}); + happen.keyup(document, {keyCode: KEYCODE_ARROW_RIGHT}); setTimeout(function () { expect(map.getCenter().lng).to.be.greaterThan(0); @@ -78,9 +87,9 @@ describe("Map.Keyboard", function () { describe("plus/minus keys", function () { it("zoom in", function (done) { - happen.keydown(document, {keyCode: 171}); // 171 = + - happen.keypress(document, {keyCode: 171}); - happen.keyup(document, {keyCode: 171}); + happen.keydown(document, {keyCode: KEYCODE_PLUS}); + happen.keypress(document, {keyCode: KEYCODE_PLUS}); + happen.keyup(document, {keyCode: KEYCODE_PLUS}); setTimeout(function () { expect(map.getZoom()).to.be.greaterThan(5); @@ -90,9 +99,9 @@ describe("Map.Keyboard", function () { it("zoom out", function (done) { - happen.keydown(document, {keyCode: 173}); // 173 = - (in firefox) - happen.keypress(document, {keyCode: 173}); - happen.keyup(document, {keyCode: 173}); + happen.keydown(document, {keyCode: KEYCODE_MINUS}); + happen.keypress(document, {keyCode: KEYCODE_MINUS}); + happen.keyup(document, {keyCode: KEYCODE_MINUS}); setTimeout(function () { expect(map.getZoom()).to.be.lessThan(5); @@ -106,9 +115,9 @@ describe("Map.Keyboard", function () { map.keyboard.disable(); - happen.keydown(document, {keyCode: 171}); // 171 = + - happen.keypress(document, {keyCode: 171}); - happen.keyup(document, {keyCode: 171}); + happen.keydown(document, {keyCode: KEYCODE_PLUS}); + happen.keypress(document, {keyCode: KEYCODE_PLUS}); + happen.keyup(document, {keyCode: KEYCODE_PLUS}); setTimeout(function () { expect(map.getZoom()).to.eql(5); @@ -120,9 +129,9 @@ describe("Map.Keyboard", function () { map.keyboard.disable(); - happen.keydown(document, {keyCode: 38}); // 38 = cursor up - happen.keypress(document, {keyCode: 38}); - happen.keyup(document, {keyCode: 38}); + happen.keydown(document, {keyCode: KEYCODE_ARROW_UP}); + happen.keypress(document, {keyCode: KEYCODE_ARROW_UP}); + happen.keyup(document, {keyCode: KEYCODE_ARROW_UP}); setTimeout(function () { expect(map.getCenter().lat).to.eql(0); @@ -140,9 +149,8 @@ describe("Map.Keyboard", function () { expect(popup.isOpen()).to.be(true); - happen.keydown(document, {keyCode: 27}); // 27 = Esc - // happen.keypress(document, {keyCode: 27}); - happen.keyup(document, {keyCode: 27}); + happen.keydown(document, {keyCode: KEYCODE_ESC}); + happen.keyup(document, {keyCode: KEYCODE_ESC}); expect(popup.isOpen()).to.be(false); }); @@ -156,11 +164,60 @@ describe("Map.Keyboard", function () { expect(popup.isOpen()).to.be(true); - happen.keydown(document, {keyCode: 27}); - happen.keyup(document, {keyCode: 27}); + happen.keydown(document, {keyCode: KEYCODE_ESC}); + happen.keyup(document, {keyCode: KEYCODE_ESC}); expect(popup.isOpen()).to.be(true); }); }); + describe("keys events binding", function () { + it("keypress", function (done) { + var keyDownSpy = sinon.spy(); + var keyPressSpy = sinon.spy(); + var keyUpSpy = sinon.spy(); + + map.on('keypress', keyPressSpy); + happen.keypress(container, {keyCode: KEYCODE_LOWERCASE_A}); + + setTimeout(function () { + expect(keyDownSpy.called).to.be(false); + expect(keyPressSpy.called).to.be.ok(); + expect(keyUpSpy.called).to.be(false); + done(); + }, 50); + }); + + it("keydown", function (done) { + var keyDownSpy = sinon.spy(); + var keyPressSpy = sinon.spy(); + var keyUpSpy = sinon.spy(); + + map.on('keydown', keyDownSpy); + happen.keydown(container, {keyCode: KEYCODE_LOWERCASE_A}); + + setTimeout(function () { + expect(keyDownSpy.called).to.be.ok(); + expect(keyPressSpy.called).to.be(false); + expect(keyUpSpy.called).to.be(false); + done(); + }, 50); + }); + + it("keyup", function (done) { + var keyDownSpy = sinon.spy(); + var keyPressSpy = sinon.spy(); + var keyUpSpy = sinon.spy(); + + map.on('keyup', keyUpSpy); + happen.keyup(container, {keyCode: KEYCODE_LOWERCASE_A}); + + setTimeout(function () { + expect(keyDownSpy.called).to.be(false); + expect(keyPressSpy.called).to.be(false); + expect(keyUpSpy.called).to.be.ok(); + done(); + }, 50); + }); + }); }); diff --git a/src/map/Map.js b/src/map/Map.js index eb428f6b943..f2d9796f4cf 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -1316,9 +1316,15 @@ export var Map = Evented.extend({ // this event. Also fired on mobile when the user holds a single touch // for a second (also called long press). // @event keypress: KeyboardEvent - // Fired when the user presses a key from the keyboard while the map is focused. + // Fired when the user presses a key from the keyboard that produces a character value while the map is focused. + // @event keydown: KeyboardEvent + // Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event, + // the `keydown` event is fired for keys that produce a character value and for keys + // that do not produce a character value. + // @event keyup: KeyboardEvent + // Fired when the user releases a key from the keyboard while the map is focused. onOff(this._container, 'click dblclick mousedown mouseup ' + - 'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this); + 'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this); if (this.options.trackResize) { onOff(window, 'resize', this._onResize, this); @@ -1382,7 +1388,7 @@ export var Map = Evented.extend({ var type = e.type; - if (type === 'mousedown' || type === 'keypress') { + if (type === 'mousedown' || type === 'keypress' || type === 'keyup' || type === 'keydown') { // prevents outline when clicking on keyboard-focusable element DomUtil.preventOutline(e.target || e.srcElement); } @@ -1421,7 +1427,7 @@ export var Map = Evented.extend({ originalEvent: e }; - if (e.type !== 'keypress') { + if (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') { var isMarker = target.getLatLng && (!target._radius || target._radius <= 10); data.containerPoint = isMarker ? this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);