Make a people group sendable, not just findable

Search made a group findable last tick; nothing made it sendable. A colleague could be
pointed at the map but not at the Fulani group you had just spent five minutes locating —
the Share button emitted the same URL no matter what was open.

It now carries the selection: ?code=<iso639-3>&country=<iso3>&name=<people group>, and the
map reopens that group on load, flying to it.

★ KEYED ON code+country+name, NEVER ON THE PIN INDEX. The index is a position in a
generated table and shifts every time the pins are rebuilt — which has happened eight
times this flight. An index-based link would keep working and silently open a DIFFERENT
people group after the next data refresh. A link that rots into a wrong answer is far
worse than one that breaks, and this map's whole discipline is not handing someone the
resources for the wrong people.

The query rides on ShareButton's embedPath rather than teaching that component about
parameters: it has four other consumers and none of them need this. Zero blast radius.

Verified end to end on the served tree, in a FRESH page rather than the one that made the
link: opening German emits
?code=deu&country=BEL&name=German, and loading that URL reopens German (deu) at zoom 4.2.
NEGATIVE CONTROL: ?code=zzq&country=ZZZ&name=Nobody opens no group at all, so the resolver
discriminates rather than falling back to whatever is first.

The repo's own smoke:share-all passes this bundle — share → reopened <gospel-resources-map>,
canvas:y. It reports one failure elsewhere, my-upg-100-list/upg-100-list "no Share button
found", which predates this flight: commit ca4343c "UPG-100 drops its duplicate share" is
an ancestor of my first commit. Not mine, and left alone.
This commit is contained in:
doxa-maps-88655c70 2026-09-24 08:01:05 +00:00
parent 4034fa9d6a
commit b771fa622d
8 changed files with 75 additions and 32 deletions

View file

@ -173,6 +173,49 @@ function setPinFilter(v) {
// SUBSTRING, NOT FUZZY: a fuzzy match over 12,379 rows returns plausible WRONG groups,
// and handing someone the resources for a similarly-named people is the failure this map
// is most careful about everywhere else.
// SHARE A GROUP, NOT JUST THE MAP. Search made a group findable; nothing made it
// sendable — a colleague could be pointed at the map but not at the Fulani group you
// just found. The share URL now carries the selection.
//
// KEYED ON code+country+name, NEVER on the pin INDEX. The index shifts every time the
// pin table is rebuilt, so an index-based link would silently open a DIFFERENT people
// group after the next data refresh — a link that rots into a wrong answer is worse than
// one that breaks. These three are stable identifiers and are matched exactly.
//
// The query rides on embedPath rather than teaching ShareButton about parameters:
// that component has other consumers and none of them need this.
const BASE_EMBED = 'gospel-resources/resources-map/index.html'
const shareEmbedPath = computed(() => {
const g = selectedGroup.value
if (!g || !g.iso639_3) return BASE_EMBED
const p = new URLSearchParams({ code: g.iso639_3, country: g.countries || '', name: g.people_group || '' })
return `${BASE_EMBED}?${p.toString()}`
})
// Reopen what a shared link names. Runs once the pins are in hand, because resolving a
// group needs the table the link refers to.
function openFromUrl() {
let sp
try { sp = new URLSearchParams(window.location.search) } catch { return }
const code = (sp.get('code') || '').trim()
if (!code) return
const country = (sp.get('country') || '').trim()
const name = (sp.get('name') || '').trim()
let best = -1
for (let i = 0; i < pinRows.value.length; i++) {
const r = pinRows.value[i]
if (r[4] !== code) continue
// exact name+country wins; code+country next; code alone last.
if (name && r[0] === name && (!country || byIso.value[r[3]]?.country === country || r[3] === country)) { best = i; break }
if (best < 0) best = i
}
if (best < 0) return
const r = pinRows.value[best]
const map = mapRef.value
if (map) map.flyTo({ center: [r[2], r[1]], zoom: Math.max(map.getZoom(), 4.2), duration: 0 })
openPin(best)
}
const q = ref('')
const matches = computed(() => {
const needle = q.value.trim().toLowerCase()
@ -559,7 +602,7 @@ onMounted(async () => {
// credit + link back is required, and gbOpen is mixed-licence with several
// countries carrying a real attribution requirement (India CC BY 2.5 IN, etc).
addMapAttribution(map, { boundaries: true })
map.once('load', () => { paint(map, adm0); paintPins(map) })
map.once('load', () => { paint(map, adm0); paintPins(map); openFromUrl() })
} catch (e) { err.value = String(e.message || e) }
})
onBeforeUnmount(() => { try { mapRef.value?.remove() } catch (_) {} })
@ -725,7 +768,7 @@ useShadowStyles(
<ZoomOutButton :map="mapRef" :is-dark="isDark" />
<LocationButton :map="mapRef" :is-dark="isDark" />
<FullscreenButton :map-container="mapEl" :is-dark="isDark" />
<ShareButton :is-dark="isDark" :embed-path="'gospel-resources/resources-map/index.html'" />
<ShareButton :is-dark="isDark" :embed-path="shareEmbedPath" />
</MapToolbar>
<div class="gm-legend">

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -26,7 +26,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -29,7 +29,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-resources-map> custom element. -->
<script src="../gospel-resources.js" integrity="sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0" crossorigin="anonymous"></script>
<script src="../gospel-resources.js" integrity="sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -556,7 +556,7 @@
"bundle": "gospel-resources",
"scriptUrl": "./gospel-resources/gospel-resources.js",
"output": "doxa-maps/gospel-resources/gospel-resources.js",
"integrity": "sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0",
"integrity": "sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj",
"elements": [
"gospel-resources-map"
],
@ -572,7 +572,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/charts/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -586,7 +586,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/data-tables/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -600,7 +600,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/resources-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
},
{
@ -614,7 +614,7 @@
"scriptUrl": "./gospel-resources/gospel-resources.js",
"embed": {
"iframe": "<iframe src=\"./gospel-resources/resources-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-RXeoLOQz+sgRrdzIKD/u7lYx2eZnVwRZI3fJi1cyRNv2DoTvUiesaEkvS/rtGRZ0\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-ZCOtE4Phz/kfvSIV412QFIl5Xx9ceLGj+tXY9TmxspkK9U7oEFdRBkbsWN0KhVCj\" crossorigin=\"anonymous\"></script>\n<gospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-resources-map>"
}
}
]