-
Notifications
You must be signed in to change notification settings - Fork 176
fix(swipe): localize the base-layer label in the Layer Swipe panel (#860) #862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -207,6 +207,7 @@ export class MapController { | |
| private fullscreenControl: maplibregl.FullscreenControl | null = null; | ||
| private compassControl: ResetBearingControl | null = null; | ||
| private compassLabel = "Reset pitch & bearing"; | ||
| private backgroundLabel = "Background"; | ||
| private geolocateControl: maplibregl.GeolocateControl | null = null; | ||
| private globeControl: maplibregl.GlobeControl | null = null; | ||
| private terrainControl: maplibregl.TerrainControl | null = null; | ||
|
|
@@ -574,7 +575,7 @@ export class MapController { | |
| this.map?.remove(); | ||
| this.map = null; | ||
| this.styleReady = false; | ||
| this.publishLayerDisplayNames([]); | ||
| this.clearLayerDisplayNames(); | ||
| } | ||
|
|
||
| setStyle(url: string): void { | ||
|
|
@@ -1577,11 +1578,28 @@ export class MapController { | |
| if (typeof window === "undefined") return; | ||
|
|
||
| const labelWindow = window as GeoLibreLayerLabelWindow; | ||
| labelWindow.__GEOLIBRE_LAYER_LABELS__ = Object.fromEntries( | ||
| layers | ||
| labelWindow.__GEOLIBRE_LAYER_LABELS__ = Object.fromEntries([ | ||
| ...layers | ||
| .flatMap((layer) => this.getNamedStyleLayers(layer)) | ||
| .map(({ id, name }) => [id, name]), | ||
| ); | ||
| .map(({ id, name }): [string, string] => [id, name]), | ||
| // The Layer Swipe panel groups all basemap layers under "__basemap__"; | ||
| // publish the translated base-layer label last so this synthetic key | ||
| // always wins over a layer that happens to share the id, matching the | ||
| // sidebar. It is published even with no overlay layers, since the panel | ||
| // always lists the basemap entry. | ||
| ["__basemap__", this.backgroundLabel], | ||
| ]); | ||
|
giswqs marked this conversation as resolved.
|
||
| window.dispatchEvent(new CustomEvent("geolibre-layer-labels-change")); | ||
| } | ||
|
|
||
| /** | ||
| * Clear all published layer display names. Used on teardown so the bridge | ||
| * does not retain stale labels; kept separate from publishLayerDisplayNames, | ||
| * which always re-publishes the basemap entry. | ||
| */ | ||
| private clearLayerDisplayNames(): void { | ||
| if (typeof window === "undefined") return; | ||
| (window as GeoLibreLayerLabelWindow).__GEOLIBRE_LAYER_LABELS__ = {}; | ||
| window.dispatchEvent(new CustomEvent("geolibre-layer-labels-change")); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dispatching This matters only in the reinitialisation path (destroy → new controller created → mapReadyGeneration increments → No code change needed—documenting the trade-off. |
||
| } | ||
|
|
||
|
|
@@ -1663,6 +1681,17 @@ export class MapController { | |
| this.compassControl?.setLabel(label); | ||
| } | ||
|
|
||
| /** | ||
| * Update the label used for the grouped base layer (e.g. after a UI language | ||
| * change). It is published through the layer-display-name bridge so the | ||
| * Layer Swipe panel, which lives outside React, shows the same translated | ||
| * base-layer label as the main layer manager. | ||
| */ | ||
| setBackgroundLabel(label: string): void { | ||
| this.backgroundLabel = label; | ||
| this.publishLayerDisplayNames(this.syncedLayers); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One heads-up: |
||
| } | ||
|
|
||
| private addGeolocateControl(): boolean { | ||
| if ( | ||
| !this.map || | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -842,3 +842,65 @@ describe("MapController geolocate permission-denied recovery", () => { | |||||||||||
| } | ||||||||||||
| })); | ||||||||||||
| }); | ||||||||||||
|
|
||||||||||||
| interface LayerLabelWindow { | ||||||||||||
| __GEOLIBRE_LAYER_LABELS__?: Record<string, string>; | ||||||||||||
| dispatchEvent: (event: unknown) => boolean; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // publishLayerDisplayNames is guarded on `window`, which `node --test` lacks, | ||||||||||||
| // so stub a minimal one for the duration of a test. Dispatched event types are | ||||||||||||
| // recorded so a test can assert the swipe panel's change event actually fires. | ||||||||||||
| function withStubbedLabelWindow( | ||||||||||||
| run: (win: LayerLabelWindow, dispatched: string[]) => void, | ||||||||||||
| ): void { | ||||||||||||
| const globals = globalThis as { window?: LayerLabelWindow }; | ||||||||||||
| const original = globals.window; | ||||||||||||
| const dispatched: string[] = []; | ||||||||||||
| const stub: LayerLabelWindow = { | ||||||||||||
| dispatchEvent: (event: unknown) => { | ||||||||||||
| dispatched.push((event as { type: string }).type); | ||||||||||||
| return true; | ||||||||||||
| }, | ||||||||||||
| }; | ||||||||||||
| globals.window = stub; | ||||||||||||
| try { | ||||||||||||
| run(stub, dispatched); | ||||||||||||
| } finally { | ||||||||||||
| if (original === undefined) delete globals.window; | ||||||||||||
| else globals.window = original; | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| describe("MapController base-layer label", () => { | ||||||||||||
| it("publishes the grouped basemap label so the swipe panel can localize it", () => { | ||||||||||||
| withStubbedLabelWindow((win, dispatched) => { | ||||||||||||
| const controller = createMapController(); | ||||||||||||
|
|
||||||||||||
| // An explicit English push publishes under the "__basemap__" key the | ||||||||||||
| // swipe panel reads, and fires the change event the panel listens for. | ||||||||||||
| controller.setBackgroundLabel("Background"); | ||||||||||||
| assert.equal(win.__GEOLIBRE_LAYER_LABELS__?.__basemap__, "Background"); | ||||||||||||
| assert.deepEqual(dispatched, ["geolibre-layer-labels-change"]); | ||||||||||||
|
|
||||||||||||
| // A language change re-publishes the translated label under the same key | ||||||||||||
| // and fires the event again so the panel re-syncs. | ||||||||||||
| controller.setBackgroundLabel("Hintergrund"); | ||||||||||||
| assert.equal(win.__GEOLIBRE_LAYER_LABELS__?.__basemap__, "Hintergrund"); | ||||||||||||
| assert.equal(dispatched.length, 2); | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor test-quality nit: the second dispatch assertion only checks the count but not the event name. The first check (
Suggested change
Also: the companion "clears published labels on destroy" test ( |
||||||||||||
| }); | ||||||||||||
| }); | ||||||||||||
|
|
||||||||||||
| it("clears published labels on destroy", () => { | ||||||||||||
| withStubbedLabelWindow((win) => { | ||||||||||||
| const controller = createMapController(); | ||||||||||||
| controller.setBackgroundLabel("Background"); | ||||||||||||
| assert.equal(win.__GEOLIBRE_LAYER_LABELS__?.__basemap__, "Background"); | ||||||||||||
|
|
||||||||||||
| // Teardown clears the bridge entirely (including the basemap entry), | ||||||||||||
| // rather than leaving the last label behind. | ||||||||||||
| controller.destroy(); | ||||||||||||
| assert.deepEqual(win.__GEOLIBRE_LAYER_LABELS__, {}); | ||||||||||||
| }); | ||||||||||||
| }); | ||||||||||||
| }); | ||||||||||||
|
giswqs marked this conversation as resolved.
|
||||||||||||
Uh oh!
There was an error while loading. Please reload this page.