From de1b4ddb977b5a98aaca8f4480f635740578f5ad Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Wed, 21 Oct 2020 16:40:16 +0200 Subject: [PATCH] Improve tests and fix singleclick --- src/ol/MapBrowserEventHandler.js | 10 +- test/spec/ol/MapBrowserEventHandler.test.js | 133 +++++++++++++++----- 2 files changed, 109 insertions(+), 34 deletions(-) diff --git a/src/ol/MapBrowserEventHandler.js b/src/ol/MapBrowserEventHandler.js index a8878986ff..d345c24999 100644 --- a/src/ol/MapBrowserEventHandler.js +++ b/src/ol/MapBrowserEventHandler.js @@ -31,6 +31,12 @@ class MapBrowserEventHandler extends EventTarget { */ this.clickTimeoutId_; + /** + * Emulate dblclick and singleclick. Will be true when only one pointer is active. + * @type {boolean} + */ + this.emulateClicks_ = false; + /** * @type {boolean} * @private @@ -137,7 +143,7 @@ class MapBrowserEventHandler extends EventTarget { pointerEvent ); this.dispatchEvent(newEvent); - } else if (this.activePointers_ === 0) { + } else { // click this.clickTimeoutId_ = setTimeout( /** @this {MapBrowserEventHandler} */ @@ -197,6 +203,7 @@ class MapBrowserEventHandler extends EventTarget { // We only fire click, singleclick, and doubleclick if nobody has called // event.stopPropagation() or event.preventDefault(). if ( + this.emulateClicks_ && !newEvent.propagationStopped && !this.dragging_ && this.isMouseActionButton_(pointerEvent) @@ -228,6 +235,7 @@ class MapBrowserEventHandler extends EventTarget { * @private */ handlePointerDown_(pointerEvent) { + this.emulateClicks_ = this.activePointers_ === 0; this.updateActivePointers_(pointerEvent); const newEvent = new MapBrowserEvent( MapBrowserEventType.POINTERDOWN, diff --git a/test/spec/ol/MapBrowserEventHandler.test.js b/test/spec/ol/MapBrowserEventHandler.test.js index 7039f329fd..c6bfc07959 100644 --- a/test/spec/ol/MapBrowserEventHandler.test.js +++ b/test/spec/ol/MapBrowserEventHandler.test.js @@ -1,6 +1,6 @@ -import Event from '../../../src/ol/events/Event.js'; import Map from '../../../src/ol/Map.js'; import MapBrowserEventHandler from '../../../src/ol/MapBrowserEventHandler.js'; +import OlEvent from '../../../src/ol/events/Event.js'; import {DEVICE_PIXEL_RATIO} from '../../../src/ol/has.js'; import {listen} from '../../../src/ol/events.js'; @@ -37,7 +37,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('emulates click', function () { - const event = new Event(); + const event = new OlEvent(); event.type = 'pointerdown'; (event.target = target), (event.clientX = 0); event.clientY = 0; @@ -46,7 +46,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('emulates singleclick', function () { - const event = new Event(); + const event = new OlEvent(); event.type = 'pointerdown'; event.target = target; event.clientX = 0; @@ -65,7 +65,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('emulates dblclick', function () { - const event = new Event(); + const event = new OlEvent(); event.type = 'pointerdown'; event.target = target; event.clientX = 0; @@ -82,26 +82,6 @@ describe('ol/MapBrowserEventHandler', function () { expect(singleclickSpy.called).to.not.be.ok(); expect(dblclickSpy.calledOnce).to.be.ok(); }); - - it('does not emulate dblclick when multiple pointers are involved', function () { - const event = new Event(); - event.type = 'pointerdown'; - event.target = target; - event.clientX = 0; - event.clientY = 0; - handler.activePointers_ = 1; - handler.emulateClick_(event); - expect(singleclickSpy.called).to.not.be.ok(); - expect(dblclickSpy.called).to.not.be.ok(); - - handler.emulateClick_(event); - expect(singleclickSpy.called).to.not.be.ok(); - expect(dblclickSpy.called).to.not.be.ok(); - - clock.tick(250); - expect(singleclickSpy.called).to.not.be.ok(); - expect(dblclickSpy.called).to.not.be.ok(); - }); }); describe('#down_', function () { @@ -115,7 +95,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is an event after handlePointerDown_ has been called', function () { - const event = new Event('pointerdown'); + const event = new OlEvent('pointerdown'); handler.handlePointerDown_(event); expect(handler.down_).to.be(event); }); @@ -128,7 +108,7 @@ describe('ol/MapBrowserEventHandler', function () { beforeEach(function () { defaultHandler = new MapBrowserEventHandler(new Map({})); moveToleranceHandler = new MapBrowserEventHandler(new Map({}), 8); - pointerdownAt0 = new Event(); + pointerdownAt0 = new OlEvent(); pointerdownAt0.type = 'pointerdown'; pointerdownAt0.clientX = 0; pointerdownAt0.clientY = 0; @@ -137,7 +117,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is not moving if distance is 0', function () { - pointerdownAt0 = new Event(); + pointerdownAt0 = new OlEvent(); pointerdownAt0.type = 'pointerdown'; pointerdownAt0.clientX = 0; pointerdownAt0.clientY = 0; @@ -145,7 +125,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is moving if distance is 2', function () { - const pointerdownAt2 = new Event(); + const pointerdownAt2 = new OlEvent(); pointerdownAt2.type = 'pointerdown'; pointerdownAt2.clientX = DEVICE_PIXEL_RATIO + 1; pointerdownAt2.clientY = DEVICE_PIXEL_RATIO + 1; @@ -153,7 +133,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is moving with negative distance', function () { - const pointerdownAt2 = new Event(); + const pointerdownAt2 = new OlEvent(); pointerdownAt2.type = 'pointerdown'; pointerdownAt2.clientX = -(DEVICE_PIXEL_RATIO + 1); pointerdownAt2.clientY = -(DEVICE_PIXEL_RATIO + 1); @@ -161,7 +141,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is not moving if distance is less than move tolerance', function () { - const pointerdownAt2 = new Event(); + const pointerdownAt2 = new OlEvent(); pointerdownAt2.type = 'pointerdown'; pointerdownAt2.clientX = DEVICE_PIXEL_RATIO + 1; pointerdownAt2.clientY = DEVICE_PIXEL_RATIO + 1; @@ -169,7 +149,7 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is moving if distance is greater than move tolerance', function () { - const pointerdownAt9 = new Event(); + const pointerdownAt9 = new OlEvent(); pointerdownAt9.type = 'pointerdown'; pointerdownAt9.clientX = DEVICE_PIXEL_RATIO * 8 + 1; pointerdownAt9.clientY = DEVICE_PIXEL_RATIO * 8 + 1; @@ -177,13 +157,13 @@ describe('ol/MapBrowserEventHandler', function () { }); it('is moving when moving back close to the down pixel', function () { - const pointermoveAt9 = new Event(); + const pointermoveAt9 = new OlEvent(); pointermoveAt9.type = 'pointermove'; pointermoveAt9.clientX = DEVICE_PIXEL_RATIO * 8 + 1; pointermoveAt9.clientY = DEVICE_PIXEL_RATIO * 8 + 1; moveToleranceHandler.handlePointerMove_(pointermoveAt9); expect(moveToleranceHandler.isMoving_(pointermoveAt9)).to.be(true); - const pointermoveAt2 = new Event(); + const pointermoveAt2 = new OlEvent(); pointermoveAt2.type = 'pointermove'; pointermoveAt2.clientX = DEVICE_PIXEL_RATIO + 1; pointermoveAt2.clientY = DEVICE_PIXEL_RATIO + 1; @@ -208,4 +188,91 @@ describe('ol/MapBrowserEventHandler', function () { expect(event.preventDefault.callCount).to.be(1); }); }); + + describe('dblclick', function () { + let clock; + let handler; + let clickSpy; + let singleclickSpy; + let dblclickSpy; + let target; + let element, down1, down2, up1, up2; + + beforeEach(function () { + clock = sinon.useFakeTimers(); + target = document.createElement('div'); + handler = new MapBrowserEventHandler( + new Map({ + target: target, + }) + ); + + element = handler.element_; + down1 = new Event('pointerdown', {target: element}); + down1.clientX = 0; + down1.clientY = 0; + down1.button = 0; + down1.pointerId = 1; + down2 = new Event('pointerdown', {target: element}); + down2.clientX = 0; + down2.clientY = 0; + down2.button = 0; + down2.pointerId = 2; + up1 = new Event('pointerup', {target: element}); + up1.clientX = 0; + up1.clientY = 0; + up1.button = 0; + up1.pointerId = 1; + up2 = new Event('pointerup', {target: element}); + up2.clientX = 0; + up2.clientY = 0; + up2.button = 0; + up2.pointerId = 2; + + clickSpy = sinon.spy(); + listen(handler, 'click', clickSpy); + + singleclickSpy = sinon.spy(); + listen(handler, 'singleclick', singleclickSpy); + + dblclickSpy = sinon.spy(); + listen(handler, 'dblclick', dblclickSpy); + }); + + afterEach(function () { + clock.restore(); + }); + + it('emulates dblclick', function () { + element.dispatchEvent(down1); + document.dispatchEvent(up1); + expect(singleclickSpy.called).to.not.be.ok(); + expect(dblclickSpy.called).to.not.be.ok(); + + element.dispatchEvent(down2); + document.dispatchEvent(up2); + expect(singleclickSpy.called).to.not.be.ok(); + expect(dblclickSpy.called).to.be.ok(); + + clock.tick(250); + expect(singleclickSpy.called).to.not.be.ok(); + expect(dblclickSpy.called).to.be.ok(); + }); + + it('does not emulate dblclick and singleclick when multiple pointers are active', function () { + element.dispatchEvent(down1); + element.dispatchEvent(down2); + expect(singleclickSpy.called).to.not.be.ok(); + expect(dblclickSpy.called).to.not.be.ok(); + + document.dispatchEvent(up1); + document.dispatchEvent(up2); + expect(singleclickSpy.called).to.not.be.ok(); + expect(dblclickSpy.called).to.not.be.ok(); + + clock.tick(250); + expect(singleclickSpy.called).to.not.be.ok(); + expect(dblclickSpy.called).to.not.be.ok(); + }); + }); });