From a9156dc5ee43b5f3f7908420eb18b2b9e0dc65c8 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Fri, 20 Oct 2023 23:20:19 +0200 Subject: [PATCH 01/14] #2498: Don't show cooperativeGestures messages when scrollZoom is disabled --- src/ui/handler/scroll_zoom.ts | 1 + src/ui/map.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index abf354f4bd..f013b41616 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -149,6 +149,7 @@ export class ScrollZoomHandler implements Handler { disable() { if (!this.isEnabled()) return; this._enabled = false; + this._map._destroyCooperativeGestures(); } wheel(e: WheelEvent) { diff --git a/src/ui/map.ts b/src/ui/map.ts index e4603ef894..1f4e28bb57 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -656,7 +656,7 @@ export class Map extends Camera { this.handlers = new HandlerManager(this, options as CompleteMapOptions); - if (this._cooperativeGestures) { + if (this._cooperativeGestures && options.scrollZoom) { this._setupCooperativeGestures(); } From 68ba8ed71a902b5367128653129da702e16a098f Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Sat, 21 Oct 2023 16:57:28 +0200 Subject: [PATCH 02/14] #2498: code review remarks addressed --- src/ui/handler/scroll_zoom.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index f013b41616..4099d5dc96 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -136,6 +136,7 @@ export class ScrollZoomHandler implements Handler { if (this.isEnabled()) return; this._enabled = true; this._aroundCenter = !!options && (options as AroundCenterOptions).around === 'center'; + this._map._setupCooperativeGestures(); } /** From 2d2d87bcd04c3179ce7402b7409022ff102903b4 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Sun, 22 Oct 2023 15:14:24 +0200 Subject: [PATCH 03/14] #2498: moved logic related to cooperativeGestures to ScrollZoomHandler --- src/ui/handler/scroll_zoom.ts | 61 ++++++++++++++++++++++++++++++++--- src/ui/handler/touch_pan.ts | 2 +- src/ui/map.ts | 58 +++------------------------------ 3 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index 4099d5dc96..e6dd4f75b0 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -6,7 +6,7 @@ import {interpolates} from '@maplibre/maplibre-gl-style-spec'; import {LngLat} from '../../geo/lng_lat'; import {TransformProvider} from './transform-provider'; -import type {Map} from '../map'; +import type {GestureOptions, Map} from '../map'; import type Point from '@mapbox/point-geometry'; import type {AroundCenterOptions} from './two_fingers_touch'; import {Handler} from '../handler_manager'; @@ -30,7 +30,11 @@ const maxScalePerFrame = 2; */ export class ScrollZoomHandler implements Handler { _map: Map; + _cooperativeGesturesScreen: HTMLElement; + _cooperativeGestures: boolean | GestureOptions; _tr: TransformProvider; + _metaKey: keyof MouseEvent; + //canvasContainer _el: HTMLElement; _enabled: boolean; _active: boolean; @@ -66,6 +70,7 @@ export class ScrollZoomHandler implements Handler { constructor(map: Map, triggerRenderFrame: () => void) { this._map = map; this._tr = new TransformProvider(map); + this._metaKey = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; this._el = map.getCanvasContainer(); this._triggerRenderFrame = triggerRenderFrame; @@ -136,7 +141,9 @@ export class ScrollZoomHandler implements Handler { if (this.isEnabled()) return; this._enabled = true; this._aroundCenter = !!options && (options as AroundCenterOptions).around === 'center'; - this._map._setupCooperativeGestures(); + if (this._map.getCooperativeGestures()) { + this.setupCooperativeGestures(); + } } /** @@ -150,13 +157,15 @@ export class ScrollZoomHandler implements Handler { disable() { if (!this.isEnabled()) return; this._enabled = false; - this._map._destroyCooperativeGestures(); + if (this._map.getCooperativeGestures()) { + this.destroyCooperativeGestures(); + } } wheel(e: WheelEvent) { if (!this.isEnabled()) return; if (this._map._cooperativeGestures) { - if (e[this._map._metaKey]) { + if (e[this._metaKey]) { e.preventDefault(); } else { return; @@ -360,4 +369,48 @@ export class ScrollZoomHandler implements Handler { delete this._finishTimeout; } } + + setupCooperativeGestures() { + this._cooperativeGestures = this._map.getCooperativeGestures(); + this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map._container); + let desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.windowsHelpText ? this._cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; + if (navigator.platform.indexOf('Mac') === 0) { + desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.macHelpText ? this._cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; + } + const mobileMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.mobileHelpText ? this._cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; + this._cooperativeGesturesScreen.innerHTML = ` +
${desktopMessage}
+
${mobileMessage}
+ `; + + // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures + this._cooperativeGesturesScreen.setAttribute('aria-hidden', 'true'); + + // Add event to canvas container since gesture container is pointer-events: none + this._el.addEventListener('wheel', this._cooperativeGesturesOnWheel, false); + + // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) + this._el.classList.add('maplibregl-cooperative-gestures'); + } + + destroyCooperativeGestures() { + DOM.remove(this._cooperativeGesturesScreen); + this._el.removeEventListener('wheel', this._cooperativeGesturesOnWheel, false); + this._el.classList.remove('maplibregl-cooperative-gestures'); + } + + _cooperativeGesturesOnWheel = (event: WheelEvent) => { + this._onCooperativeGesture(event, event[this._metaKey], 1); + }; + + _onCooperativeGesture(event: any, metaPress, touches) { + if (!metaPress && touches < 2) { + // Alert user how to scroll/pan + this._cooperativeGesturesScreen.classList.add('maplibregl-show'); + setTimeout(() => { + this._cooperativeGesturesScreen.classList.remove('maplibregl-show'); + }, 100); + } + return false; + } } diff --git a/src/ui/handler/touch_pan.ts b/src/ui/handler/touch_pan.ts index be3eff4fdb..d07999ac48 100644 --- a/src/ui/handler/touch_pan.ts +++ b/src/ui/handler/touch_pan.ts @@ -46,7 +46,7 @@ export class TouchPanHandler implements Handler { if (this._map._cooperativeGestures) { if (this._minTouches === 2 && mapTouches.length < 2 && !this._cancelCooperativeMessage) { // If coop gesture enabled, show panning info to user - this._map._onCooperativeGesture(e, false, mapTouches.length); + this._map.scrollZoom._onCooperativeGesture(e, false, mapTouches.length); } else if (!this._cancelCooperativeMessage) { // If user is successfully navigating, we don't need this warning until the touch resets this._cancelCooperativeMessage = true; diff --git a/src/ui/map.ts b/src/ui/map.ts index 1f4e28bb57..02a18935fc 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -450,15 +450,12 @@ export class Map extends Camera { style: Style; painter: Painter; handlers: HandlerManager; - _container: HTMLElement; _canvasContainer: HTMLElement; _controlContainer: HTMLElement; _controlPositions: {[_: string]: HTMLElement}; _interactive: boolean; _cooperativeGestures: boolean | GestureOptions; - _cooperativeGesturesScreen: HTMLElement; - _metaKey: keyof MouseEvent; _showTileBoundaries: boolean; _showCollisionBoxes: boolean; _showPadding: boolean; @@ -583,7 +580,6 @@ export class Map extends Camera { this._interactive = options.interactive; this._cooperativeGestures = options.cooperativeGestures; - this._metaKey = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; this._maxTileCacheSize = options.maxTileCacheSize; this._maxTileCacheZoomLevels = options.maxTileCacheZoomLevels; this._failIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat; @@ -656,8 +652,8 @@ export class Map extends Camera { this.handlers = new HandlerManager(this, options as CompleteMapOptions); - if (this._cooperativeGestures && options.scrollZoom) { - this._setupCooperativeGestures(); + if (this._cooperativeGestures) { + this.scrollZoom.setupCooperativeGestures(); } const hashName = (typeof options.hash === 'string' && options.hash) || undefined; @@ -1176,9 +1172,9 @@ export class Map extends Camera { setCooperativeGestures(gestureOptions?: GestureOptions | boolean | null): Map { this._cooperativeGestures = gestureOptions; if (this._cooperativeGestures) { - this._setupCooperativeGestures(); + this.scrollZoom.setupCooperativeGestures(); } else { - this._destroyCooperativeGestures(); + this.scrollZoom.destroyCooperativeGestures(); } return this; @@ -2940,39 +2936,6 @@ export class Map extends Camera { this._container.addEventListener('scroll', this._onMapScroll, false); } - _cooperativeGesturesOnWheel = (event: WheelEvent) => { - this._onCooperativeGesture(event, event[this._metaKey], 1); - }; - - _setupCooperativeGestures() { - const container = this._container; - this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', container); - let desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.windowsHelpText ? this._cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; - if (navigator.platform.indexOf('Mac') === 0) { - desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.macHelpText ? this._cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; - } - const mobileMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.mobileHelpText ? this._cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; - this._cooperativeGesturesScreen.innerHTML = ` -
${desktopMessage}
-
${mobileMessage}
- `; - - // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures - this._cooperativeGesturesScreen.setAttribute('aria-hidden', 'true'); - - // Add event to canvas container since gesture container is pointer-events: none - this._canvasContainer.addEventListener('wheel', this._cooperativeGesturesOnWheel, false); - - // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) - this._canvasContainer.classList.add('maplibregl-cooperative-gestures'); - } - - _destroyCooperativeGestures() { - DOM.remove(this._cooperativeGesturesScreen); - this._canvasContainer.removeEventListener('wheel', this._cooperativeGesturesOnWheel, false); - this._canvasContainer.classList.remove('maplibregl-cooperative-gestures'); - } - _resizeCanvas(width: number, height: number, pixelRatio: number) { // Request the required canvas size taking the pixelratio into account. this._canvas.width = Math.floor(pixelRatio * width); @@ -3047,17 +3010,6 @@ export class Map extends Camera { return false; }; - _onCooperativeGesture(event: any, metaPress, touches) { - if (!metaPress && touches < 2) { - // Alert user how to scroll/pan - this._cooperativeGesturesScreen.classList.add('maplibregl-show'); - setTimeout(() => { - this._cooperativeGesturesScreen.classList.remove('maplibregl-show'); - }, 100); - } - return false; - } - /** * Returns a Boolean indicating whether the map is fully loaded. * @@ -3286,7 +3238,7 @@ export class Map extends Camera { DOM.remove(this._canvasContainer); DOM.remove(this._controlContainer); if (this._cooperativeGestures) { - this._destroyCooperativeGestures(); + this.scrollZoom.destroyCooperativeGestures(); } this._container.classList.remove('maplibregl-map'); From 784cbf690301cf790d42c4569bdbb0d51abee185 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Sun, 22 Oct 2023 22:08:18 +0200 Subject: [PATCH 04/14] #2498: change some function calls + add done calls in unit tests --- src/ui/handler/scroll_zoom.ts | 11 +++-------- src/ui/map.test.ts | 2 ++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index e6dd4f75b0..d4113df697 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -34,7 +34,6 @@ export class ScrollZoomHandler implements Handler { _cooperativeGestures: boolean | GestureOptions; _tr: TransformProvider; _metaKey: keyof MouseEvent; - //canvasContainer _el: HTMLElement; _enabled: boolean; _active: boolean; @@ -141,9 +140,7 @@ export class ScrollZoomHandler implements Handler { if (this.isEnabled()) return; this._enabled = true; this._aroundCenter = !!options && (options as AroundCenterOptions).around === 'center'; - if (this._map.getCooperativeGestures()) { - this.setupCooperativeGestures(); - } + if (this._map.getCooperativeGestures()) this.setupCooperativeGestures(); } /** @@ -157,9 +154,7 @@ export class ScrollZoomHandler implements Handler { disable() { if (!this.isEnabled()) return; this._enabled = false; - if (this._map.getCooperativeGestures()) { - this.destroyCooperativeGestures(); - } + if (this._map.getCooperativeGestures()) this.destroyCooperativeGestures(); } wheel(e: WheelEvent) { @@ -372,7 +367,7 @@ export class ScrollZoomHandler implements Handler { setupCooperativeGestures() { this._cooperativeGestures = this._map.getCooperativeGestures(); - this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map._container); + this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map.getContainer()); let desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.windowsHelpText ? this._cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; if (navigator.platform.indexOf('Mac') === 0) { desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.macHelpText ? this._cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; diff --git a/src/ui/map.test.ts b/src/ui/map.test.ts index d5d90778a5..09c6ddc573 100755 --- a/src/ui/map.test.ts +++ b/src/ui/map.test.ts @@ -567,6 +567,7 @@ describe('Map', () => { }); map.addSource('geojson', createStyleSource()); expect(map.isSourceLoaded('geojson')).toBe(false); + done(); }); }); @@ -586,6 +587,7 @@ describe('Map', () => { }); map.addSource('geojson', createStyleSource()); expect(map.isSourceLoaded('geojson')).toBe(false); + done(); }); }); From e3677ebb06cdd4f8abf446e96266db865257c4bd Mon Sep 17 00:00:00 2001 From: Arkadiusz Date: Sun, 22 Oct 2023 22:53:26 +0200 Subject: [PATCH 05/14] Update _metaKey in scroll_zoom.ts --- src/ui/handler/scroll_zoom.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index d4113df697..62cad4425f 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -33,7 +33,7 @@ export class ScrollZoomHandler implements Handler { _cooperativeGesturesScreen: HTMLElement; _cooperativeGestures: boolean | GestureOptions; _tr: TransformProvider; - _metaKey: keyof MouseEvent; + _metaKey: keyof MouseEvent = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; _el: HTMLElement; _enabled: boolean; _active: boolean; @@ -69,7 +69,6 @@ export class ScrollZoomHandler implements Handler { constructor(map: Map, triggerRenderFrame: () => void) { this._map = map; this._tr = new TransformProvider(map); - this._metaKey = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; this._el = map.getCanvasContainer(); this._triggerRenderFrame = triggerRenderFrame; From ddeebe175441973e074590075a0753b0c3ce1e0a Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Mon, 23 Oct 2023 18:59:52 +0200 Subject: [PATCH 06/14] #2498: decrease size --- src/ui/map.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ui/map.ts b/src/ui/map.ts index 02a18935fc..cf973beb4c 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -652,9 +652,7 @@ export class Map extends Camera { this.handlers = new HandlerManager(this, options as CompleteMapOptions); - if (this._cooperativeGestures) { - this.scrollZoom.setupCooperativeGestures(); - } + if (this._cooperativeGestures) this.scrollZoom.setupCooperativeGestures(); const hashName = (typeof options.hash === 'string' && options.hash) || undefined; this._hash = options.hash && (new Hash(hashName)).addTo(this); From af5c20aaea9eea52cba2e88d1e694652ec281665 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Mon, 23 Oct 2023 20:18:25 +0200 Subject: [PATCH 07/14] #2498: decrease dist size --- src/ui/handler/scroll_zoom.ts | 12 ++++-------- src/ui/map.ts | 4 +--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index 62cad4425f..750ee21689 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -31,7 +31,6 @@ const maxScalePerFrame = 2; export class ScrollZoomHandler implements Handler { _map: Map; _cooperativeGesturesScreen: HTMLElement; - _cooperativeGestures: boolean | GestureOptions; _tr: TransformProvider; _metaKey: keyof MouseEvent = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; _el: HTMLElement; @@ -365,24 +364,21 @@ export class ScrollZoomHandler implements Handler { } setupCooperativeGestures() { - this._cooperativeGestures = this._map.getCooperativeGestures(); + const cooperativeGestures = this._map.getCooperativeGestures(); this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map.getContainer()); - let desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.windowsHelpText ? this._cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; + let desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.windowsHelpText ? cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; if (navigator.platform.indexOf('Mac') === 0) { - desktopMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.macHelpText ? this._cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; + desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.macHelpText ? cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; } - const mobileMessage = typeof this._cooperativeGestures !== 'boolean' && this._cooperativeGestures.mobileHelpText ? this._cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; + const mobileMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.mobileHelpText ? cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; this._cooperativeGesturesScreen.innerHTML = `
${desktopMessage}
${mobileMessage}
`; - // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures this._cooperativeGesturesScreen.setAttribute('aria-hidden', 'true'); - // Add event to canvas container since gesture container is pointer-events: none this._el.addEventListener('wheel', this._cooperativeGesturesOnWheel, false); - // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) this._el.classList.add('maplibregl-cooperative-gestures'); } diff --git a/src/ui/map.ts b/src/ui/map.ts index cf973beb4c..e2f30ba436 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -3235,9 +3235,7 @@ export class Map extends Camera { this._canvas.removeEventListener('webglcontextlost', this._contextLost, false); DOM.remove(this._canvasContainer); DOM.remove(this._controlContainer); - if (this._cooperativeGestures) { - this.scrollZoom.destroyCooperativeGestures(); - } + if (this._cooperativeGestures) this.scrollZoom.destroyCooperativeGestures(); this._container.classList.remove('maplibregl-map'); PerformanceUtils.clearMetrics(); From 239e94c0eb98f8c6108bd5e10edabc2ad338cb35 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Mon, 23 Oct 2023 20:19:22 +0200 Subject: [PATCH 08/14] #2498: remove unused import type --- src/ui/handler/scroll_zoom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index 750ee21689..bc4fa620dc 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -6,7 +6,7 @@ import {interpolates} from '@maplibre/maplibre-gl-style-spec'; import {LngLat} from '../../geo/lng_lat'; import {TransformProvider} from './transform-provider'; -import type {GestureOptions, Map} from '../map'; +import type {Map} from '../map'; import type Point from '@mapbox/point-geometry'; import type {AroundCenterOptions} from './two_fingers_touch'; import {Handler} from '../handler_manager'; From 8feb7f0bbbc7e95c48c4f152884c7f28fb8970e9 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Tue, 24 Oct 2023 21:11:24 +0200 Subject: [PATCH 09/14] #2498: replace deprecated navigator.platform with navigator.userAgent --- src/ui/handler/scroll_zoom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index bc4fa620dc..d11e44f050 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -32,7 +32,7 @@ export class ScrollZoomHandler implements Handler { _map: Map; _cooperativeGesturesScreen: HTMLElement; _tr: TransformProvider; - _metaKey: keyof MouseEvent = navigator.platform.indexOf('Mac') === 0 ? 'metaKey' : 'ctrlKey'; + _metaKey: keyof MouseEvent = navigator.userAgent.indexOf('Mac') !== -1 ? 'metaKey' : 'ctrlKey'; _el: HTMLElement; _enabled: boolean; _active: boolean; From eaf50c5bb150f59581dcea641d5b7938b4f90899 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Wed, 25 Oct 2023 09:03:11 +0200 Subject: [PATCH 10/14] #2498: remove abundant done() calls --- src/ui/map.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ui/map.test.ts b/src/ui/map.test.ts index 09c6ddc573..d5d90778a5 100755 --- a/src/ui/map.test.ts +++ b/src/ui/map.test.ts @@ -567,7 +567,6 @@ describe('Map', () => { }); map.addSource('geojson', createStyleSource()); expect(map.isSourceLoaded('geojson')).toBe(false); - done(); }); }); @@ -587,7 +586,6 @@ describe('Map', () => { }); map.addSource('geojson', createStyleSource()); expect(map.isSourceLoaded('geojson')).toBe(false); - done(); }); }); From 51e83057e3ff29cb4bb995110a1049243f6d2e20 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Wed, 25 Oct 2023 16:04:06 +0200 Subject: [PATCH 11/14] #2498: new CooperativeGestureControl --- src/ui/control/cooperative_gesture_contol.ts | 111 +++++++++++++++++++ src/ui/control/fullscreen_control.ts | 3 +- src/ui/handler/scroll_zoom.ts | 47 +------- src/ui/handler/touch_pan.ts | 18 +-- src/ui/map.ts | 34 +++--- 5 files changed, 131 insertions(+), 82 deletions(-) create mode 100644 src/ui/control/cooperative_gesture_contol.ts diff --git a/src/ui/control/cooperative_gesture_contol.ts b/src/ui/control/cooperative_gesture_contol.ts new file mode 100644 index 0000000000..c7b3666cf4 --- /dev/null +++ b/src/ui/control/cooperative_gesture_contol.ts @@ -0,0 +1,111 @@ +import {DOM} from '../../util/dom'; + +import type {Map} from '../map'; +import type {ControlPosition, IControl} from './control'; + +/** + * The {@link CooperativeGestureControl} options object + */ +/** + * An options object for the gesture settings + * @example + * ```ts + * let options = { + * windowsHelpText: "Use Ctrl + scroll to zoom the map", + * macHelpText: "Use ⌘ + scroll to zoom the map", + * mobileHelpText: "Use two fingers to move the map", + * } + * ``` + */ +export type GestureOptions = { + windowsHelpText?: string; + macHelpText?: string; + mobileHelpText?: string; +}; + +/** + * A `CooperativeGestureControl` is a control that adds cooperative gesture info when user tries to zoom in/out. + * + * @group Markers and Controls + * + * @example + * ```ts + * map.addControl(new maplibregl.CooperativeGestureControl({ + * windowsHelpText: "Use Ctrl + scroll to zoom the map", + * macHelpText: "Use ⌘ + scroll to zoom the map", + * mobileHelpText: "Use two fingers to move the map", + * })); + * ``` + **/ +export class CooperativeGestureControl implements IControl { + options: boolean | GestureOptions; + _map: Map; + _container: HTMLElement; + _metaKey: keyof MouseEvent = navigator.userAgent.indexOf('Mac') !== -1 ? 'metaKey' : 'ctrlKey'; + + constructor(options: boolean | GestureOptions = {}) { + this.options = options; + } + + getDefaultPosition(): ControlPosition { + return 'top-left'; + } + + /** {@inheritDoc IControl.onAdd} */ + onAdd(map: Map) { + this._map = map; + const mapCanvasContainer = this._map.getCanvasContainer(); + const cooperativeGestures = this._map.getCooperativeGestures(); + this._container = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map.getContainer()); + let desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.windowsHelpText ? cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; + if (this._metaKey === 'metaKey') { + desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.macHelpText ? cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; + } + const mobileMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.mobileHelpText ? cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; + this._container.innerHTML = ` +
${desktopMessage}
+
${mobileMessage}
+ `; + // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures + this._container.setAttribute('aria-hidden', 'true'); + // Add event to canvas container since gesture container is pointer-events: none + this._map.on('wheel', this._cooperativeGesturesOnWheel); + this._map.on('touchmove', this._cooperativeGesturesOnTouch); + // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) + mapCanvasContainer.classList.add('maplibregl-cooperative-gestures'); + + return this._container; + } + + /** {@inheritDoc IControl.onRemove} */ + onRemove() { + DOM.remove(this._container); + if (this._map) { + const mapCanvasContainer = this._map.getCanvasContainer(); + this._map.off('wheel', this._cooperativeGesturesOnWheel); + this._map.off('touchmove', this._cooperativeGesturesOnTouch); + mapCanvasContainer.classList.remove('maplibregl-cooperative-gestures'); + this._map = undefined; + } + } + + _cooperativeGesturesOnTouch = (event: TouchEvent) => { + this._onCooperativeGesture(event, false); + }; + + _cooperativeGesturesOnWheel = (event: WheelEvent) => { + this._onCooperativeGesture(event, event[this._metaKey]); + }; + + _onCooperativeGesture(event: any, metaPress) { + if (!metaPress) { + // Alert user how to scroll/pan + this._container.classList.add('maplibregl-show'); + setTimeout(() => { + this._container.classList.remove('maplibregl-show'); + }, 100); + } + return false; + } + +} diff --git a/src/ui/control/fullscreen_control.ts b/src/ui/control/fullscreen_control.ts index fb7af04a58..13b9467f5a 100644 --- a/src/ui/control/fullscreen_control.ts +++ b/src/ui/control/fullscreen_control.ts @@ -3,8 +3,9 @@ import {DOM} from '../../util/dom'; import {warnOnce} from '../../util/util'; import {Event, Evented} from '../../util/evented'; -import type {Map, GestureOptions} from '../map'; +import type {Map} from '../map'; import type {IControl} from './control'; +import {GestureOptions} from './cooperative_gesture_contol'; /** * The {@link FullscreenControl} options diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index d11e44f050..42bdb9d92d 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -30,7 +30,6 @@ const maxScalePerFrame = 2; */ export class ScrollZoomHandler implements Handler { _map: Map; - _cooperativeGesturesScreen: HTMLElement; _tr: TransformProvider; _metaKey: keyof MouseEvent = navigator.userAgent.indexOf('Mac') !== -1 ? 'metaKey' : 'ctrlKey'; _el: HTMLElement; @@ -138,7 +137,8 @@ export class ScrollZoomHandler implements Handler { if (this.isEnabled()) return; this._enabled = true; this._aroundCenter = !!options && (options as AroundCenterOptions).around === 'center'; - if (this._map.getCooperativeGestures()) this.setupCooperativeGestures(); + const cooperativeGestures = this._map.getCooperativeGestures(); + if (cooperativeGestures) this._map.setCooperativeGestures(cooperativeGestures); } /** @@ -152,7 +152,7 @@ export class ScrollZoomHandler implements Handler { disable() { if (!this.isEnabled()) return; this._enabled = false; - if (this._map.getCooperativeGestures()) this.destroyCooperativeGestures(); + this._map.setCooperativeGestures(null); } wheel(e: WheelEvent) { @@ -362,45 +362,4 @@ export class ScrollZoomHandler implements Handler { delete this._finishTimeout; } } - - setupCooperativeGestures() { - const cooperativeGestures = this._map.getCooperativeGestures(); - this._cooperativeGesturesScreen = DOM.create('div', 'maplibregl-cooperative-gesture-screen', this._map.getContainer()); - let desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.windowsHelpText ? cooperativeGestures.windowsHelpText : 'Use Ctrl + scroll to zoom the map'; - if (navigator.platform.indexOf('Mac') === 0) { - desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.macHelpText ? cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; - } - const mobileMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.mobileHelpText ? cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; - this._cooperativeGesturesScreen.innerHTML = ` -
${desktopMessage}
-
${mobileMessage}
- `; - // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures - this._cooperativeGesturesScreen.setAttribute('aria-hidden', 'true'); - // Add event to canvas container since gesture container is pointer-events: none - this._el.addEventListener('wheel', this._cooperativeGesturesOnWheel, false); - // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) - this._el.classList.add('maplibregl-cooperative-gestures'); - } - - destroyCooperativeGestures() { - DOM.remove(this._cooperativeGesturesScreen); - this._el.removeEventListener('wheel', this._cooperativeGesturesOnWheel, false); - this._el.classList.remove('maplibregl-cooperative-gestures'); - } - - _cooperativeGesturesOnWheel = (event: WheelEvent) => { - this._onCooperativeGesture(event, event[this._metaKey], 1); - }; - - _onCooperativeGesture(event: any, metaPress, touches) { - if (!metaPress && touches < 2) { - // Alert user how to scroll/pan - this._cooperativeGesturesScreen.classList.add('maplibregl-show'); - setTimeout(() => { - this._cooperativeGesturesScreen.classList.remove('maplibregl-show'); - }, 100); - } - return false; - } } diff --git a/src/ui/handler/touch_pan.ts b/src/ui/handler/touch_pan.ts index d07999ac48..b759e6a696 100644 --- a/src/ui/handler/touch_pan.ts +++ b/src/ui/handler/touch_pan.ts @@ -1,8 +1,9 @@ import Point from '@mapbox/point-geometry'; import {indexTouches} from './handler_util'; import type {Map} from '../map'; -import {GestureOptions} from '../map'; + import {Handler} from '../handler_manager'; +import {GestureOptions} from '../control/cooperative_gesture_contol'; export class TouchPanHandler implements Handler { @@ -15,7 +16,6 @@ export class TouchPanHandler implements Handler { _clickTolerance: number; _sum: Point; _map: Map; - _cancelCooperativeMessage: boolean; constructor(options: { clickTolerance: number; @@ -31,11 +31,6 @@ export class TouchPanHandler implements Handler { this._active = false; this._touches = {}; this._sum = new Point(0, 0); - - // Put a delay on the cooperative gesture message so it's less twitchy - setTimeout(() => { - this._cancelCooperativeMessage = false; - }, 200); } touchstart(e: TouchEvent, points: Array, mapTouches: Array) { @@ -43,15 +38,6 @@ export class TouchPanHandler implements Handler { } touchmove(e: TouchEvent, points: Array, mapTouches: Array) { - if (this._map._cooperativeGestures) { - if (this._minTouches === 2 && mapTouches.length < 2 && !this._cancelCooperativeMessage) { - // If coop gesture enabled, show panning info to user - this._map.scrollZoom._onCooperativeGesture(e, false, mapTouches.length); - } else if (!this._cancelCooperativeMessage) { - // If user is successfully navigating, we don't need this warning until the touch resets - this._cancelCooperativeMessage = true; - } - } if (!this._active || mapTouches.length < this._minTouches) return; e.preventDefault(); return this._calculateTransform(e, points, mapTouches); diff --git a/src/ui/map.ts b/src/ui/map.ts index e2f30ba436..737883109d 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -65,6 +65,7 @@ import {Terrain} from '../render/terrain'; import {RenderToTexture} from '../render/render_to_texture'; import {config} from '../util/config'; import type {QueryRenderedFeaturesOptions, QuerySourceFeatureOptions} from '../source/query_features'; +import {CooperativeGestureControl, GestureOptions} from './control/cooperative_gesture_contol'; const version = packageJSON.version; @@ -328,23 +329,6 @@ export type MapOptions = { maxCanvasSize?: [number, number]; }; -/** - * An options object for the gesture settings - * @example - * ```ts - * let options = { - * windowsHelpText: "Use Ctrl + scroll to zoom the map", - * macHelpText: "Use ⌘ + scroll to zoom the map", - * mobileHelpText: "Use two fingers to move the map", - * } - * ``` - */ -export type GestureOptions = { - windowsHelpText?: string; - macHelpText?: string; - mobileHelpText?: string; -}; - export type AddImageOptions = { } @@ -456,6 +440,7 @@ export class Map extends Camera { _controlPositions: {[_: string]: HTMLElement}; _interactive: boolean; _cooperativeGestures: boolean | GestureOptions; + _cooperativeGesturesControl: CooperativeGestureControl; _showTileBoundaries: boolean; _showCollisionBoxes: boolean; _showPadding: boolean; @@ -652,7 +637,9 @@ export class Map extends Camera { this.handlers = new HandlerManager(this, options as CompleteMapOptions); - if (this._cooperativeGestures) this.scrollZoom.setupCooperativeGestures(); + if (options.cooperativeGestures) { + this.addControl(new CooperativeGestureControl(options.cooperativeGestures)); + } const hashName = (typeof options.hash === 'string' && options.hash) || undefined; this._hash = options.hash && (new Hash(hashName)).addTo(this); @@ -1170,9 +1157,14 @@ export class Map extends Camera { setCooperativeGestures(gestureOptions?: GestureOptions | boolean | null): Map { this._cooperativeGestures = gestureOptions; if (this._cooperativeGestures) { - this.scrollZoom.setupCooperativeGestures(); + if (this._cooperativeGesturesControl) { + //remove existing control + this.removeControl(this._cooperativeGesturesControl); + } + this._cooperativeGesturesControl = new CooperativeGestureControl(this._cooperativeGestures); + this.addControl(this._cooperativeGesturesControl); } else { - this.scrollZoom.destroyCooperativeGestures(); + this.removeControl(this._cooperativeGesturesControl); } return this; @@ -3235,7 +3227,7 @@ export class Map extends Camera { this._canvas.removeEventListener('webglcontextlost', this._contextLost, false); DOM.remove(this._canvasContainer); DOM.remove(this._controlContainer); - if (this._cooperativeGestures) this.scrollZoom.destroyCooperativeGestures(); + if (this._cooperativeGestures) this.removeControl(this._cooperativeGesturesControl); this._container.classList.remove('maplibregl-map'); PerformanceUtils.clearMetrics(); From 6e734ce1980fcdfd1366e542ba001e372ccca201 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Fri, 27 Oct 2023 16:42:01 +0200 Subject: [PATCH 12/14] #2498: completely separated CooperativeGestureControl --- src/ui/control/control.ts | 2 +- src/ui/control/cooperative_gesture_contol.ts | 35 ++++++++++++-------- src/ui/handler/scroll_zoom.ts | 2 +- src/ui/map.test.ts | 8 ++++- src/ui/map.ts | 7 ++-- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/ui/control/control.ts b/src/ui/control/control.ts index eb715d669b..cfbbccc4f2 100644 --- a/src/ui/control/control.ts +++ b/src/ui/control/control.ts @@ -4,7 +4,7 @@ import type {Map} from '../map'; * A position defintion for the control to be placed, can be in one of the corners of the map. * When two or more controls are places in the same location they are stacked toward the center of the map. */ -export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; +export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'map-container'; /** * Interface for interactive controls added to the map. This is a diff --git a/src/ui/control/cooperative_gesture_contol.ts b/src/ui/control/cooperative_gesture_contol.ts index c7b3666cf4..df7c5291f0 100644 --- a/src/ui/control/cooperative_gesture_contol.ts +++ b/src/ui/control/cooperative_gesture_contol.ts @@ -48,7 +48,7 @@ export class CooperativeGestureControl implements IControl { } getDefaultPosition(): ControlPosition { - return 'top-left'; + return 'map-container'; } /** {@inheritDoc IControl.onAdd} */ @@ -77,27 +77,36 @@ export class CooperativeGestureControl implements IControl { return this._container; } + // /** {@inheritDoc IControl.onRemove} */ + // onRemove() { + // DOM.remove(this._container); + // if (this._map) { + // const mapCanvasContainer = this._map.getCanvasContainer(); + // this._map.off('wheel', this._cooperativeGesturesOnWheel); + // this._map.off('touchmove', this._cooperativeGesturesOnTouch); + // mapCanvasContainer.classList.remove('maplibregl-cooperative-gestures'); + // this._map = undefined; + // } + // } /** {@inheritDoc IControl.onRemove} */ - onRemove() { + onRemove(map: Map) { DOM.remove(this._container); - if (this._map) { - const mapCanvasContainer = this._map.getCanvasContainer(); - this._map.off('wheel', this._cooperativeGesturesOnWheel); - this._map.off('touchmove', this._cooperativeGesturesOnTouch); - mapCanvasContainer.classList.remove('maplibregl-cooperative-gestures'); - this._map = undefined; - } + const mapCanvasContainer = map.getCanvasContainer(); + map.off('wheel', this._cooperativeGesturesOnWheel); + map.off('touchmove', this._cooperativeGesturesOnTouch); + mapCanvasContainer.classList.remove('maplibregl-cooperative-gestures'); + this._map = undefined; } - _cooperativeGesturesOnTouch = (event: TouchEvent) => { - this._onCooperativeGesture(event, false); + _cooperativeGesturesOnTouch = () => { + this._onCooperativeGesture(false); }; _cooperativeGesturesOnWheel = (event: WheelEvent) => { - this._onCooperativeGesture(event, event[this._metaKey]); + this._onCooperativeGesture(event['originalEvent'][this._metaKey]); }; - _onCooperativeGesture(event: any, metaPress) { + _onCooperativeGesture(metaPress:boolean) { if (!metaPress) { // Alert user how to scroll/pan this._container.classList.add('maplibregl-show'); diff --git a/src/ui/handler/scroll_zoom.ts b/src/ui/handler/scroll_zoom.ts index 42bdb9d92d..3d939f80dc 100644 --- a/src/ui/handler/scroll_zoom.ts +++ b/src/ui/handler/scroll_zoom.ts @@ -150,9 +150,9 @@ export class ScrollZoomHandler implements Handler { * ``` */ disable() { + this._map.setCooperativeGestures(false); if (!this.isEnabled()) return; this._enabled = false; - this._map.setCooperativeGestures(null); } wheel(e: WheelEvent) { diff --git a/src/ui/map.test.ts b/src/ui/map.test.ts index d5d90778a5..74fbf597f1 100755 --- a/src/ui/map.test.ts +++ b/src/ui/map.test.ts @@ -1205,7 +1205,7 @@ describe('Map', () => { test('#remove', () => { const map = createMap(); const spyWorkerPoolRelease = jest.spyOn(map.style.dispatcher.workerPool, 'release'); - expect(map.getContainer().childNodes).toHaveLength(2); + expect(map.getContainer().childNodes).toHaveLength(3); map.remove(); expect(spyWorkerPoolRelease).toHaveBeenCalledTimes(1); expect(map.getContainer().childNodes).toHaveLength(0); @@ -2677,6 +2677,12 @@ describe('Map', () => { expect(map.getContainer().querySelector('.maplibregl-cooperative-gesture-screen').getAttribute('aria-hidden')).toBeTruthy(); }); + + test('cooperativeGesture container element is not available when scrollZoom disabled', () => { + const map = createMap({cooperativeGestures: true}); + map.scrollZoom.disable(); + expect(map.getContainer().querySelector('.maplibregl-cooperative-gesture-screen')).toBeFalsy(); + }); }); describe('getCameraTargetElevation', () => { diff --git a/src/ui/map.ts b/src/ui/map.ts index 737883109d..022c05411e 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -638,7 +638,7 @@ export class Map extends Camera { this.handlers = new HandlerManager(this, options as CompleteMapOptions); if (options.cooperativeGestures) { - this.addControl(new CooperativeGestureControl(options.cooperativeGestures)); + this.setCooperativeGestures(options.cooperativeGestures); } const hashName = (typeof options.hash === 'string' && options.hash) || undefined; @@ -2919,8 +2919,8 @@ export class Map extends Camera { const controlContainer = this._controlContainer = DOM.create('div', 'maplibregl-control-container', container); const positions = this._controlPositions = {}; - ['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach((positionName) => { - positions[positionName] = DOM.create('div', `maplibregl-ctrl-${positionName} `, controlContainer); + ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'map-container'].forEach((positionName) => { + positions[positionName] = DOM.create('div', `maplibregl-ctrl-${positionName}`, positionName === 'map-container' ? this._container : controlContainer); }); this._container.addEventListener('scroll', this._onMapScroll, false); @@ -3227,7 +3227,6 @@ export class Map extends Camera { this._canvas.removeEventListener('webglcontextlost', this._contextLost, false); DOM.remove(this._canvasContainer); DOM.remove(this._controlContainer); - if (this._cooperativeGestures) this.removeControl(this._cooperativeGesturesControl); this._container.classList.remove('maplibregl-map'); PerformanceUtils.clearMetrics(); From 841a392cc0378baaf552447eb606c1443c2c6cbe Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Fri, 27 Oct 2023 20:35:03 +0200 Subject: [PATCH 13/14] #2498: fix failing unit test --- src/ui/control/control.ts | 2 +- src/ui/control/cooperative_gesture_contol.ts | 13 +------------ src/ui/map.test.ts | 2 +- src/ui/map.ts | 6 +++--- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/ui/control/control.ts b/src/ui/control/control.ts index cfbbccc4f2..c6e2b57792 100644 --- a/src/ui/control/control.ts +++ b/src/ui/control/control.ts @@ -4,7 +4,7 @@ import type {Map} from '../map'; * A position defintion for the control to be placed, can be in one of the corners of the map. * When two or more controls are places in the same location they are stacked toward the center of the map. */ -export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'map-container'; +export type ControlPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'full'; /** * Interface for interactive controls added to the map. This is a diff --git a/src/ui/control/cooperative_gesture_contol.ts b/src/ui/control/cooperative_gesture_contol.ts index df7c5291f0..04f8dd8b62 100644 --- a/src/ui/control/cooperative_gesture_contol.ts +++ b/src/ui/control/cooperative_gesture_contol.ts @@ -48,7 +48,7 @@ export class CooperativeGestureControl implements IControl { } getDefaultPosition(): ControlPosition { - return 'map-container'; + return 'full'; } /** {@inheritDoc IControl.onAdd} */ @@ -77,17 +77,6 @@ export class CooperativeGestureControl implements IControl { return this._container; } - // /** {@inheritDoc IControl.onRemove} */ - // onRemove() { - // DOM.remove(this._container); - // if (this._map) { - // const mapCanvasContainer = this._map.getCanvasContainer(); - // this._map.off('wheel', this._cooperativeGesturesOnWheel); - // this._map.off('touchmove', this._cooperativeGesturesOnTouch); - // mapCanvasContainer.classList.remove('maplibregl-cooperative-gestures'); - // this._map = undefined; - // } - // } /** {@inheritDoc IControl.onRemove} */ onRemove(map: Map) { DOM.remove(this._container); diff --git a/src/ui/map.test.ts b/src/ui/map.test.ts index 74fbf597f1..43c7bfcb1f 100755 --- a/src/ui/map.test.ts +++ b/src/ui/map.test.ts @@ -1205,7 +1205,7 @@ describe('Map', () => { test('#remove', () => { const map = createMap(); const spyWorkerPoolRelease = jest.spyOn(map.style.dispatcher.workerPool, 'release'); - expect(map.getContainer().childNodes).toHaveLength(3); + expect(map.getContainer().childNodes).toHaveLength(2); map.remove(); expect(spyWorkerPoolRelease).toHaveBeenCalledTimes(1); expect(map.getContainer().childNodes).toHaveLength(0); diff --git a/src/ui/map.ts b/src/ui/map.ts index 022c05411e..b88ef41dda 100644 --- a/src/ui/map.ts +++ b/src/ui/map.ts @@ -732,7 +732,7 @@ export class Map extends Camera { const positionContainer = this._controlPositions[position]; if (position.indexOf('bottom') !== -1) { positionContainer.insertBefore(controlElement, positionContainer.firstChild); - } else { + } else if (position !== 'full') { positionContainer.appendChild(controlElement); } return this; @@ -2919,8 +2919,8 @@ export class Map extends Camera { const controlContainer = this._controlContainer = DOM.create('div', 'maplibregl-control-container', container); const positions = this._controlPositions = {}; - ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'map-container'].forEach((positionName) => { - positions[positionName] = DOM.create('div', `maplibregl-ctrl-${positionName}`, positionName === 'map-container' ? this._container : controlContainer); + ['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach((positionName) => { + positions[positionName] = DOM.create('div', `maplibregl-ctrl-${positionName}`, controlContainer); }); this._container.addEventListener('scroll', this._onMapScroll, false); From 3da57effa8c864fd7cad9682f5a84816eed42f33 Mon Sep 17 00:00:00 2001 From: arekgotfryd Date: Sat, 28 Oct 2023 17:13:15 +0200 Subject: [PATCH 14/14] #2498: Unsafe HTML constructed from library input - fix --- src/ui/control/cooperative_gesture_contol.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/ui/control/cooperative_gesture_contol.ts b/src/ui/control/cooperative_gesture_contol.ts index 04f8dd8b62..eb67bb927d 100644 --- a/src/ui/control/cooperative_gesture_contol.ts +++ b/src/ui/control/cooperative_gesture_contol.ts @@ -52,7 +52,7 @@ export class CooperativeGestureControl implements IControl { } /** {@inheritDoc IControl.onAdd} */ - onAdd(map: Map) { + onAdd(map:Map) { this._map = map; const mapCanvasContainer = this._map.getCanvasContainer(); const cooperativeGestures = this._map.getCooperativeGestures(); @@ -62,10 +62,16 @@ export class CooperativeGestureControl implements IControl { desktopMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.macHelpText ? cooperativeGestures.macHelpText : 'Use ⌘ + scroll to zoom the map'; } const mobileMessage = typeof cooperativeGestures !== 'boolean' && cooperativeGestures.mobileHelpText ? cooperativeGestures.mobileHelpText : 'Use two fingers to move the map'; - this._container.innerHTML = ` -
${desktopMessage}
-
${mobileMessage}
- `; + // Create and append the desktop message div + const desktopDiv = document.createElement('div'); + desktopDiv.className = 'maplibregl-desktop-message'; + desktopDiv.textContent = desktopMessage; + this._container.appendChild(desktopDiv); + // Create and append the mobile message div + const mobileDiv = document.createElement('div'); + mobileDiv.className = 'maplibregl-mobile-message'; + mobileDiv.textContent = mobileMessage; + this._container.appendChild(mobileDiv); // Remove cooperative gesture screen from the accessibility tree since screenreaders cannot interact with the map using gestures this._container.setAttribute('aria-hidden', 'true'); // Add event to canvas container since gesture container is pointer-events: none @@ -73,10 +79,8 @@ export class CooperativeGestureControl implements IControl { this._map.on('touchmove', this._cooperativeGesturesOnTouch); // Add a cooperative gestures class (enable touch-action: pan-x pan-y;) mapCanvasContainer.classList.add('maplibregl-cooperative-gestures'); - return this._container; } - /** {@inheritDoc IControl.onRemove} */ onRemove(map: Map) { DOM.remove(this._container);