diff --git a/library/composables/useMapProvider.js b/library/composables/useMapProvider.js index 26790a2df..c499e1cfe 100644 --- a/library/composables/useMapProvider.js +++ b/library/composables/useMapProvider.js @@ -106,6 +106,36 @@ export function isMapboxMap(map) { * @param {object} map the live map instance * @returns {object|undefined} the engine namespace, or undefined when neither is loaded */ +/** + * The provider NAME that built THIS map: 'mapbox', 'maplibre', or undefined when neither global is + * loaded or `map` is not a map at all. + * + * ★ WHY THIS EXISTS, given engineFor() is right above it. engineFor returns the engine NAMESPACE, + * which is what you want for constructing things (Marker, Popup, a second Map). Two call sites want + * the opposite: a NAME, to put in a diagnostic field and to choose an attribution string. They were + * each doing their own `map instanceof window.maplibregl.Map` sniff, which is the raw-global coupling + * C3 exists to remove — and `resolveMapProvider()` cannot serve them because it reads a CONFIG, not a + * live map, so on a dual-engine page it answers about the wrong thing. + * + * ★ THE AMBIGUOUS CASE IS THE WHOLE REASON THIS RETURNS undefined RATHER THAN A DEFAULT. Both call + * sites tested for MAPLIBRE and fell through to 'mapbox', so a stub, a destroyed map or a page where + * neither global loaded read as 'mapbox'. A rewrite in terms of the existing isMapboxMap() would have + * inverted that — falling through to 'maplibre' — and silently changed what a diagnostic reports and + * which attribution a poster prints. Returning undefined forces each caller to keep its OWN default + * visible at the call site, so the migration cannot quietly move a default. Changing a default is not + * a curation migration. + * + * @param {object} map the live map instance + * @returns {'mapbox'|'maplibre'|undefined} + */ +export function providerFor(map) { + if (typeof window === 'undefined') return undefined + const ml = window.maplibregl, mb = window.mapboxgl + if (ml && ml.Map && map instanceof ml.Map) return 'maplibre' + if (mb && mb.Map && map instanceof mb.Map) return 'mapbox' + return undefined +} + export function engineFor(map) { if (typeof window === 'undefined') return undefined const ml = window.maplibregl, mb = window.mapboxgl diff --git a/plugin-designs/all-people-groups/all-people-groups.vue b/plugin-designs/all-people-groups/all-people-groups.vue index 805464fd5..42b9c9ca8 100644 --- a/plugin-designs/all-people-groups/all-people-groups.vue +++ b/plugin-designs/all-people-groups/all-people-groups.vue @@ -31,7 +31,7 @@ */ import { inject, ref, computed, onMounted, onBeforeUnmount } from 'vue' import { useI18n } from 'vue-i18n' -import { useMapInstance } from '@map/composables/useMapInstance.js' +import { useMapInstance, engineGlobal } from '@map/composables/useMapInstance.js' import { resolveMapProvider, setProjectionOn } from '@map/composables/useMapProvider.js' import { useMapData } from '@map/composables/useMapData.js' import { useShadowStyles } from '@map/composables/useShadowStyles.js' @@ -295,7 +295,9 @@ function addLayer(fc) { const pray = doxaRec && doxaRec.slug ? `${esc(tr('pray'))}` : '' - const NS = mapProvider === 'maplibre' ? window.maplibregl : window.mapboxgl + // C3: engineGlobal() resolves a provider NAME to its namespace and already defaults to Mapbox + // for anything unrecognised, which is exactly what this ternary's else branch did. + const NS = engineGlobal(mapProvider) new NS.Popup({ closeButton: true, maxWidth: '290px' }) .setLngLat(e.lngLat) .setHTML(`