Merge the pilot (development ceb7168bf, P1 tab addresses) into the UPG100 combined landing

This commit is contained in:
Doxa Maps 2026-10-03 06:52:42 +00:00
commit 2b1f55e7cf
104 changed files with 999 additions and 281 deletions

View file

@ -237,6 +237,8 @@ and a change here can break other maps.
`import … from '@map/composables/useSharedMapToken.js'`
- **useTextHighlight** — highlightRanges(value, indices) — wrap each matched index range in
`import … from '@map/composables/useTextHighlight.js'`
- **useViewAddress** — useViewAddress.js — the page's ADDRESS for the view a reader is on: which app tab, which view inside it, which
`import … from '@map/composables/useViewAddress.js'`
### Utilities (pure helper functions)

View file

@ -0,0 +1,237 @@
#!/usr/bin/env node
// check:view-address — the page's address (library/composables/useViewAddress.js) and its ONE history write.
// A. the pure helpers: the id whitelist + 64 cap; an unknown or malformed value reads as absent (the default opens);
// the level rule (a tab change drops pane and place, a pane change drops place, unless the change sets them);
// foreign params keep their exact text.
// B. the writes, on a simulated browser history: an 'app' owner pushes once and keeps history.state with `current`
// and the hash; an unchanged address writes nothing; a partner page (no owner) writes nothing; a 'host' owner
// writes nothing and hands the host one dxm-address event; nested elements announce dxm-view; Back/Forward is
// only read, never written.
// C. COEXISTENCE with the filters (useShareableView, which writes through the same commitUrl): a filter write keeps
// tab/pane/place, the hash or the query it does not own, and the router's history.state; a tab/pane/place write
// keeps the filters (query AND hash form); both survive Back and Forward, and re-applying the old tab after Back
// writes nothing, so Forward still exists.
// D. THE CENSUS of history writers, enumerated from the tree: every history.pushState/replaceState call in library/
// and plugin-designs/ is the helper's or a listed writer. A new one fails until it is listed here with its reason.
// --self-test: each poison below must FAIL its arm. Pure node: no Vite, no build, no browser.
import { execFileSync } from 'node:child_process'
import { readFileSync } from 'node:fs'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')
// The history writers that exist today besides the helper, by call count. Adding one means a row here with a reason.
const KNOWN = {
'library/composables/useViewAddress.js': [1, 'THE write (commitUrl)'],
'library/utils/languageRequest.js': [1, '?lang= on a generated page only (MAP_OWNS_PAGE); keeps state and every other param'],
'library/layouts/app-wrapper-material/index.html': [1, "the layout page's own #/<map> hash; a fragment-only URL keeps the query"],
'plugin-designs/gospel-internet/src/useBoard.js': [1, 'its own keys on its own leaves (writeUrl); keeps state, foreign params and the hash'],
'plugin-designs/gospel-resources/data-tables.vue': [1, "clearFilter: replaceState({}, '', pathname) wipes the whole query and hash; reported to its owner"],
'plugin-designs/regions-dashboard/region-dashboards.vue': [2, '#<slug> on its own leaf (URL_SYNC); P2 moves it to `place`'],
}
// SOURCE files only: gates and node scripts may simulate history. A write is `.pushState(` / `.replaceState(` (an aliased
// history included) or a computed `history[… 'pushState' …]`.
const WRITE = /\.(?:push|replace)State\s*\(|\[[^\]\n]*['"](?:push|replace)State['"]/g
function census() {
const out = execFileSync('git', ['grep', '--untracked', '-cE', '(push|replace)State', '--', 'library', 'plugin-designs',
':!*.md', ':!*.mjs', ':!**/scripts/**', ':!**/test/**', ':!**/*.test.*', ':!**/*.spec.*'], { cwd: ROOT, encoding: 'utf8' }).trim()
const counts = {}
for (const line of out.split('\n').filter(Boolean)) {
const i = line.lastIndexOf(':')
const file = line.slice(0, i)
// -c counts LINES; count the calls themselves (a ternary writes twice on one line).
const n = (readFileSync(join(ROOT, file), 'utf8').match(WRITE) || []).length
if (n) counts[file] = n
}
return counts
}
// ── a browser's history, simulated: entries + index, popstate on back/forward, write counters ──────────────────────
function browser(href, state = null) {
const entries = [{ url: new URL(href), state }]
let i = 0
const writes = { push: 0, replace: 0 }
const listeners = new Set()
const loc = {
get href() { return entries[i].url.href },
get pathname() { return entries[i].url.pathname },
get search() { return entries[i].url.search },
get hash() { return entries[i].url.hash },
}
const copy = (s) => (s == null ? s : JSON.parse(JSON.stringify(s)))
const hist = {
get state() { return entries[i].state },
get length() { return entries.length },
pushState(s, _, url) { writes.push++; entries.splice(i + 1); entries.push({ url: new URL(url, entries[i].url), state: copy(s) }); i++ },
replaceState(s, _, url) { writes.replace++; entries[i] = { url: new URL(url, entries[i].url), state: copy(s) } },
back() { if (i > 0) { i--; listeners.forEach((h) => h()) } },
forward() { if (i < entries.length - 1) { i++; listeners.forEach((h) => h()) } },
}
globalThis.location = loc; globalThis.history = hist
globalThis.addEventListener = (t, h) => t === 'popstate' && listeners.add(h)
globalThis.removeEventListener = (t, h) => t === 'popstate' && listeners.delete(h)
const at = () => loc.pathname + loc.search + loc.hash
const q = () => new URLSearchParams(loc.search)
return { loc, hist, writes, at, q, listeners }
}
const unset = () => { for (const k of ['location', 'history', 'addEventListener', 'removeEventListener']) delete globalThis[k] }
async function arms({ va, sv, counts }) {
const fails = []
const eq = (tag, got, want) => { if (JSON.stringify(got) !== JSON.stringify(want)) fails.push(`${tag}: got ${JSON.stringify(got)}, want ${JSON.stringify(want)}`) }
try {
// ── A. pure helpers ──
eq('A: a plain id is kept', va.cleanKey('regions-dashboard'), 'regions-dashboard')
eq('A: a 64-char id is kept', va.cleanKey('a'.repeat(64)), 'a'.repeat(64))
for (const bad of ['a'.repeat(65), '<b>', 'a b', '-lead', '../x', 'x?y', 'x#y', '']) {
if (va.cleanKey(bad) !== '') fails.push(`A: the whitelist lets ${JSON.stringify(bad.slice(0, 20))} through`)
}
eq('A: an unknown or malformed value reads as absent', va.readViewKeys('?tab=a%20b&pane=%E0%A4%A&place=angola&tab=second'), { tab: '', pane: '', place: 'angola' })
eq('A: a tab change drops pane and place', va.viewSearch('?tab=a&pane=b&place=c&lang=ar', { tab: 'd' }), '?tab=d&lang=ar')
eq('A: a pane change drops place, keeps tab', va.viewSearch('?tab=a&pane=b&place=c', { pane: 'e' }), '?tab=a&pane=e')
eq('A: a place change keeps tab and pane', va.viewSearch('?tab=a&pane=b&place=c', { place: 'f' }), '?tab=a&pane=b&place=f')
eq('A: a change that sets the deeper level keeps it', va.viewSearch('?tab=a&pane=b&place=c', { tab: 'd', pane: 'p' }), '?tab=d&pane=p')
eq('A: the same tab changes nothing', va.viewSearch('?tab=a&pane=b&place=c', { tab: 'a' }), '?tab=a&pane=b&place=c')
eq('A: foreign params keep their exact text', va.viewSearch('?lang=ar&access=yes%7Cpartial&q=rice+%26+beans&tab=a', { tab: 'b' }), '?tab=b&lang=ar&access=yes%7Cpartial&q=rice+%26+beans')
eq('A: removing the last key leaves no "?"', va.viewSearch('?tab=a', { tab: '' }), '')
eq('A: urlOwner', ['app', 'host', 'App', true, undefined, 'partner'].map((o) => va.urlOwnerOf({ urlOwner: o })), ['app', 'host', '', '', '', ''])
// ── B. writes ──
{
const b = browser('https://x.test/deep-research?lang=ar#top', { back: '/', current: '/deep-research?lang=ar#top', position: 3 })
const r = va.writeViewKeys({ tab: 'regions' }, { owner: 'app', push: true })
if (r !== 'written' || b.writes.push !== 1) fails.push(`B: an app owner's tab change is not ONE push (${r}, ${b.writes.push} pushes)`)
if (b.at() !== '/deep-research?tab=regions&lang=ar#top') fails.push(`B: the write lost the hash or a foreign param: ${b.at()}`)
const s = b.hist.state || {}
if (s.position !== 3 || s.back !== '/') fails.push(`B: history.state was not kept: ${JSON.stringify(s)}`)
if (s.current !== b.at()) fails.push(`B: history.state.current is not the new URL (${s.current}): a Vue Router host loses the link`)
const r2 = va.writeViewKeys({ tab: 'regions' }, { owner: 'app', push: true })
if (r2 !== 'unchanged' || b.writes.push + b.writes.replace !== 1) fails.push(`B: an unchanged address wrote (${r2})`)
if (va.commitUrl({}) !== false || b.writes.push + b.writes.replace !== 1) fails.push('B: commitUrl wrote an identical URL')
}
{
const b = browser('https://partner.test/page?tab=theirs')
for (const owner of ['', undefined, 'partner']) va.writeViewKeys({ tab: 'regions' }, { owner, push: true })
if (b.writes.push + b.writes.replace) fails.push(`B: a partner page (no owner) was written ${b.writes.push + b.writes.replace}×`)
}
{
const b = browser('https://dx.test/deep-research?lang=ar')
const el = new EventTarget(); const got = []
el.addEventListener(va.ADDRESS_EVENT, (e) => got.push(e))
const r = va.writeViewKeys({ tab: 'posters' }, { owner: 'host', push: true, el })
if (b.writes.push + b.writes.replace) fails.push("B: a 'host' owner wrote history itself (the host's router must)")
if (r !== 'announced' || got.length !== 1) fails.push(`B: a 'host' owner did not hand the host ONE ${va.ADDRESS_EVENT} (${r}, ${got.length})`)
else {
const e = got[0]
if (!e.bubbles || !e.composed) fails.push(`B: ${va.ADDRESS_EVENT} cannot leave a shadow root (bubbles ${e.bubbles}, composed ${e.composed})`)
if (e.detail?.keys?.tab !== 'posters' || e.detail?.push !== true || e.detail?.href !== '/deep-research?tab=posters&lang=ar') fails.push(`B: ${va.ADDRESS_EVENT} detail is wrong: ${JSON.stringify(e.detail)}`)
}
// the host has not navigated yet; once it has, the same choice again must not ask it to navigate twice
b.hist.replaceState(b.hist.state, '', '/deep-research?tab=posters&lang=ar'); b.writes.replace--
const r2 = va.writeViewKeys({ tab: 'posters' }, { owner: 'host', push: true, el })
if (r2 !== 'unchanged' || got.length !== 1) fails.push(`B: a 'host' owner announced an unchanged address (${r2}, ${got.length} events)`)
}
{
browser('https://x.test/p')
const el = new EventTarget(); const got = []
el.addEventListener(va.VIEW_EVENT, (e) => got.push(e))
va.announceView(el, 'pane', 'dashboard')
if (va.announceView(el, 'filters', 'x') !== false) fails.push('B: announceView accepts a key that is not tab/pane/place')
if (got.length !== 1 || !got[0].bubbles || !got[0].composed || got[0].detail?.key !== 'pane' || got[0].detail?.value !== 'dashboard') fails.push(`B: a nested element's ${va.VIEW_EVENT} is wrong or cannot leave its shadow root`)
}
// ── C. coexistence with the filters, and Back/Forward ──
{
const b = browser('https://x.test/board?tab=a&pane=b&place=c#top', { current: '/board?tab=a&pane=b&place=c#top', position: 2 })
sv.writeFilterView({ access_level: 'yes' }, 'rice', { mode: 'query', facetKeys: { access: 'access_level' } })
const q = b.q()
if (q.get('tab') !== 'a' || q.get('pane') !== 'b' || q.get('place') !== 'c') fails.push(`C: a filter write (query) dropped tab/pane/place: ${b.at()}`)
if (q.get('access') !== 'yes' || q.get('q') !== 'rice' || b.loc.hash !== '#top') fails.push(`C: a filter write (query) lost its own params or the hash: ${b.at()}`)
if (b.hist.state?.position !== 2 || b.hist.state?.current !== b.at()) fails.push(`C: a filter write dropped the router's history.state or its current: ${JSON.stringify(b.hist.state)}`)
if (b.writes.push) fails.push('C: a filter write pushed (filters replace)')
}
{
const b = browser('https://x.test/research?tab=a&pane=b')
sv.writeFilterView({ region: 'asia' }, '', {})
if (b.loc.search !== '?tab=a&pane=b' || !b.loc.hash.startsWith('#f=region:asia')) fails.push(`C: a filter write (hash) dropped tab/pane/place: ${b.at()}`)
}
{
const b = browser('https://x.test/board?access=yes&q=rice#f=region:asia')
va.writeViewKeys({ tab: 'map' }, { owner: 'app', push: true })
const q = b.q()
if (q.get('access') !== 'yes' || q.get('q') !== 'rice' || b.loc.hash !== '#f=region:asia') fails.push(`C: a tab write dropped the filters: ${b.at()}`)
va.writeViewKeys({ place: 'angola' }, { owner: 'app', push: true })
if (b.q().get('access') !== 'yes' || b.loc.hash !== '#f=region:asia') fails.push(`C: a place write dropped the filters: ${b.at()}`)
}
{
// A shell with the filters inside: first paint, a filter, a tab change, another filter, then Back and Forward.
// The app re-applies the tab on popstate the way an owner does: it sets its tab, and its tab watcher writes.
const b = browser('https://x.test/deep-research')
const app = { tab: '' }
const setTab = (t, push) => { app.tab = t; va.writeViewKeys({ tab: t }, { owner: 'app', push }) }
const off = va.onAddressChange((keys) => setTab(keys.tab || 'home', true))
setTab('a', false)
sv.writeFilterView({ access_level: 'yes' }, '', { mode: 'query', facetKeys: { access: 'access_level' } })
setTab('b', true)
sv.writeFilterView({ access_level: 'no' }, '', { mode: 'query', facetKeys: { access: 'access_level' } })
const len = b.hist.length; const w = b.writes.push + b.writes.replace
b.hist.back()
if (b.q().get('tab') !== 'a' || b.q().get('access') !== 'yes') fails.push(`C: after Back the entry lost its tab or its filters: ${b.at()}`)
if (app.tab !== 'a') fails.push('C: Back did not re-apply the tab')
if (b.writes.push + b.writes.replace !== w) fails.push('C: re-applying the tab after Back WROTE history (Forward is lost)')
b.hist.forward()
if (b.hist.length !== len || b.q().get('tab') !== 'b' || b.q().get('access') !== 'no') fails.push(`C: after Forward the entry lost its tab or its filters, or Forward was gone: ${b.at()} (${b.hist.length}/${len})`)
off()
if (b.listeners.size) fails.push('C: onAddressChange off() left its popstate listener')
}
} finally { unset() }
// ── D. the census ──
for (const [file, n] of Object.entries(counts)) {
if (!KNOWN[file]) fails.push(`D: a new history writer: ${file} (${n}). Route it through useViewAddress (commitUrl), or list it in KNOWN with its reason`)
else if (KNOWN[file][0] !== n) fails.push(`D: ${file} now has ${n} history writes, the census says ${KNOWN[file][0]}`)
}
for (const file of Object.keys(KNOWN)) if (!counts[file]) fails.push(`D: ${file} is listed as a writer but no longer writes: drop its row`)
return fails
}
const va = await import(join(ROOT, 'library/composables/useViewAddress.js'))
const sv = await import(join(ROOT, 'library/composables/useShareableView.js'))
const counts = census()
const real = { va, sv, counts }
let code = 0
if (process.argv.includes('--self-test')) {
// The old filter write, as it was: its own replaceState(null, …) of the whole URL.
const oldFilterWrite = (fs, term, o = {}) => {
const url = o.mode === 'query' ? sv.serializeQuery(fs, term, location.search, o) + location.hash : location.search + sv.serializeView(fs, term, o)
history.replaceState(null, '', location.pathname + url); return true
}
const poisons = [
['a write that drops history.state.current', { ...real, va: { ...va, writeViewKeys: (c, o) => { const s = va.viewSearch(location.search, c); history[o.push ? 'pushState' : 'replaceState']({ ...history.state }, '', location.pathname + s + location.hash); return 'written' } } }, /^B: history\.state\.current/],
['a write when not the owner', { ...real, va: { ...va, writeViewKeys: (c, o) => va.writeViewKeys(c, { ...o, owner: 'app' }) } }, /^B: a partner page/],
['a tab change that keeps a stale place', { ...real, va: { ...va, viewSearch: (s, c) => { const k = { ...va.readViewKeys(s), ...Object.fromEntries(Object.entries(c).map(([a, b]) => [a, va.cleanKey(b)])) }; const f = s.replace(/^\?/, '').split('&').filter((p) => p && !va.VIEW_KEYS.includes(p.split('=')[0])); const all = [...va.VIEW_KEYS.filter((x) => k[x]).map((x) => `${x}=${k[x]}`), ...f]; return all.length ? '?' + all.join('&') : '' } } }, /^A: a tab change drops pane and place/],
['a whitelist with no length cap', { ...real, va: { ...va, cleanKey: (v) => (/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(String(v ?? '')) ? String(v) : '') } }, /^A: the whitelist lets/],
['a write when the address is unchanged', { ...real, va: { ...va, writeViewKeys: (c, o) => { const s = va.viewSearch(location.search, c); history[o.push ? 'pushState' : 'replaceState']({ ...(history.state || {}), current: location.pathname + s + location.hash }, '', location.pathname + s + location.hash); return 'written' } } }, /^B: an unchanged address wrote|^C: re-applying the tab after Back WROTE/],
["a 'host' owner that writes history itself", { ...real, va: { ...va, writeViewKeys: (c, o) => va.writeViewKeys(c, { ...o, owner: o.owner === 'host' ? 'app' : o.owner }) } }, /^B: a 'host' owner wrote/],
['a dxm-address that cannot leave a shadow root', { ...real, va: { ...va, writeViewKeys: (c, o) => { if (o.owner !== 'host') return va.writeViewKeys(c, o); const s = va.viewSearch(location.search, c); o.el.dispatchEvent(new CustomEvent(va.ADDRESS_EVENT, { bubbles: true, detail: { keys: va.readViewKeys(s), href: location.pathname + s, push: o.push } })); return 'announced' } } }, /^B: dxm-address cannot leave/],
// the three coexistence poisons
['a FILTER write that drops tab/pane/place (no foreign params kept)', { ...real, sv: { ...sv, writeFilterView: (fs, term, o = {}) => va.commitUrl(o.mode === 'query' ? { search: sv.serializeQuery(fs, term, '', o) } : { search: '', hash: sv.serializeView(fs, term, o) }) } }, /^C: a filter write \((query|hash)\) dropped tab\/pane\/place/],
['the old filter write: its own replaceState(null) (the router state is wiped)', { ...real, sv: { ...sv, writeFilterView: oldFilterWrite } }, /^C: a filter write dropped the router's history\.state/],
['a TAB write that drops the filters (foreign params and hash)', { ...real, va: { ...va, writeViewKeys: (c, o) => { if (o.owner !== 'app') return va.writeViewKeys(c, o); const k = va.readViewKeys(va.viewSearch(location.search, c)); const s = va.VIEW_KEYS.filter((x) => k[x]).map((x) => `${x}=${k[x]}`).join('&'); return va.commitUrl({ search: s ? '?' + s : '', hash: '' }, { push: o.push }) ? 'written' : 'unchanged' } } }, /^C: a (tab|place) write dropped the filters/],
['a tab change written as a REPLACE (Back leaves the page)', { ...real, va: { ...va, writeViewKeys: (c, o) => va.writeViewKeys(c, { ...o, push: false }) } }, /^B: an app owner's tab change is not ONE push|^C: after Back/],
['a popstate handler that writes the address', { ...real, va: { ...va, onAddressChange: (cb) => va.onAddressChange((k) => { cb(k); history.pushState(history.state, '', location.href) }) } }, /^C: re-applying the tab after Back WROTE|^C: after Forward/],
// the census
['a new history writer in the tree', { ...real, counts: { ...counts, 'plugin-designs/some-plugin/page.vue': 1 } }, /^D: a new history writer/],
['useShareableView writing history itself again', { ...real, counts: { ...counts, 'library/composables/useShareableView.js': 1 } }, /^D: a new history writer: library\/composables\/useShareableView\.js/],
]
for (const [name, inp, rx] of poisons) {
const f = await arms(inp); const ok = f.some((x) => rx.test(x))
console.log(ok ? `✓ caught: ${name} -> ${f.find((x) => rx.test(x))}` : `✗ MISSED: ${name}${f.length ? ' (failed instead: ' + f[0] + ')' : ''}`)
if (!ok) code = 1
}
} else {
const f = await arms(real)
if (f.length) { f.forEach((x) => console.log('FAIL ' + x)); code = 1 }
else console.log(`PASS check:view-address — the id whitelist and the level rule; one push per tab change with history.state + current kept; nothing written when unchanged, on a partner page, or by a 'host' owner (one dxm-address instead); filters and tab/pane/place keep each other through writes, Back and Forward; ${Object.keys(counts).length} history writers in the tree, all accounted for`)
}
process.exit(code)

View file

@ -925,7 +925,10 @@ function mapPageHtml(opts) {
? `\n <script>window.MAP_APP_API_URL = ${JSON.stringify(apiBaseUrl)};</script>`
: ''
// Bake the QA corner widget onto the host platform's embed surface (opt-out via build-config qaWidget:false).
const pageConfig = DEST_CONFIG.qaWidget ? { ...config, qa: true } : config
// urlOwner 'app' (library/composables/useViewAddress.js): this generated page is OURS, so its shell may write the
// view address (?tab=…) for a reload and a sent link. Only the page's own config gets it, never an embed snippet
// (embedCfg), so a partner's page is never written to; and a FRAMED page drops it at runtime (below).
const pageConfig = { ...(DEST_CONFIG.qaWidget ? { ...config, qa: true } : config), urlOwner: 'app' }
// PROVIDER-AWARE PAGE (see library/composables/useMapProvider.js): a profile or
// instance whose config says provider:'maplibre' gets the MapLibre peer (token-
// free, no Mapbox account) and SKIPS the token ladder entirely — the map mounts
@ -1099,6 +1102,9 @@ ${apiScript}
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = ${JSON.stringify(pageConfig)};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -197,6 +197,16 @@ export function leafRewrite(path, treeName = TREE_NAME) {
return '/__leaf/' + segs.join('/')
}
// urlOwner 'app' (library/composables/useViewAddress.js) for a dev page that is OURS, the rule generate-tree bakes
// into the built leaf: its shell writes ?tab=, so a clicked tab survives a reload and a copied link opens it. A
// FRAMED page drops it: Plugin Studio iframes its map rows from /__leaf/, and a history push from an iframe lands
// in the top page's Back stack. Write the element unowned and put this classic script right after it; it runs
// before the deferred module script upgrades the element. `<` is escaped: profile/instance come from the URL.
export function ownIfTopScript(cfg = {}) {
const owned = JSON.stringify(JSON.stringify({ ...cfg, urlOwner: 'app' })).replace(/</g, '\\u003c')
return `<script>try{if(window.self===window.top)document.currentScript.previousElementSibling.setAttribute('profile-config',${owned})}catch(e){}</script>`
}
export function autoSpaDevPlugin(token = '') {
// One generator for both galleries (internal/generate-gallery.mjs), driven by the same build
// config the built page bakes. What dev changes: the model comes from discovery, the live
@ -365,7 +375,8 @@ export function autoSpaDevPlugin(token = '') {
// renders the SAME view here as in production rather than the bundle's default.
// assetsBase too, as the built leaf's BASE_CONFIG carries it ("../../assets" there; root-absolute
// here, because a /__leaf/ URL's depth differs from the tree's and the pool is served at /assets).
const pc = JSON.stringify(instance ? { profile, instanceId: instance, assetsBase: '/assets' } : { profile, assetsBase: '/assets' })
const leafPc = instance ? { profile, instanceId: instance, assetsBase: '/assets' } : { profile, assetsBase: '/assets' }
const pc = JSON.stringify(leafPc)
// The composition tier of THIS profile, read from the same discovery the gallery uses.
// `nested-elements-mfe` (cap-4) is the StackLayout scroll-stack tier — see the style note
// below. An unknown profile falls through to the fixed-viewport leaf, the safe default.
@ -430,6 +441,7 @@ export function autoSpaDevPlugin(token = '') {
// live 19-bundle tree. Passing the base makes a nested shell see exactly what the top
// level sees. Elements that ignore tree-base simply drop an unknown attribute.
`<${tag} tree-base="/__plugin-gallery" profile-config='${pc}'></${tag}>`,
ownIfTopScript(leafPc),
`<script type="module" src="/plugin-designs/${bundle}/index.js"></script>`,
'</body></html>',
].filter(Boolean).join('\n'))
@ -499,6 +511,7 @@ export function autoSpaDevPlugin(token = '') {
// manifest-shaped model the built tree bakes (19 bundles / 30 profiles), so pointing the
// studio at it gives dev the same tab list production has.
'<plugin-studio tree-base="/__plugin-gallery"></plugin-studio>',
ownIfTopScript(),
'<script type="module" src="/plugin-designs/plugin-studio/index.js"></script>',
'</body></html>',
].filter(Boolean).join('\n'))

View file

@ -44,6 +44,7 @@
* stays unconditional, because restoring a link someone sent must work everywhere.
*/
import { watch, onMounted } from 'vue'
import { commitUrl } from './useViewAddress.js'
const slugify = (s) => String(s ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40)
// Minimal escaping, maximal legibility: reserve our delimiters + %, keep spaces as `+` (the
@ -177,17 +178,25 @@ export function parseQuery(search, facetKeys = [], { searchKey = 'q' } = {}) {
return out
}
/**
* The filter write. It goes through useViewAddress's commitUrl, the page's ONE history write, so it can never undo
* a tab/pane/place write and keeps history.state (+ `current`) on a Vue Router host. It used to write
* replaceState(null, …) itself, which wiped the router's state there. Query mode replaces only its own params; hash
* mode replaces only the hash. Everything else in the URL stays. Exported so check:view-address drives this exact
* write. Returns whether it wrote.
*/
export function writeFilterView(filterSet, searchTerm, options = {}) {
try {
if (typeof location === 'undefined') return false
return options.mode === 'query'
? commitUrl({ search: serializeQuery(filterSet, searchTerm, location.search, options) })
: commitUrl({ hash: serializeView(filterSet, searchTerm, options) })
} catch (_) { return false }
}
export function useShareableView(bus, options = {}) {
const { mode = 'hash', write: shouldWrite = true, facetKeys } = options
const push = () => {
try {
if (typeof location === 'undefined' || !shouldWrite) return
const url = mode === 'query'
? serializeQuery(bus.filterSet, bus.searchTerm?.value, location.search, { ...options, facetKeys }) + location.hash
: location.search + serializeView(bus.filterSet, bus.searchTerm?.value, options)
history.replaceState(null, '', location.pathname + url)
} catch (_) { /* sandboxed */ }
}
const push = () => { if (shouldWrite) writeFilterView(bus.filterSet, bus.searchTerm?.value, options) }
watch(() => ({ ...bus.filterSet, __q: bus.searchTerm?.value }), push, { deep: true })
onMounted(() => {
try {

View file

@ -0,0 +1,111 @@
/**
* useViewAddress.js — the page's ADDRESS for the view a reader is on: which app tab, which view inside it, which
* place. One shared vocabulary and ONE history writer, so a tab, a view or a selection can be reloaded and sent as a
* link on every host, while a partner's page is never written to.
*
* ★ THE SCHEME (query, not hash: a hash is a host page's anchor, and filters already live there).
* ?tab=<app tab>&pane=<view inside the tab>&place=<selection>
* Levels: changing `tab` drops `pane` and `place`; changing `pane` drops `place`. Every other parameter (a host's
* own, the filters useShareableView writes) and the hash are kept as they are. A value that is not a plain id
* (letters, digits, `-`, `_`, at most 64) reads as absent, so a stale or hand-edited link falls back to the default.
* `pane`, not `view`: `?view=` is already published by four of our own pages (gospel-internet's board/map, Gospel
* Resources' map ?view=zero, pplr-data-maps and upg-neighbor lenses), and one of them sits inside a shell tab.
*
* ★ ONE WRITER PER PAGE. Only the OUTERMOST element that owns the address writes it; profile-config `urlOwner` says
* who that is:
* 'app' our own pages (a generated leaf, Plugin Studio): writeViewKeys() writes history itself;
* 'host' a host with its own router (DX Life): writeViewKeys() dispatches ADDRESS_EVENT and the HOST writes;
* absent a partner's page: nothing is written; links are still READ (readViewKeys works everywhere).
* A nested element never writes: it announces its choice upward (announceView) and the owner records it.
*
* ★ THE ONE HISTORY WRITE: commitUrl(). The view keys and useShareableView's filters both write through it, so those
* two can never undo each other. The tree's other history writers are pinned by check:view-address's census and move
* onto commitUrl in later phases. On a push, commitUrl copies the previous entry's state (Vue Router's `position` and
* `back` included). That is correct for a replace. A Vue Router page is a 'host' owner, so its router does its own
* pushes. It keeps `history.state` and sets its `current` to the
* new URL. MEASURED on a Vue Router host (2026-09-30): a pushState that drops Router's state fields makes the next
* in-app navigation rewrite the entry back to Router's last-known URL, and the link is lost. It writes nothing when
* the URL would not change. A user's tab/pane/place change is a push (one Back step); first paint, link
* normalisation and filters are a replace.
*
* Pure helpers, no dependency. Safe under node and in a sandboxed frame (every access is guarded).
*/
export const VIEW_KEYS = ['tab', 'pane', 'place']
/** nested element → the address owner: { key, value, push }. Composed + bubbling, so it leaves shadow roots. */
export const VIEW_EVENT = 'dxm-view'
/** an owner with urlOwner 'host' → the host's router: { keys, href, push }; the host does router[push ? 'push' : 'replace'](href). */
export const ADDRESS_EVENT = 'dxm-address'
/** A plain id (letters, digits, `-`, `_`, at most 64), or '' for anything else. */
export const cleanKey = (v) => { const s = String(v ?? '').trim(); return /^[A-Za-z0-9][\w-]{0,63}$/.test(s) ? s : '' }
/** { tab, pane, place } from a search string; '' for a key that is absent or not a plain id. The FIRST of a repeated
* key decides, as URLSearchParams.get does for the shells that already read ?tab=; a malformed escape reads as absent. */
export function readViewKeys(search) {
const q = new URLSearchParams(search || '')
return Object.fromEntries(VIEW_KEYS.map((k) => [k, cleanKey(q.get(k))]))
}
// Bubbling + composed, so the event leaves every shadow root on its way to the owner or the host.
const send = (el, type, detail) => !!el?.dispatchEvent && (el.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail })), true)
/**
* The search string after `changes` ({ tab?, pane?, place? }; '' or null removes a key), with the level rule: a
* changed level drops the deeper levels that `changes` does not set itself. Foreign parameters keep their place and
* their exact text (useShareableView's legible `,` and unicode are not re-encoded). Returns '' or '?…'.
*/
export function viewSearch(search, changes = {}) {
const next = readViewKeys(search)
VIEW_KEYS.forEach((k, level) => {
if (!(k in changes) || cleanKey(changes[k]) === next[k]) return
next[k] = cleanKey(changes[k])
VIEW_KEYS.slice(level + 1).forEach((d) => { if (!(d in changes)) next[d] = '' })
})
const all = VIEW_KEYS.filter((k) => next[k]).map((k) => k + '=' + next[k])
.concat((search || '').replace(/^\?/, '').split('&').filter((p) => p && !VIEW_KEYS.includes(p.split('=')[0])))
return all.length ? '?' + all.join('&') : ''
}
/**
* THE one write to the address bar. `search` ('' or '?…') and `hash` ('' or '#…') default to the current ones, which
* is the shape viewSearch, serializeQuery and serializeView all return. Keeps history.state and sets its
* `current` (Vue Router's field) to the new URL. Returns true when it wrote; false when the URL was already that, or
* the page cannot be written (no history, a sandbox).
*/
export function commitUrl({ search, hash } = {}, { push = false } = {}) {
try {
const p = location.pathname
const url = p + (search ?? location.search) + (hash ?? location.hash)
if (url === p + location.search + location.hash) return false
history[push ? 'pushState' : 'replaceState']({ ...(history.state || {}), current: url }, '', url)
return true
} catch (_) { return false }
}
/** 'app' | 'host' | '' from a profile-config. Anything else is '' (a partner's page: read only). */
export const urlOwnerOf = (cfg) => (cfg && (cfg.urlOwner === 'app' || cfg.urlOwner === 'host') ? cfg.urlOwner : '')
/**
* The owner's write for tab/pane/place. owner 'app': commitUrl (push for a reader's choice). owner 'host': dispatch
* ADDRESS_EVENT from `el` for the host's router; nothing is written here. Anything else: nothing. Returns what it did:
* 'written' | 'announced' | 'unchanged' | 'none'.
*/
export function writeViewKeys(changes, { owner = '', push = true, el = null } = {}) {
if ((owner !== 'app' && owner !== 'host') || !globalThis.location) return 'none'
const search = viewSearch(location.search, changes)
if (search === location.search) return 'unchanged'
if (owner === 'app') return commitUrl({ search }, { push }) ? 'written' : 'unchanged'
return send(el, ADDRESS_EVENT, { keys: readViewKeys(search), href: location.pathname + search + location.hash, push }) ? 'announced' : 'none'
}
/** A nested element reports a reader's choice to whoever owns the address (it never writes itself). */
export const announceView = (el, key, value, { push = true } = {}) =>
VIEW_KEYS.includes(key) && send(el, VIEW_EVENT, { key, value: cleanKey(value), push })
/** Back / Forward: cb(readViewKeys(location.search)). Re-apply state only; never write from here. Returns off(). */
export function onAddressChange(cb) {
const h = () => cb(readViewKeys(location.search))
globalThis.addEventListener?.('popstate', h)
return () => globalThis.removeEventListener?.('popstate', h)
}

View file

@ -359,7 +359,7 @@
"fix:sri": "node internal/fix-sri.mjs",
"gallery": "node internal/generate-gallery.mjs",
"gates:post": "node internal/run-parallel.mjs --label=post -- check:capability-derived check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:zoning-declared check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:script-flags check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:pin-dim-slider check:legend-source check:clustering-modes check:composite-embed-knobs check:composite-locale-leaks check:linked-vocabulary check:wp-embed check:dashboard-geocoder-provider check:leaf-engine-per-provider check:auto-engine check:engine-contract check:map-props-unit check:composites-mount check:composite-interop check:no-free-identifiers check:map-fly-reduced-motion check:mst-clustering check:list-prop-unit check:profiles-mount check:cdn-pins check:no-eval check:popup-escaping check:i18n-treeshake check:pinned-umd check:one-palette:self-test check:no-cross-plugin-imports check:no-cross-plugin-imports:self-test check:map-attribution check:studio-rail check:approx-pin-note check:embedder-keys check:provider-for check:legend-logical-insets check:legend-logical-insets:self-test check:optional-t-equivalence check:text-highlight check:religion-label-not-value check:i18n-stopped-scope check:no-silent-engine check:no-silent-engine:self-test check:regions-uses-library check:shadow-css-parses check:square-map-controls check:preset-config-merge check:instance-config-keys check:frozen-labels check:plural-forms check:region-fill-repaint check:region-paint-single-source check:poster-print-fallback check:posters-exportable check:country-names check:reduced-motion check:no-dead-library check:universal-props check:readme-size check:tree-relative check:leaf-hints check:snippet-engine check:snippet-engine:self-test check:embed-base check:link-coverage check:no-public-binds check:shared-reached check:tree-weight check:no-fleet-names:self-test check:pin-hint-floor:self-test check:poster-sizes:self-test check:shell-header:self-test check:preview-flag-dev-only:self-test check:poster-type-registry:self-test check:host-floor:self-test check:phone-print-keep:self-test check:pinned-fetch-fresh:self-test",
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts check:setup-order check:package-json-unique-keys check:no-repo-pb-hooks check:no-credentials-omit check:no-credentials-omit:self-test check:shadow-reduced-motion check:poster-action-print check:targets check:targets:self-test check:browser-gates-guarded check:pin-selection check:facet-shape check:hardcoded-english:self-test check:list-selection check:selector-fields check:upg-zone-joins check:gospel-set-charts check:gospel-set-fit check:describe-group check:one-scroll-container check:packet-charts check:pins-in-state check:fork-leaders check:circular-layout check:composite-token-url check:language-tree-layout check:i18n-keys-exist check:i18n-never-translated check:packet-variants check:profile-table check:element-bootstrap check:embed-url-absolute check:frame-target check:language-tree-model check:map-menu-anchor check:selection-kinds check:tiered-points check:whiteboard-projection check:mercator-slice check:ring-vocabulary check:map-props-unit check:mobile-gating check:provide-shadowing check:legend-top-offset check:cdn-cache check:plural-forms check:select-zone-race check:script-registry check:map-control-overlap check:poster-attribution check:board-map-options check:gospel-whiteboard check:packet-map-missing-loud check:poster-layout-optin check:ported-globals-identical check:ring-bands check:packet-a1-structure check:india-states check:batch-selection-export check:zone-title-tier-a check:evangelical-share check:map-labels check:packet-offline check:help-reachable check:gated-not-in-tree check:window-globals-released check:legend-data-contract check:no-internal-role-nouns check:poster-fetch-guard check:people-group-records check:sentence-slots check:popup-href-escaped check:popup-pan-controls check:country-map-refetch check:pane-config-reforward check:viewport-meta check:viewport-meta:self-test check:label-key-coverage check:poster-browser-equiv check:poster-render-pinned check:country-sheet-one-path check:country-sheet-one-path:self-test check:side-lanes check:side-lanes:self-test check:poster-section check:poster-section:self-test check:posterverse-shelf check:host-locale-fetch check:print-frame-reclaim check:click-sheet check:coverage-consistent:chained check:coverage-consistent:poison check:dashboard-filter-a11y check:filter-multivalue check:hover-channel check:kit-options-reachable check:layout-key-namespaced check:legend-mirrors check:map-unmount-race check:no-conflict-markers check:series-isolation check:snapshot-guard check:stale-sweep-claim check:surfaces-read-the-tier check:translator-contacts check:wall-wysiwyg check:wall-print-watch check:wall-no-bg-photos check:wall-pan check:template-i18n check:list-pattern-doc check:shadow-style-labels-unique check:grid-image-loading check:retry-fetch check:panel-sheets check:poster-wall-host-seams check:poster-sections check:poster-sections:self-test check:poster-design-catalogue check:poster-design-catalogue:self-test check:upg100-zone-copy check:upg100-zone-copy:self-test check:wall-photo-weight check:no-fleet-names check:pin-hint-floor check:poster-sizes check:upg-count check:shell-header check:pg-name-gate check:preview-flag-dev-only check:poster-type-registry check:host-floor check:phone-print-keep check:pinned-fetch-fresh",
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts check:setup-order check:package-json-unique-keys check:no-repo-pb-hooks check:no-credentials-omit check:no-credentials-omit:self-test check:shadow-reduced-motion check:poster-action-print check:targets check:targets:self-test check:browser-gates-guarded check:pin-selection check:facet-shape check:hardcoded-english:self-test check:list-selection check:selector-fields check:upg-zone-joins check:gospel-set-charts check:gospel-set-fit check:describe-group check:one-scroll-container check:packet-charts check:pins-in-state check:fork-leaders check:circular-layout check:composite-token-url check:language-tree-layout check:i18n-keys-exist check:i18n-never-translated check:packet-variants check:profile-table check:element-bootstrap check:embed-url-absolute check:frame-target check:language-tree-model check:map-menu-anchor check:selection-kinds check:tiered-points check:whiteboard-projection check:mercator-slice check:ring-vocabulary check:map-props-unit check:mobile-gating check:provide-shadowing check:legend-top-offset check:cdn-cache check:plural-forms check:select-zone-race check:script-registry check:map-control-overlap check:poster-attribution check:board-map-options check:gospel-whiteboard check:packet-map-missing-loud check:poster-layout-optin check:ported-globals-identical check:ring-bands check:packet-a1-structure check:india-states check:batch-selection-export check:zone-title-tier-a check:evangelical-share check:map-labels check:packet-offline check:help-reachable check:gated-not-in-tree check:window-globals-released check:legend-data-contract check:no-internal-role-nouns check:poster-fetch-guard check:people-group-records check:sentence-slots check:popup-href-escaped check:popup-pan-controls check:country-map-refetch check:pane-config-reforward check:viewport-meta check:viewport-meta:self-test check:label-key-coverage check:poster-browser-equiv check:poster-render-pinned check:country-sheet-one-path check:country-sheet-one-path:self-test check:side-lanes check:side-lanes:self-test check:poster-section check:poster-section:self-test check:posterverse-shelf check:host-locale-fetch check:print-frame-reclaim check:click-sheet check:coverage-consistent:chained check:coverage-consistent:poison check:dashboard-filter-a11y check:filter-multivalue check:hover-channel check:kit-options-reachable check:layout-key-namespaced check:legend-mirrors check:map-unmount-race check:no-conflict-markers check:series-isolation check:snapshot-guard check:stale-sweep-claim check:surfaces-read-the-tier check:translator-contacts check:wall-wysiwyg check:wall-print-watch check:wall-no-bg-photos check:wall-pan check:template-i18n check:list-pattern-doc check:shadow-style-labels-unique check:grid-image-loading check:retry-fetch check:panel-sheets check:poster-wall-host-seams check:poster-sections check:poster-sections:self-test check:poster-design-catalogue check:poster-design-catalogue:self-test check:upg100-zone-copy check:upg100-zone-copy:self-test check:wall-photo-weight check:no-fleet-names check:pin-hint-floor check:poster-sizes check:upg-count check:shell-header check:pg-name-gate check:preview-flag-dev-only check:poster-type-registry check:host-floor check:phone-print-keep check:pinned-fetch-fresh check:view-address check:view-address:self-test",
"gen:iso3-to-alpha2": "node library/scripts/generate-iso3-to-alpha2.mjs",
"internet:adm1": "node plugin-designs/cities-internet/scripts/build-adm1-internet.mjs",
"library-index": "node internal/generate-library-index.mjs",
@ -428,6 +428,8 @@
"check:side-lanes:self-test": "node plugin-designs/country-posters/scripts/check-side-lanes.mjs --self-test",
"check:poster-section": "node plugin-designs/country-posters/scripts/check-poster-section.mjs",
"check:poster-section:self-test": "node plugin-designs/country-posters/scripts/check-poster-section.mjs --self-test",
"check:view-address": "node internal/check-view-address.mjs",
"check:view-address:self-test": "node internal/check-view-address.mjs --self-test",
"check:poster-sections": "node plugin-designs/poster-sections/scripts/check-poster-sections.mjs",
"check:poster-sections:self-test": "node plugin-designs/poster-sections/scripts/check-poster-sections.mjs --self-test",
"gen:poster-sections-presets": "node plugin-designs/poster-sections/scripts/gen-presets.mjs",
@ -719,6 +721,8 @@
"check:side-lanes:self-test": "a poster-render.js copy WITHOUT the lane clamp must make check:side-lanes' crossing arm FAIL on the same seeded data (it does: 36 crossings), so the arm is shown able to fail.",
"check:poster-section": "the reusable poster section (<dxm-poster-section>): the type registry has 'country'; DX Life's /regions slugs (and every other spelling of a region) each show their countries, every country once; a withheld whole-country poster stays withheld through the type; the element's attributes map to its config; PosterSection.vue injects every name its template uses.",
"check:poster-section:self-test": "a registry without 'country', a region key without \"&\" → \"and\", and a section that uses a name it does not inject must each make check:poster-section fail.",
"check:view-address": "the page's address (library/composables/useViewAddress.js: ?tab= &pane= &place=) and its ONE history write, on a simulated browser history: the id whitelist + 64 cap and the level rule; an app owner's tab change is one push that keeps history.state with current (Vue Router's field) and the hash; nothing is written when unchanged, on a partner page (no urlOwner), or by a host owner (it hands the host one composed dxm-address). Coexistence with the filters (useShareableView writes through the same commitUrl): a filter write keeps tab/pane/place, a tab/pane/place write keeps the filters, both survive Back and Forward, and re-applying the tab after Back writes nothing. Plus the census: every history.pushState/replaceState in library/ and plugin-designs/ source is the helper or a listed writer. Pure node, no build.",
"check:view-address:self-test": "14 poisons must each make check:view-address fail: a write without history.state.current, a write when not the owner, a tab change that keeps a stale place, no length cap, a write when unchanged, a host owner writing history, a dxm-address that cannot leave a shadow root, a filter write that drops tab/pane/place, the old replaceState(null) filter write, a tab write that drops the filters, a tab change written as a replace, a popstate handler that writes, a new history writer in the tree, useShareableView writing history itself again.",
"check:poster-sections": "the Poster Sections page (plugin-designs/poster-sections): every panel choice (each region or All regions, each language, open or collapsed, 1-5 per row) builds <dxm-poster-section> tags that the element's own attribute reader turns back into exactly those choices; All regions is one section per region; Copy embed is the bundle script plus those same tags. The presets file holds, per poster type, exactly an all-regions preset plus one per region its adapter's scopes() returns, so a region the data drops (or gains) cannot drift from the presets; a poster type not on the tree has no presets (its pages could show no posters); and the built preset pages are exactly the presets (no stale page).",
"check:poster-sections:self-test": "a tag builder that drops columns, one that drops collapsed, one that repeats a region under All regions, a preset for a region the type does not have, and a built page for a preset that no longer exists must each make check:poster-sections fail.",
"gen:poster-sections-presets": "writes plugin-designs/poster-sections/poster-sections.instances.json from each poster type's own scopes() (all regions + one preset per region, titled by the type's own section title, then configure); the list check:poster-sections holds the file to.",

View file

@ -67,7 +67,7 @@
:header="showHeader"
:groups="navGroups"
:active="activeKey"
@update:active="onSelect">
@update:active="onRailSelect">
<!-- #brand: the DX-Maps logo mark, left of the title (a compass-star glyph, self-drawn SVG — no
external asset, offline/F-Droid safe; the accent green matches the admin shell). -->
@ -216,6 +216,7 @@ import { helpFor } from './src/experimentalHelp.js'
import { TAB_INFO } from './src/tabInfo.js'
import MapInfo from '@map/components/info/MapInfo.vue'
import { loadScriptOnce, whenTagDefined } from '@map/utils/embedScript.js'
import { readViewKeys, writeViewKeys, onAddressChange, urlOwnerOf } from '@map/composables/useViewAddress.js'
// THE HOST PAGE'S LANGUAGE, by the same ladder every nested map already uses (library/i18n
// detectLocale): ?lang= / ?locale= on the page URL, then <html lang>. '' when the page says nothing.
@ -1130,6 +1131,11 @@ export default defineComponent({
// A map's own "?" asks for its help with a composed doxa:help event (library HelpButton).
this._onHostedHelp = (e) => this.onHostedHelp(e)
this.$el.addEventListener('doxa:help', this._onHostedHelp)
// Back / Forward re-open the tab the address names (useViewAddress), and never write. Only where a page OWNS
// its address: on a partner's page a popstate is the partner's own navigation, and re-reading the URL there
// would snap a host's fixed `tab` attribute back to the default. The owner is read per event: a host may set
// profile-config after mount.
this._offAddress = onAddressChange(({ tab }) => { if (urlOwnerOf(this.cfg)) this.openFromAddress(tab) })
},
// Release the media-query listener. This element is a custom element a host can add and REMOVE at
// will (a cap-5 SPA is mounted and unmounted by shells, tabs and the studio), and a live listener
@ -1137,6 +1143,7 @@ export default defineComponent({
beforeUnmount() {
if (this._langObs) { this._langObs.disconnect(); this._langObs = null }
if (this._onHostedHelp) { this.$el.removeEventListener('doxa:help', this._onHostedHelp); this._onHostedHelp = null }
if (this._offAddress) { this._offAddress(); this._offAddress = null }
if (!this._mql || !this._onMedia) return
if (this._mql.removeEventListener) this._mql.removeEventListener('change', this._onMedia)
else if (this._mql.removeListener) this._mql.removeListener(this._onMedia)
@ -1440,10 +1447,11 @@ export default defineComponent({
this._honouredTab = true
},
// The tab a HOST asked to open first: the `tab` attribute, then profile-config.tab, then ?tab= on
// the page URL (so an iframe src or a shared link can deep-link). '' when nobody asked.
// the page URL (so an iframe src or a shared link can deep-link). '' when nobody asked. The URL is read
// through useViewAddress: the first ?tab= wins, and a value that is not a plain id reads as absent.
requestedTab() {
let q = ''
try { q = new URLSearchParams(location.search).get('tab') || '' } catch { /* non-browser */ }
try { q = readViewKeys(location.search).tab } catch { /* non-browser */ }
return String(this.tab || this.cfg.tab || q || '').trim()
},
// The index to open on mount: the requested tab when it exists and is enabled at this width,
@ -1496,6 +1504,26 @@ export default defineComponent({
const i = this.tabs.findIndex(t => t.id === key)
if (i !== -1) this.select(i)
},
// ★ THE PAGE ADDRESS (shareable pages, useViewAddress). A READER's pick in the rail is the one switch that
// writes ?tab=, as a push, so a reload keeps the tab, a sent link opens it, and Back returns to the previous one.
// Who writes is the page's urlOwner: 'app' (our own leaf page) writes history, 'host' (DX Life) gets a
// dxm-address event and its router writes, and a partner's page is never written. Every other switch is not a
// choice and writes nothing: the manifest's re-select, the device fallback, a host's `tab` attribute, Back and
// Forward. Nor is there a first-paint write: a bare URL means the device's default tab, and pinning a phone's
// default into the address would send a desktop reader to it.
onRailSelect(key) {
const before = this.activeKey
this.onSelect(key)
if (this.activeKey !== before) writeViewKeys({ tab: this.activeKey }, { owner: urlOwnerOf(this.cfg), push: true, el: this.$el })
},
// Back / Forward: the tab the address names, else the page's configured first tab (profile-config.tab), else the
// device default. Not the `tab` attribute: a host with a router re-points it from this same popstate, and until
// it does, it still names the tab being left.
openFromAddress(tab) {
const want = tab || String(this.cfg.tab || '').trim()
const i = want ? this.tabs.findIndex(t => t.id === want) : -1
this.select(i >= 0 && !this.isDesktopOnly(want) ? i : this.firstVisibleIndex())
},
// Resolve a tree-relative ref ("./x" / "x") against the tree base. If base is '' we keep it
// relative to THIS document — but this bundle's own folder is <base>/doxa-maps-spa/, so a
// co-located leaf at <base>/big-picture/... is one level UP: prefix '../'.

View file

@ -35,7 +35,9 @@
with no page reload; each map tab loads lazily on first open.</p>
</div>
<div class="frame">
<doxa-maps-spa id="dms" heading="Deep Research"></doxa-maps-spa>
<!-- urlOwner 'app': this page is ours (the dev server serves it), so a tab pick writes ?tab= and a reload or a
sent link opens that tab (useViewAddress). A partner's page leaves it out and is never written. -->
<doxa-maps-spa id="dms" heading="Deep Research" profile-config='{"urlOwner":"app"}'></doxa-maps-spa>
</div>
</div>

View file

@ -35,7 +35,9 @@
real tag; map elements nest as their own SPA. Switch with no page reload.</p>
</div>
<div class="frame">
<plugin-studio id="ps" title="Plugin Studio"></plugin-studio>
<!-- This page is the app, so Studio owns the address: a clicked tab is written to ?tab=,
a reload keeps it and a sent link opens it. The built leaf page bakes the same key. -->
<plugin-studio id="ps" title="Plugin Studio" profile-config='{"urlOwner":"app"}'></plugin-studio>
</div>
</div>

View file

@ -225,6 +225,7 @@ import StudioTree from './src/StudioTree.vue'
import { LANGUAGES, loadLocale, saveLocale, getLanguage, normaliseLocale } from '@map/layouts/app-wrapper-material/languages.js'
import { publishMapToken, clearMapToken } from '@map/composables/useSharedMapToken.js'
import { loadScriptOnce, whenTagDefined } from '@map/utils/embedScript.js'
import { readViewKeys, writeViewKeys, onAddressChange, urlOwnerOf, commitUrl } from '@map/composables/useViewAddress.js'
// The reader's own map token / token-service URL. localStorage only: never written into the build,
// never sent anywhere but Mapbox (the token) or the URL the reader typed (the service).
@ -762,11 +763,20 @@ export default defineComponent({
.catch(() => {})
}
this.loadManifest()
// Back / Forward re-open the tab the address names; they never write (useViewAddress.js says why).
this._offAddress = onAddressChange(({ tab }) => {
const key = this.keyOfTab(tab)
if (key) this.select(key, { fromHistory: true })
else if (this.rows.length) this.select(this.rows[0].key, { fromHistory: true })
})
},
// The corner-widget hosts live on window.__doxaStudioWidgets so a HOT UPDATE remounts Studio onto
// the same hosts and a live widget (Rudder) keeps its state. A real unmount must release them, or
// the hosts and every widget element in them stay pinned on the page after Studio is gone.
beforeUnmount() {
// FIRST, before the hot-update return below: a remounted Studio adds its own listener, and a kept one would
// re-apply every Back twice.
if (this._offAddress) { this._offAddress(); this._offAddress = null }
if (import.meta.hot) return
const W = window.__doxaStudioWidgets
if (W && W.hosts) for (const h of Object.values(W.hosts)) { try { h.remove() } catch (_) {} }
@ -1003,20 +1013,45 @@ export default defineComponent({
// list" instead of a tab. It opens the first tab, remembers in localStorage the tab you were on,
// and a reload goes back to that tab.
//
// 1. the URL hash — an explicit, shareable request always wins over a remembered one
// 2. localStorage — what you were last looking at, so a reload is not a fresh start
// 3. the first row — never leave the pane empty
// 1. ?tab= — the view address (useViewAddress.js): a reload and a SENT link open it
// 2. the URL hash — the old shareable form (#bundle/profile); rewritten to ?tab= on first paint
// 3. localStorage — what you were last looking at, so a reload is not a fresh start
// 4. the first row — never leave the pane empty
//
// The first select() is a REPLACE (first paint); a reader's click is a PUSH (one Back step), written only
// where this page owns its address (urlOwner 'app', baked into our own leaf page; a partner's page and a
// framed leaf only read).
//
// Called once after the manifest lands, so `rows` is populated and every candidate can be
// checked against it. A remembered key whose bundle was renamed or removed simply fails that
// check and falls through to the first row — a stale key must never render an empty pane, which
// is the very state this replaces.
route() {
const first = { firstPaint: true }
const asked = this.keyOfTab(readViewKeys(typeof location !== 'undefined' ? location.search : '').tab)
if (asked) { this.select(asked, first); return }
const h = (typeof location !== 'undefined' && location.hash || '').replace(/^#\/?/, '')
if (h && this.rows.some(r => r.key === h)) { this.select(h); return }
if (h && this.rows.some(r => r.key === h)) {
this.select(h, first)
// The old #bundle/profile link now reads as ?tab=; its hash goes, so the address has ONE form.
if (urlOwnerOf(this.cfg) === 'app') commitUrl({ hash: '' })
return
}
const remembered = this.readLastTab()
if (remembered && this.rows.some(r => r.key === remembered)) { this.select(remembered); return }
if (this.rows.length) this.select(this.rows[0].key)
if (remembered && this.rows.some(r => r.key === remembered)) { this.select(remembered, first); return }
if (this.rows.length) this.select(this.rows[0].key, first)
},
// ★ A ROW'S TAB ID. A row key is "<bundle>/<profile>", and the address takes plain ids only (no "/"), so the tab
// WRITTEN is "<bundle>__<profile>": stable, since a profile name another bundle adopts later cannot make a sent
// link mean a different row. READ: that form, or a bare profile name while it names exactly one row (a typed
// ?tab=poster-styles), else '' (the default tab opens).
tabIdOf(key) { return String(key || '').replace('/', '__') },
keyOfTab(id) {
if (!id) return ''
const full = id.includes('__') ? id.replace('__', '/') : ''
if (full && this.rows.some(r => r.key === full)) return full
const byProfile = this.rows.filter(r => r.key.split('/')[1] === id)
return byProfile.length === 1 ? byProfile[0].key : ''
},
// Storage is keyed per HOST (pathname), because two cap-5 shells served from one origin would
// otherwise fight over a single key and each reload would yank the other's tab.
@ -1034,7 +1069,7 @@ export default defineComponent({
writeLastTab(key) {
try { window.localStorage.setItem(this.storageKey(), key) } catch (_) { /* storage unavailable */ }
},
select(key) {
select(key, { fromHistory = false, firstPaint = false } = {}) {
// ★ BAIL BEFORE TOUCHING STATE if `key` names no real row. A composition-folder's TOP row can be
// a SYNTHETIC head (see compositionTrees) for a composite that cannot list itself as one of its own
// tabs (plugin-studio nesting <plugin-studio> would be infinite regress — same reasoning
@ -1062,6 +1097,8 @@ export default defineComponent({
// Remember it AFTER confirming the row exists, so a bad key is never written back — otherwise
// one stray select() would poison the next reload with a key that fails route()'s check.
this.writeLastTab(key)
// The view address: a reader's choice is a push, the first paint a replace, Back/Forward never writes.
if (!fromHistory) writeViewKeys({ tab: this.tabIdOf(key) }, { owner: urlOwnerOf(this.cfg), push: !firstPaint, el: this.$el })
// A heavy row's slot only exists after the v-if subtree renders, so wait a tick before
// mounting into it — on the first activation the ref is null at this point.
if (!row.mounted) this.$nextTick(() => { if (this.activeKey === row.key) this.mountElement(row) })

View file

@ -15,7 +15,9 @@
<body>
<!-- Capability 5, the app shell: one element, <posterverse-app>, is a vertical-tab rail of every
poster plugin. Each tab loads its plugin's own script lazily on first open. -->
<posterverse-app></posterverse-app>
<!-- This page is our own (the dev server's staging page), so the shell owns the address: the open tab is
written to ?tab=, a reload keeps it and a copied link opens it. -->
<posterverse-app profile-config='{"urlOwner":"app"}'></posterverse-app>
<script type="module" src="./index.js"></script>
</body>
</html>

View file

@ -74,6 +74,7 @@ import BackToTopButton from '@map/components/BackToTopButton.vue'
import ShellLanguageMenu from '@map/components/ShellLanguageMenu.vue'
import { saveLocale } from '@map/layouts/app-wrapper-material/languages.js'
import { loadScriptOnce, whenTagDefined } from '@map/utils/embedScript.js'
import { readViewKeys, writeViewKeys, onAddressChange, urlOwnerOf } from '@map/composables/useViewAddress.js'
import { translate, LOCALES } from './src/strings.js'
import { SECTIONS, TABS, resolveTabs } from './src/tabs.js'
@ -226,11 +227,22 @@ export default defineComponent({
mounted() {
this.watchHostLang()
// Paint the rail at once; the manifest completes the rows in the background and re-drives the mount.
this.select(this.initialIndex())
// First paint is a REPLACE, so a reload or a shared link keeps the tab without adding a Back step. If the
// address names a tab that only arrives with the manifest (a provisional row), write nothing yet: writing
// tab 0 here would overwrite the link, and applyManifest's own first-paint replace writes the honoured tab.
const want = this.requestedTab()
const known = !want || this.tabs.some((t) => t.id === want)
this.select(this.initialIndex(), { firstPaint: true, fromHistory: !known })
// Back / Forward re-apply the tab from the address and never write (writing would lose Forward).
this._offAddress = onAddressChange(({ tab }) => {
const i = this.tabs.findIndex((t) => t.id === tab)
this.select(i >= 0 ? i : 0, { fromHistory: true })
})
this.loadManifest()
},
beforeUnmount() {
if (this._langObs) { this._langObs.disconnect(); this._langObs = null }
if (this._offAddress) { this._offAddress(); this._offAddress = null }
},
methods: {
tr(key, params) { return translate(this.uiLocale, key, params) },
@ -250,8 +262,11 @@ export default defineComponent({
},
requestedTab() {
let q = ''
try { q = new URLSearchParams(location.search).get('tab') || '' } catch { /* non-browser */ }
return String(this.tab || this.cfg.tab || q || '').trim()
try { q = readViewKeys(location.search).tab } catch { /* non-browser */ }
// On a page whose address this shell owns, the URL (a reload, a shared link) beats a baked cfg.tab, or the
// first-paint replace would overwrite the link with the default. Elsewhere the host's config leads.
const order = urlOwnerOf(this.cfg) ? [this.tab, q, this.cfg.tab] : [this.tab, this.cfg.tab, q]
return String(order.find((v) => v) || '').trim()
},
initialIndex() {
const i = this.tabs.findIndex((t) => t.id === this.requestedTab())
@ -306,7 +321,7 @@ export default defineComponent({
const w = !this._honouredTab && want ? this.tabs.findIndex((t) => t.id === want) : -1
const i = this.tabs.findIndex((t) => t.id === activeId)
this._honouredTab = true
this.select(w >= 0 ? w : (i >= 0 ? i : 0))
this.select(w >= 0 ? w : (i >= 0 ? i : 0), { firstPaint: true })
},
onSelect(key) {
const i = this.tabs.findIndex((t) => t.id === key)
@ -322,7 +337,10 @@ export default defineComponent({
if (this.base) return this.base.replace(/\/+$/, '') + '/' + r
return '../' + r
},
select(i) {
// The tab is written to the address by the ONE owner (urlOwner in profile-config: 'app' on our own pages,
// 'host' when a host's router writes, absent on a partner's page = read only). A reader's choice is a push;
// first paint is a replace; Back / Forward never write.
select(i, { fromHistory = false, firstPaint = false } = {}) {
const prevIndex = this.activeIndex
this.activeIndex = i
// Release the outgoing heavy pane first, so at most one live map context exists at a time.
@ -334,6 +352,7 @@ export default defineComponent({
if (!t) return
// Tell the host which plugin is showing (CustomEvent 'tab-change', detail[0] = { id, label }).
if (prevIndex !== i || !this._announced) { this._announced = true; this.$emit('tab-change', { id: t.id, label: this.tabLabel(t) }) }
if (!fromHistory) writeViewKeys({ tab: t.id }, { owner: urlOwnerOf(this.cfg), push: !firstPaint, el: this.$el })
if (!t.scriptUrl) return // applyManifest selects again once the manifest lands
// A heavy tab's slot exists only after its v-if subtree renders, so mount on the next tick.
if (!t.mounted) this.$nextTick(() => { if (this.activeIndex === i) this.mountElement(i) })

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"all-people-groups","dataSource":"pray-tools","instanceId":"all-people-groups-all-people-groups","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"all-people-groups","dataSource":"pray-tools","instanceId":"all-people-groups-all-people-groups","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"bible-posters","dataSource":"pray-tools","instanceId":"bible-posters-bible-posters","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"bible-posters","dataSource":"pray-tools","instanceId":"bible-posters-bible-posters","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -89,7 +89,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"big-picture","provider":"maplibre","instanceId":"bp-big-picture"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"big-picture","provider":"maplibre","instanceId":"bp-big-picture","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -89,7 +89,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"big-picture","provider":"maplibre","instanceId":"bp-big-picture-frontier","accent":"#22d3ee","title":"Big Picture — Frontier Focus"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"big-picture","provider":"maplibre","instanceId":"bp-big-picture-frontier","accent":"#22d3ee","title":"Big Picture — Frontier Focus","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -89,7 +89,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"big-picture","dataSource":"pray-tools","instanceId":"big-picture-big-picture","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"big-picture","dataSource":"pray-tools","instanceId":"big-picture-big-picture","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"bless-india-posters","dataSource":"pray-tools","instanceId":"bless-india-posters-bless-india-posters","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"bless-india-posters","dataSource":"pray-tools","instanceId":"bless-india-posters-bless-india-posters","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"connectivity-list","dataSource":"pray-tools","instanceId":"cities-internet-connectivity-list","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"connectivity-list","dataSource":"pray-tools","instanceId":"cities-internet-connectivity-list","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"connectivity-map","dataSource":"pray-tools","instanceId":"cities-internet-connectivity-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"connectivity-map","dataSource":"pray-tools","instanceId":"cities-internet-connectivity-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"data-tables","dataSource":"pray-tools","instanceId":"cities-internet-data-tables","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"data-tables","dataSource":"pray-tools","instanceId":"cities-internet-data-tables","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"country-map","dataSource":"pray-tools","instanceId":"country-map-country-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"country-map","dataSource":"pray-tools","instanceId":"country-map-country-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"countries-map","dataSource":"pray-tools","instanceId":"country-posters-countries-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"countries-map","dataSource":"pray-tools","instanceId":"country-posters-countries-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"country-poster-wall","dataSource":"pray-tools","instanceId":"country-posters-country-poster-wall","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"country-poster-wall","dataSource":"pray-tools","instanceId":"country-posters-country-poster-wall","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -98,7 +98,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"country-posters-mfe","dataSource":"pray-tools","instanceId":"country-posters-country-posters-mfe","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"country-posters-mfe","dataSource":"pray-tools","instanceId":"country-posters-country-posters-mfe","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"poster-section","dataSource":"pray-tools","instanceId":"country-posters-poster-section","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"poster-section","dataSource":"pray-tools","instanceId":"country-posters-poster-section","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

File diff suppressed because one or more lines are too long

View file

@ -82,7 +82,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../../dashboard-plus-grid.js" integrity="sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6" crossorigin="anonymous"></script>
<script src="../../dashboard-plus-grid.js" integrity="sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -98,7 +98,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","mobile":"desktop-only","mobileLabel":"Dashboard + Grid","profile":"dashboard-plus-grid"};
var BASE_CONFIG = {"assetsBase":"../../../assets","mobile":"desktop-only","mobileLabel":"Dashboard + Grid","profile":"dashboard-plus-grid","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -82,7 +82,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <dashboard-plus-grid> custom element. -->
<script src="../dashboard-plus-grid.js" integrity="sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6" crossorigin="anonymous"></script>
<script src="../dashboard-plus-grid.js" integrity="sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -98,7 +98,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"mobile":"desktop-only","mobileLabel":"Dashboard + Grid","profile":"dashboard-plus-grid","dataSource":"pray-tools","instanceId":"dashboard-plus-grid-dashboard-plus-grid","assetsBase":"../../assets"};
var BASE_CONFIG = {"mobile":"desktop-only","mobileLabel":"Dashboard + Grid","profile":"dashboard-plus-grid","dataSource":"pray-tools","instanceId":"dashboard-plus-grid-dashboard-plus-grid","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"demo-map","dataSource":"pray-tools","instanceId":"demo-map-demo-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"demo-map","dataSource":"pray-tools","instanceId":"demo-map-demo-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -88,7 +88,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"demo-map","provider":"maplibre","instanceId":"demo-maplibre"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"demo-map","provider":"maplibre","instanceId":"demo-maplibre","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
<script src="../../doxa-maps-spa.js" integrity="sha384-TB7DtATxmWQAqr62j7QJmMjxBfiSysTZiUUxP0Su9xh9JlNO0YvFEafCKinjqd3W" crossorigin="anonymous"></script>
<script src="../../doxa-maps-spa.js" integrity="sha384-JbdbnT273exxkEbpgtOE3DxfYeQ1iPRockZeONzgkP1TJ3dITNCl4yRJ5KMXiXQb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-maps-spa","provider":"maplibre","instanceId":"doxa-maps-spa-app","title":"Deep Research"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-maps-spa","provider":"maplibre","instanceId":"doxa-maps-spa-app","title":"Deep Research","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
<script src="../doxa-maps-spa.js" integrity="sha384-TB7DtATxmWQAqr62j7QJmMjxBfiSysTZiUUxP0Su9xh9JlNO0YvFEafCKinjqd3W" crossorigin="anonymous"></script>
<script src="../doxa-maps-spa.js" integrity="sha384-JbdbnT273exxkEbpgtOE3DxfYeQ1iPRockZeONzgkP1TJ3dITNCl4yRJ5KMXiXQb" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"doxa-maps-spa","dataSource":"pray-tools","instanceId":"doxa-maps-spa-doxa-maps-spa","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"doxa-maps-spa","dataSource":"pray-tools","instanceId":"doxa-maps-spa-doxa-maps-spa","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -410,7 +410,7 @@
"bundle": "dashboard-plus-grid",
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"output": "dx-maps/dashboard-plus-grid/dashboard-plus-grid.js",
"integrity": "sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6",
"integrity": "sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O",
"elements": [
"dashboard-plus-grid"
],
@ -434,8 +434,8 @@
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"embed": {
"iframe": "<iframe src=\"./dashboard-plus-grid/dashboard-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
},
"instances": [
{
@ -505,7 +505,7 @@
"bundle": "doxa-maps-spa",
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"output": "dx-maps/doxa-maps-spa/doxa-maps-spa.js",
"integrity": "sha384-TB7DtATxmWQAqr62j7QJmMjxBfiSysTZiUUxP0Su9xh9JlNO0YvFEafCKinjqd3W",
"integrity": "sha384-JbdbnT273exxkEbpgtOE3DxfYeQ1iPRockZeONzgkP1TJ3dITNCl4yRJ5KMXiXQb",
"elements": [
"doxa-maps-spa"
],
@ -535,7 +535,7 @@
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"embed": {
"iframe": "<iframe src=\"./doxa-maps-spa/doxa-maps-spa/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=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-TB7DtATxmWQAqr62j7QJmMjxBfiSysTZiUUxP0Su9xh9JlNO0YvFEafCKinjqd3W\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-JbdbnT273exxkEbpgtOE3DxfYeQ1iPRockZeONzgkP1TJ3dITNCl4yRJ5KMXiXQb\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
},
"instances": [
{
@ -798,7 +798,7 @@
"bundle": "gospel-internet",
"scriptUrl": "./gospel-internet/gospel-internet.js",
"output": "dx-maps/gospel-internet/gospel-internet.js",
"integrity": "sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0",
"integrity": "sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL",
"elements": [
"gospel-internet-board"
],
@ -819,8 +819,8 @@
"scriptUrl": "./gospel-internet/gospel-internet.js",
"embed": {
"iframe": "<iframe src=\"./gospel-internet/board/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
},
"instances": [
{
@ -1219,7 +1219,7 @@
"bundle": "plugin-studio",
"scriptUrl": "./plugin-studio/plugin-studio.js",
"output": "dx-maps/plugin-studio/plugin-studio.js",
"integrity": "sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE",
"integrity": "sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz",
"elements": [
"plugin-studio"
],
@ -1250,7 +1250,7 @@
"scriptUrl": "./plugin-studio/plugin-studio.js",
"embed": {
"iframe": "<iframe src=\"./plugin-studio/plugin-studio/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=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
},
"instances": [
{
@ -1505,7 +1505,7 @@
"bundle": "posterverse",
"scriptUrl": "./posterverse/posterverse.js",
"output": "dx-maps/posterverse/posterverse.js",
"integrity": "sha384-UNJXfmuXx36JrGNHayoe7QpSEFG0cri9uRl2nJlXLJWBBWrYAn48OOzilxFVJZNu",
"integrity": "sha384-1jvCHQrT11Mixml/KvdnT44djTWvIe6TjNk2vU66hwtF4mefgVCSIRhMwXukYAqZ",
"elements": [
"posterverse-app"
],
@ -1532,7 +1532,7 @@
"scriptUrl": "./posterverse/posterverse.js",
"embed": {
"iframe": "<iframe src=\"./posterverse/posterverse/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=\"./posterverse/posterverse.js\" integrity=\"sha384-UNJXfmuXx36JrGNHayoe7QpSEFG0cri9uRl2nJlXLJWBBWrYAn48OOzilxFVJZNu\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<posterverse-app profile-config='{\"profile\":\"posterverse\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></posterverse-app>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./posterverse/posterverse.js\" integrity=\"sha384-1jvCHQrT11Mixml/KvdnT44djTWvIe6TjNk2vU66hwtF4mefgVCSIRhMwXukYAqZ\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<posterverse-app profile-config='{\"profile\":\"posterverse\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></posterverse-app>"
},
"instances": [
{
@ -1683,7 +1683,7 @@
"bundle": "research-dashboard",
"scriptUrl": "./research-dashboard/research-dashboard.js",
"output": "dx-maps/research-dashboard/research-dashboard.js",
"integrity": "sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl",
"integrity": "sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0",
"elements": [
"research-dashboard-map"
],
@ -1702,8 +1702,8 @@
"scriptUrl": "./research-dashboard/research-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./research-dashboard/research-dashboard/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
},
"bundle": "research-dashboard"
}

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"research-map","dataSource":"pray-tools","instanceId":"doxa-research-map-research-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"research-map","dataSource":"pray-tools","instanceId":"doxa-research-map-research-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -88,7 +88,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"research-map","provider":"maplibre","instanceId":"research-map-maplibre"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"research-map","provider":"maplibre","instanceId":"research-map-maplibre","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-simple-map","instanceId":"embed-adoption","dataSource":"pray-tools","tabs":[{"id":"adoption","colorStrategy":"adoption","legend":"adoption","popup":"adoption"}]};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-simple-map","instanceId":"embed-adoption","dataSource":"pray-tools","tabs":[{"id":"adoption","colorStrategy":"adoption","legend":"adoption","popup":"adoption"}],"urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-simple-map","instanceId":"embed-engagement","dataSource":"pray-tools","tabs":[{"id":"engagement","colorStrategy":"engagement","legend":"engagement","popup":"engagement"}]};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-simple-map","instanceId":"embed-engagement","dataSource":"pray-tools","tabs":[{"id":"engagement","colorStrategy":"engagement","legend":"engagement","popup":"engagement"}],"urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"doxa-simple-map","dataSource":"pray-tools","instanceId":"doxa-simple-map-doxa-simple-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"doxa-simple-map","dataSource":"pray-tools","instanceId":"doxa-simple-map-doxa-simple-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-simple-map","instanceId":"embed-prayer","dataSource":"pray-tools","tabs":[{"id":"prayer","colorStrategy":"prayer","legend":"prayer","popup":"prayer"}]};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-simple-map","instanceId":"embed-prayer","dataSource":"pray-tools","tabs":[{"id":"prayer","colorStrategy":"prayer","legend":"prayer","popup":"prayer"}],"urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-vision-card","provider":"maplibre","instanceId":"vision-card-default"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-vision-card","provider":"maplibre","instanceId":"vision-card-default","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-vision-card","provider":"maplibre","instanceId":"vision-card-frontier","accent":"#22d3ee","title":"The last frontier of the gospel.","tagline":"Frontier people groups: fewer than one person in a thousand is an evangelical believer."};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"doxa-vision-card","provider":"maplibre","instanceId":"vision-card-frontier","accent":"#22d3ee","title":"The last frontier of the gospel.","tagline":"Frontier people groups: fewer than one person in a thousand is an evangelical believer.","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"doxa-vision-card","dataSource":"pray-tools","instanceId":"doxa-vision-card-doxa-vision-card","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"doxa-vision-card","dataSource":"pray-tools","instanceId":"doxa-vision-card-doxa-vision-card","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"golden-path-check","dataSource":"pray-tools","instanceId":"golden-path-check-golden-path-check","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"golden-path-check","dataSource":"pray-tools","instanceId":"golden-path-check-golden-path-check","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","dataSource":"pray-tools","instanceId":"gospel-internet-board","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","dataSource":"pray-tools","instanceId":"gospel-internet-board","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","view":"province","panel":"map"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","view":"province","panel":"map","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","panel":"tree"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","panel":"tree","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","view":"platforms"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","view":"platforms","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","list":"700"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","list":"700","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <gospel-internet-board> custom element. -->
<script src="../../gospel-internet.js" integrity="sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0" crossorigin="anonymous"></script>
<script src="../../gospel-internet.js" integrity="sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","view":"zero"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"urlState":"query","mobile":"larger-screens","mobileLabel":"Gospel × Internet","profile":"board","view":"zero","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

File diff suppressed because one or more lines are too long

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"charts","dataSource":"pray-tools","instanceId":"gospel-resources-charts","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"charts","dataSource":"pray-tools","instanceId":"gospel-resources-charts","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"data-tables","dataSource":"pray-tools","instanceId":"gospel-resources-data-tables","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"data-tables","dataSource":"pray-tools","instanceId":"gospel-resources-data-tables","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -98,7 +98,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"gospel-dashboard","dataSource":"pray-tools","instanceId":"gospel-resources-gospel-dashboard","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"gospel-dashboard","dataSource":"pray-tools","instanceId":"gospel-resources-gospel-dashboard","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"resources-list","dataSource":"pray-tools","instanceId":"gospel-resources-resources-list","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"resources-list","dataSource":"pray-tools","instanceId":"gospel-resources-resources-list","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"resources-map","dataSource":"pray-tools","instanceId":"gospel-resources-resources-map","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"resources-map","dataSource":"pray-tools","instanceId":"gospel-resources-resources-map","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -24,6 +24,6 @@
</head>
<body>
<plugin-studio tree-base="."></plugin-studio>
<script src="./plugin-studio/plugin-studio.js" integrity="sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE" crossorigin="anonymous"></script>
<script src="./plugin-studio/plugin-studio.js" integrity="sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz" crossorigin="anonymous"></script>
</body>
</html>

View file

@ -410,7 +410,7 @@
"bundle": "dashboard-plus-grid",
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"output": "dx-maps/dashboard-plus-grid/dashboard-plus-grid.js",
"integrity": "sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6",
"integrity": "sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O",
"elements": [
"dashboard-plus-grid"
],
@ -434,8 +434,8 @@
"scriptUrl": "./dashboard-plus-grid/dashboard-plus-grid.js",
"embed": {
"iframe": "<iframe src=\"./dashboard-plus-grid/dashboard-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-Gry7ilwyyvp9rqx1qRLdOBzTUf2c/mobwY9u0PPnMi0hh85yLU9+lievYMxGaKW6\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-6eSrxg390nmpP3NsF1ViQX0ez3SuSwDQc6lCVH3M064cUpYe1SmEIzCT9obKVW6O\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<dashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></dashboard-plus-grid>"
},
"instances": [
{
@ -505,7 +505,7 @@
"bundle": "doxa-maps-spa",
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"output": "dx-maps/doxa-maps-spa/doxa-maps-spa.js",
"integrity": "sha384-TB7DtATxmWQAqr62j7QJmMjxBfiSysTZiUUxP0Su9xh9JlNO0YvFEafCKinjqd3W",
"integrity": "sha384-JbdbnT273exxkEbpgtOE3DxfYeQ1iPRockZeONzgkP1TJ3dITNCl4yRJ5KMXiXQb",
"elements": [
"doxa-maps-spa"
],
@ -535,7 +535,7 @@
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"embed": {
"iframe": "<iframe src=\"./doxa-maps-spa/doxa-maps-spa/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=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-TB7DtATxmWQAqr62j7QJmMjxBfiSysTZiUUxP0Su9xh9JlNO0YvFEafCKinjqd3W\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-JbdbnT273exxkEbpgtOE3DxfYeQ1iPRockZeONzgkP1TJ3dITNCl4yRJ5KMXiXQb\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
},
"instances": [
{
@ -798,7 +798,7 @@
"bundle": "gospel-internet",
"scriptUrl": "./gospel-internet/gospel-internet.js",
"output": "dx-maps/gospel-internet/gospel-internet.js",
"integrity": "sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0",
"integrity": "sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL",
"elements": [
"gospel-internet-board"
],
@ -819,8 +819,8 @@
"scriptUrl": "./gospel-internet/gospel-internet.js",
"embed": {
"iframe": "<iframe src=\"./gospel-internet/board/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-gZOzGQ4n1HeYAmQ2svLsGrDgEq/p5aqf/ZVSo2NRMJWvj1b4N10WyiRXFc27sch0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./gospel-internet/gospel-internet.js\" integrity=\"sha384-wbljRqxErJtdKSc2q8bFZ4voFf9vN9+8EM6xJOewT8DHnhKvX9kJiEVyKT7kaqFL\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<gospel-internet-board profile-config='{\"profile\":\"board\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></gospel-internet-board>"
},
"instances": [
{
@ -1219,7 +1219,7 @@
"bundle": "plugin-studio",
"scriptUrl": "./plugin-studio/plugin-studio.js",
"output": "dx-maps/plugin-studio/plugin-studio.js",
"integrity": "sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE",
"integrity": "sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz",
"elements": [
"plugin-studio"
],
@ -1250,7 +1250,7 @@
"scriptUrl": "./plugin-studio/plugin-studio.js",
"embed": {
"iframe": "<iframe src=\"./plugin-studio/plugin-studio/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=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
},
"instances": [
{
@ -1505,7 +1505,7 @@
"bundle": "posterverse",
"scriptUrl": "./posterverse/posterverse.js",
"output": "dx-maps/posterverse/posterverse.js",
"integrity": "sha384-UNJXfmuXx36JrGNHayoe7QpSEFG0cri9uRl2nJlXLJWBBWrYAn48OOzilxFVJZNu",
"integrity": "sha384-1jvCHQrT11Mixml/KvdnT44djTWvIe6TjNk2vU66hwtF4mefgVCSIRhMwXukYAqZ",
"elements": [
"posterverse-app"
],
@ -1532,7 +1532,7 @@
"scriptUrl": "./posterverse/posterverse.js",
"embed": {
"iframe": "<iframe src=\"./posterverse/posterverse/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=\"./posterverse/posterverse.js\" integrity=\"sha384-UNJXfmuXx36JrGNHayoe7QpSEFG0cri9uRl2nJlXLJWBBWrYAn48OOzilxFVJZNu\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<posterverse-app profile-config='{\"profile\":\"posterverse\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></posterverse-app>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./posterverse/posterverse.js\" integrity=\"sha384-1jvCHQrT11Mixml/KvdnT44djTWvIe6TjNk2vU66hwtF4mefgVCSIRhMwXukYAqZ\" crossorigin=\"anonymous\"></script>\n<!-- provider: \"maplibre\" is the default; change it to \"mapbox\" and fill tk to use Mapbox. -->\n<posterverse-app profile-config='{\"profile\":\"posterverse\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></posterverse-app>"
},
"instances": [
{
@ -1683,7 +1683,7 @@
"bundle": "research-dashboard",
"scriptUrl": "./research-dashboard/research-dashboard.js",
"output": "dx-maps/research-dashboard/research-dashboard.js",
"integrity": "sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl",
"integrity": "sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0",
"elements": [
"research-dashboard-map"
],
@ -1702,8 +1702,8 @@
"scriptUrl": "./research-dashboard/research-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./research-dashboard/research-dashboard/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
"script": "<!-- MapLibre engine (the default), fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.js\" integrity=\"sha384-5+cfbwT0iiub6VsQAdn6yz16nr6sDiQoHx6tm4O8OVYXHYOxcffFmCJBL0dgdvGp\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://cdn.jsdelivr.net/npm/maplibre-gl@5.24.0/dist/maplibre-gl.css\" integrity=\"sha384-uTttxo/aOKbdE5RlD/SPzSDoDmNvGlUYPjONi2MN/b7c9HPSvW07OIuyP7uL6jxK\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0\" crossorigin=\"anonymous\"></script>\n<!-- MapLibre draws this map and needs no token. For Mapbox, paste this map's embed.scriptMapbox from manifest.json instead: it sets \"provider\":\"mapbox\" and preloads the Mapbox engine; fill \"tk\" with your token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"maplibre\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>",
"scriptMapbox": "<!-- Mapbox engine, fetched early -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<link rel=\"preload\" as=\"style\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css\" integrity=\"sha384-rp1X/jJ9MpWPef9OimfXhOaOc4Gzs87yQvF+ajwY6X2H4PTeHNycNlLWiWvj7ehV\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0\" crossorigin=\"anonymous\"></script>\n<!-- Mapbox draws this map: fill \"tk\" with your Mapbox token. -->\n<research-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"provider\":\"mapbox\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></research-dashboard-map>"
},
"bundle": "research-dashboard"
}

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"poster-wall","dataSource":"pray-tools","instanceId":"my-upg-100-list-poster-wall","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"poster-wall","dataSource":"pray-tools","instanceId":"my-upg-100-list-poster-wall","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"upg-100-list","dataSource":"pray-tools","instanceId":"my-upg-100-list-upg-100-list","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"upg-100-list","dataSource":"pray-tools","instanceId":"my-upg-100-list-upg-100-list","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -98,7 +98,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"upg-100-mfe","dataSource":"pray-tools","instanceId":"my-upg-100-list-upg-100-mfe","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"upg-100-mfe","dataSource":"pray-tools","instanceId":"my-upg-100-list-upg-100-mfe","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"people-groups-grid","provider":"maplibre","instanceId":"people-groups-grid-driven","pray-base-url":"https://pray.doxa.life","show-search":"false","show-filters":"false"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"people-groups-grid","provider":"maplibre","instanceId":"people-groups-grid-driven","pray-base-url":"https://pray.doxa.life","show-search":"false","show-filters":"false","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"people-groups-grid","dataSource":"pray-tools","instanceId":"people-groups-grid-people-groups-grid","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"people-groups-grid","dataSource":"pray-tools","instanceId":"people-groups-grid-people-groups-grid","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"people-groups-grid","provider":"maplibre","instanceId":"people-groups-grid","pray-base-url":"https://pray.doxa.life"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"people-groups-grid","provider":"maplibre","instanceId":"people-groups-grid","pray-base-url":"https://pray.doxa.life","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <plugin-studio> custom element. -->
<script src="../plugin-studio.js" integrity="sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE" crossorigin="anonymous"></script>
<script src="../plugin-studio.js" integrity="sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"plugin-studio","dataSource":"pray-tools","instanceId":"plugin-studio-plugin-studio","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"plugin-studio","dataSource":"pray-tools","instanceId":"plugin-studio-plugin-studio","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <plugin-studio> custom element. -->
<script src="../../plugin-studio.js" integrity="sha384-wIm+A7YFW95FumG/5ZGHJkwW5ujHyOQY/3XkPZGl/IdYVF+2MOKaiH//7orwd7pE" crossorigin="anonymous"></script>
<script src="../../plugin-studio.js" integrity="sha384-fUBGsSNbCdWEJ6QNmeOJf78N88LmjL7b5ktyt11xm5iSZxM/u2xwNdPzHaT2A6Dz" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"plugin-studio","provider":"maplibre","instanceId":"plugin-studio","title":"Plugin Studio"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"plugin-studio","provider":"maplibre","instanceId":"plugin-studio","title":"Plugin Studio","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -89,7 +89,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"poster-design-mfe","dataSource":"pray-tools","instanceId":"poster-design-poster-design-mfe","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"poster-design-mfe","dataSource":"pray-tools","instanceId":"poster-design-poster-design-mfe","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"poster-sizes","dataSource":"pray-tools","instanceId":"poster-design-poster-sizes","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"poster-sizes","dataSource":"pray-tools","instanceId":"poster-design-poster-sizes","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"poster-styles","dataSource":"pray-tools","instanceId":"poster-design-poster-styles","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"poster-styles","dataSource":"pray-tools","instanceId":"poster-design-poster-styles","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","configure":true};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","configure":true,"urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"africa"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"africa","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"all"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"all","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"asia"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"asia","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"europe"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"europe","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"latin-america-and-caribbean"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"latin-america-and-caribbean","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"middle-east"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"middle-east","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"north-america-and-non-spanish-caribbean"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"north-america-and-non-spanish-caribbean","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"oceania"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"poster-sections","type":"country","scope":"oceania","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"poster-sections","dataSource":"pray-tools","instanceId":"poster-sections-poster-sections","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"poster-sections","dataSource":"pray-tools","instanceId":"poster-sections-poster-sections","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

File diff suppressed because one or more lines are too long

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <posterverse-app> custom element. -->
<script src="../../posterverse.js" integrity="sha384-UNJXfmuXx36JrGNHayoe7QpSEFG0cri9uRl2nJlXLJWBBWrYAn48OOzilxFVJZNu" crossorigin="anonymous"></script>
<script src="../../posterverse.js" integrity="sha384-1jvCHQrT11Mixml/KvdnT44djTWvIe6TjNk2vU66hwtF4mefgVCSIRhMwXukYAqZ" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"posterverse","provider":"maplibre","instanceId":"posterverse-app","heading":"Posterverse"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"posterverse","provider":"maplibre","instanceId":"posterverse-app","heading":"Posterverse","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -67,7 +67,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <posterverse-app> custom element. -->
<script src="../posterverse.js" integrity="sha384-UNJXfmuXx36JrGNHayoe7QpSEFG0cri9uRl2nJlXLJWBBWrYAn48OOzilxFVJZNu" crossorigin="anonymous"></script>
<script src="../posterverse.js" integrity="sha384-1jvCHQrT11Mixml/KvdnT44djTWvIe6TjNk2vU66hwtF4mefgVCSIRhMwXukYAqZ" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"posterverse","dataSource":"pray-tools","instanceId":"posterverse-posterverse","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"posterverse","dataSource":"pray-tools","instanceId":"posterverse-posterverse","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"pplr-data-maps","dataSource":"pray-tools","instanceId":"pplr-data-maps-pplr-data-maps","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"pplr-data-maps","dataSource":"pray-tools","instanceId":"pplr-data-maps-pplr-data-maps","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"prayer-walk-planner","dataSource":"pray-tools","instanceId":"prayer-walk-planner-prayer-walk-planner","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"prayer-walk-planner","dataSource":"pray-tools","instanceId":"prayer-walk-planner-prayer-walk-planner","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"region-dashboards","dataSource":"pray-tools","instanceId":"regions-dashboard-region-dashboards","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"region-dashboards","dataSource":"pray-tools","instanceId":"regions-dashboard-region-dashboards","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -83,7 +83,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"regions-list","dataSource":"pray-tools","instanceId":"regions-dashboard-regions-list","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"regions-list","dataSource":"pray-tools","instanceId":"regions-dashboard-regions-list","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -94,7 +94,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"regions-mfe","dataSource":"pray-tools","instanceId":"regions-dashboard-regions-mfe","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"regions-mfe","dataSource":"pray-tools","instanceId":"regions-dashboard-regions-mfe","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

File diff suppressed because one or more lines are too long

View file

@ -76,7 +76,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <research-dashboard-map> custom element. -->
<script src="../research-dashboard.js" integrity="sha384-xF63GgYlNh2ISrWowg2bVmEua8No2+eej7QZpTOBfTPZlx/HJwmO/jD3qdD/Fbgl" crossorigin="anonymous"></script>
<script src="../research-dashboard.js" integrity="sha384-QXxsY2mQTDSHzPA/PliyvqmkiiaM53CiNEYx0aREj2wgRHD/bDGJfhsW4v5R1Ki0" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:
@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"research-dashboard","dataSource":"pray-tools","instanceId":"research-dashboard-research-dashboard","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"research-dashboard","dataSource":"pray-tools","instanceId":"research-dashboard-research-dashboard","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -94,7 +94,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"research-map-plus-grid"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"research-map-plus-grid","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -94,7 +94,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"research-map-plus-grid","dataSource":"pray-tools","instanceId":"research-map-plus-grid-research-map-plus-grid","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"research-map-plus-grid","dataSource":"pray-tools","instanceId":"research-map-plus-grid-research-map-plus-grid","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -94,7 +94,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"profile":"stack-demo","dataSource":"pray-tools","instanceId":"stack-demo-stack-demo","assetsBase":"../../assets"};
var BASE_CONFIG = {"profile":"stack-demo","dataSource":"pray-tools","instanceId":"stack-demo-stack-demo","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -94,7 +94,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"stack-demo"};
var BASE_CONFIG = {"assetsBase":"../../../assets","profile":"stack-demo","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"profile":"upg-neighbor","view":"mobilize"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"profile":"upg-neighbor","view":"mobilize","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"profile":"upg-neighbor","view":"mobilize"};
var BASE_CONFIG = {"assetsBase":"../../../assets","pinHint":false,"profile":"upg-neighbor","view":"mobilize","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

View file

@ -92,7 +92,10 @@
(function () {
var slot = document.getElementById('slot');
var status = document.getElementById('status');
var BASE_CONFIG = {"pinHint":false,"profile":"upg-neighbor","dataSource":"pray-tools","instanceId":"upg-neighbor-upg-neighbor","assetsBase":"../../assets"};
var BASE_CONFIG = {"pinHint":false,"profile":"upg-neighbor","dataSource":"pray-tools","instanceId":"upg-neighbor-upg-neighbor","assetsBase":"../../assets","urlOwner":"app"};
// Framed (the iframe embed on a partner's page): READ the address, never write it. A push inside a frame adds
// entries to the partner page's own Back button (the joint session history).
try { if (window.self !== window.top) delete BASE_CONFIG.urlOwner } catch (e) { delete BASE_CONFIG.urlOwner }
// MapLibre map pages AND shell pages (app-shell / nested-mfe-spa) need NO token:
// the ladder below is skipped entirely and the element mounts immediately.
// (A leaf whose engine is MapLibre at RUNTIME joins them — see PROVIDER below.)

Some files were not shown because too many files have changed in this diff Show more