feat: origin-derived share URL — defaults to the map page's own location so embeds are correct on any CDN/host (GitHub Pages, host public/, external), explicit path still wins
This commit is contained in:
parent
f8eb75d239
commit
de054ca078
5 changed files with 106 additions and 222 deletions
|
|
@ -393,15 +393,20 @@ const sizePresets = {
|
|||
'profileConfig') via profile-config.shareEmbedPath;
|
||||
(3) the research-map page as a final fallback. */
|
||||
const profileConfig = inject('profileConfig', null)
|
||||
const embedPath = computed(() =>
|
||||
props.embedPath || profileConfig?.value?.shareEmbedPath || '/maps/doxa-research-map.html'
|
||||
)
|
||||
|
||||
/* ORIGIN-DERIVED by default: each map builds to a self-contained page ("Share shares
|
||||
THE MAP"), so when no explicit path is configured the current page's own location IS
|
||||
the correct embed url — works unchanged on GitHub Pages, a host site's public/, or any
|
||||
CDN. An explicit prop/config path still wins (absolute url passes through; a path joins
|
||||
the live origin). */
|
||||
const shareUrl = computed(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return window.location.origin + embedPath.value
|
||||
const explicit = props.embedPath || profileConfig?.value?.shareEmbedPath || ''
|
||||
if (typeof window === 'undefined') {
|
||||
return 'https://doxa.life' + (explicit || '/maps/doxa-research-map.html')
|
||||
}
|
||||
return 'https://doxa.life' + embedPath.value
|
||||
if (explicit) {
|
||||
return /^https?:\/\//.test(explicit) ? explicit : window.location.origin + explicit
|
||||
}
|
||||
return window.location.origin + window.location.pathname
|
||||
})
|
||||
|
||||
const embedSnippet = computed(() => {
|
||||
|
|
|
|||
74
public/doxa-maps/country-posters/country-posters.js
generated
74
public/doxa-maps/country-posters/country-posters.js
generated
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
62
public/doxa-maps/doxa-simple-map/doxa-simple-map.js
generated
62
public/doxa-maps/doxa-simple-map/doxa-simple-map.js
generated
File diff suppressed because one or more lines are too long
121
public/doxa-maps/prayer-map/demo-map/index.html
generated
121
public/doxa-maps/prayer-map/demo-map/index.html
generated
|
|
@ -1,121 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>demo-map · prayer-map</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<!-- Mapbox peer loaded ONCE here; the map custom element mounts in this page and
|
||||
uses window.mapboxgl directly (same realm → no cross-realm container errors). -->
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.css" rel="stylesheet" />
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.css" rel="stylesheet" />
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js"></script>
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js"></script>
|
||||
<style>
|
||||
/* BARE full-page map — no chrome. The custom element IS the page, so the
|
||||
browser URL shares the map itself (design note: "Share shares THE MAP"). */
|
||||
html, body { height: 100%; margin: 0; background: #0a0e15; }
|
||||
#slot, prayer-map { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }
|
||||
#status { position: fixed; inset: 0; z-index: 2; display: grid; place-items: center;
|
||||
padding: 24px; text-align: center; color: #9aa7b8;
|
||||
font: 13px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
||||
#status.err { color: #f87171; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="slot"></div>
|
||||
<div id="status">loading token…</div>
|
||||
|
||||
<!-- Bundle IIFE — registers the <prayer-map> custom element. -->
|
||||
<script src="../prayer-map.js"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
// 1. prop — a token hardcoded into this page's profile-config (config.tk)
|
||||
// 2. ?tk= URL param — token carried in the shared link
|
||||
// 3. baked token — opt-in literal token inlined at build time (build-config.token)
|
||||
// A token from rungs 1-3 is used DIRECTLY (no network). Otherwise a token
|
||||
// *endpoint* is resolved and fetched:
|
||||
// 4. window.MAP_TOKEN_URL override 5. configured TOKEN_SRC URL 6. same-origin /api/maps/token
|
||||
// TOKEN_SRC is treated as DATA, never eval'd: the literal "window.MAP_TOKEN_URL"
|
||||
// means "read that global"; anything else is used as a URL — so both a global
|
||||
// name and a plain URL are safe (no SyntaxError footgun).
|
||||
(function () {
|
||||
var slot = document.getElementById('slot');
|
||||
var status = document.getElementById('status');
|
||||
var BASE_CONFIG = {"profile":"demo-map","dataSource":"pray-tools","instanceId":"prayer-map-demo-map","assetsBase":"../../../assets"};
|
||||
var TOKEN_SRC = "/api/maps/token.json";
|
||||
var BAKED_TOKEN = "";
|
||||
var DEFAULT_TOKEN_URL = '/api/maps/token';
|
||||
|
||||
function fail(msg) { if (status) { status.className = 'err'; status.textContent = '⚠ ' + msg; } }
|
||||
// No token anywhere on the ladder → ask ONCE, store locally, remount. No dead ends.
|
||||
function askToken() {
|
||||
if (!status) return;
|
||||
status.className = 'err';
|
||||
status.innerHTML = 'map needs a Mapbox token — ' +
|
||||
'<input id="tkIn" type="password" placeholder="paste pk.… (stays in this browser)" ' +
|
||||
'style="font:12px ui-monospace,monospace;padding:6px 8px;border-radius:6px;border:1px solid #223047;background:#0e1623;color:#eef2f7;width:min(320px,70vw)"> ' +
|
||||
'<button id="tkGo" style="font:700 11px ui-monospace,monospace;padding:7px 12px;border-radius:999px;border:0;cursor:pointer;background:linear-gradient(90deg,#46d4ff,#b9a6f5);color:#0a0e15">use it</button>';
|
||||
var go = document.getElementById('tkGo');
|
||||
if (go) go.addEventListener('click', function () {
|
||||
var v = (document.getElementById('tkIn').value || '').trim();
|
||||
if (!v) return;
|
||||
try { localStorage.setItem('MAPS_STAGING_TK', v); } catch (e) {}
|
||||
mount(v);
|
||||
});
|
||||
}
|
||||
function done() { if (status && status.parentNode) { status.parentNode.removeChild(status); } }
|
||||
|
||||
function mount(token) {
|
||||
if (!token) { return askToken(); }
|
||||
try {
|
||||
var cfg = Object.assign({}, BASE_CONFIG, { tk: token });
|
||||
var el = document.createElement("prayer-map");
|
||||
el.setAttribute('profile-config', JSON.stringify(cfg));
|
||||
slot.innerHTML = '';
|
||||
slot.appendChild(el);
|
||||
done();
|
||||
} catch (e) { fail(e && e.message ? e.message : String(e)); }
|
||||
}
|
||||
|
||||
function qp(name) {
|
||||
try { return new URLSearchParams(location.search).get(name) || ''; }
|
||||
catch (e) { return ''; }
|
||||
}
|
||||
|
||||
function extractToken(data) {
|
||||
if (typeof data === 'string') return data.trim();
|
||||
if (data && typeof data === 'object') return data.token || data.tk || data.accessToken || '';
|
||||
return '';
|
||||
}
|
||||
|
||||
// Rungs 1-3b: an actual token → mount directly, no fetch.
|
||||
// 2b = localStorage: the paste-once store shared with the staging pages
|
||||
// (MAPS_STAGING_TK) — paste a token ONCE anywhere in the tree, every page uses it.
|
||||
var stored = '';
|
||||
try { stored = localStorage.getItem('MAPS_STAGING_TK') || ''; } catch (e) {}
|
||||
var urlTk = qp('tk');
|
||||
if (urlTk) { try { localStorage.setItem('MAPS_STAGING_TK', urlTk); } catch (e) {} }
|
||||
var directToken = (BASE_CONFIG && BASE_CONFIG.tk) || urlTk || stored || BAKED_TOKEN;
|
||||
if (directToken) { return mount(directToken); }
|
||||
|
||||
// Rungs 4-6: resolve a token endpoint and fetch it.
|
||||
var tokenUrl =
|
||||
(window.MAP_TOKEN_URL) ||
|
||||
(TOKEN_SRC && TOKEN_SRC !== 'window.MAP_TOKEN_URL' ? TOKEN_SRC : '') ||
|
||||
DEFAULT_TOKEN_URL;
|
||||
|
||||
fetch(tokenUrl)
|
||||
.then(function (r) {
|
||||
var ct = r.headers.get('content-type') || '';
|
||||
return ct.indexOf('json') !== -1 ? r.json() : r.text();
|
||||
})
|
||||
.then(function (data) { mount(extractToken(data)); })
|
||||
.catch(function (e) {
|
||||
fail('Token fetch failed from ' + tokenUrl + ' — set window.MAP_TOKEN_URL or pass ?tk=. (' + (e && e.message ? e.message : e) + ')');
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue