library: one embedScript for the app shells, replacing four private copies
DEDUP-AUDIT.md (measured today: 253 files, 31 cross-plugin duplicate clusters, 622 duplicated lines) ranks this tenth by raw cost and first by suitability. It is the only cluster where the copies are identical in code, close over nothing, and sit in two plugins with one owner between them. loadScriptOnce (13 lines) and whenTagDefined (11) were byte-identical between doxa-maps-spa and plugin-studio. deriveTreeBase (9) differed by ONE COMMENT LINE and not one character of code -- drift in the documentation of a shared function, which is its own argument for having one copy. They are one concern, not three: load a bundle's script once, wait for its custom element to register, and work out the tree base to load it from. That is what a capability-5 app shell does to nest another plugin, and both plugins here ARE the capability-5 shells. Any future shell needs the same three. Verbatim move: no parameterisation, no behaviour change, callers import instead of declaring. The comments travel with the code because each records a measurement -- particularly the one explaining why onload is not a usable success signal for a dev-server ES module. ONE BEHAVIOUR CHANGE, AND IT IS AN IMPROVEMENT: the _loaded cache is now shared. Two shells on one page previously kept separate caches and each loaded the same bundle; the second now reuses the first's promise. deriveTreeBase reads document.currentScript, so it is only valid AT MODULE EVALUATION TIME. The call sites did not move -- both entries still call it at module top level -- and the library file documents the constraint, because a later call silently returns '' and every nested bundle URL would break. Verified: both bundles build; each built file contains all three functions exactly once and still derives currentScript; check:sri, check:series-isolation, check:studio-rail and check:capability-derived all PASS. library/utils/embedScript.js is the build owner's under rule 5B. The plugin-designs and public/ changes are in the same commit because they import it -- landing them apart breaks the build in between.
This commit is contained in:
parent
15b8cb4756
commit
d0939c0492
14 changed files with 105 additions and 123 deletions
82
library/utils/embedScript.js
Normal file
82
library/utils/embedScript.js
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* embedScript — load another bundle's script and wait for its element to register.
|
||||
*
|
||||
* ★ WHAT AN APP SHELL DOES. A capability-5 plugin nests other plugins, so it needs three things:
|
||||
* work out the tree root it was served from, load a bundle's `.js` exactly once, and wait for the
|
||||
* custom element to actually exist before mounting it. Both shells in this repo — the Research
|
||||
* Gallery (`doxa-maps-spa`) and the Plugin Studio (`plugin-studio`) — had their own copy of all
|
||||
* three, identical in code (DEDUP-AUDIT.md, 2026-09-28: 33 lines, the only cross-plugin cluster
|
||||
* that is identical, closes over nothing, and spans one owner's plugins).
|
||||
*
|
||||
* Moved verbatim; the comments below are the originals, because each records a measurement.
|
||||
*
|
||||
* ★ ONE BEHAVIOUR CHANGE, AND IT IS AN IMPROVEMENT: `_loaded` is now shared. Two shells on one page
|
||||
* previously kept separate caches and would each load the same bundle. Now the second one reuses
|
||||
* the first's promise. Same result, one network request instead of two.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Load a bundle exactly once per URL; resolves after its script has executed.
|
||||
*
|
||||
* ★ A CLASSIC SCRIPT FIRES onload AND THEN FAILS, for a dev-server bundle. Measured 2026-09-22:
|
||||
* pointing a plain <script> at a dev entry (/plugin-designs/<bundle>/index.js, a real ES MODULE)
|
||||
* fires onload — so a loader watching onload reports SUCCESS — and only THEN throws "Cannot use
|
||||
* import statement outside a module" as an ASYNC page error. The tag is never defined,
|
||||
* document.createElement(tag) yields an inert HTMLUnknownElement, and the pane sits empty while its
|
||||
* own state reads 'ready'. onload is structurally incapable of seeing this, so it is not a usable
|
||||
* success signal by itself — which is why every mount below also waits on whenTagDefined().
|
||||
*
|
||||
* The built tree ships IIFEs, where a classic tag is correct, so this only ever bites under the dev
|
||||
* server — exactly the surface a developer works on. Rule: a rooted /plugin-designs/ entry (or any
|
||||
* .../index.js) is a dev ES module; everything else is a built IIFE.
|
||||
*
|
||||
* SRI is optional (attrs.integrity).
|
||||
*/
|
||||
const _loaded = {}
|
||||
export function loadScriptOnce(url, attrs) {
|
||||
if (_loaded[url]) return _loaded[url]
|
||||
_loaded[url] = new Promise((ok, fail) => {
|
||||
const s = document.createElement('script')
|
||||
s.src = url
|
||||
if (/^\/plugin-designs\//.test(url) || /\/index\.js(\?|$)/.test(url)) s.type = 'module'
|
||||
if (attrs) for (const k in attrs) if (attrs[k]) s.setAttribute(k, attrs[k])
|
||||
s.onload = () => ok()
|
||||
s.onerror = () => { delete _loaded[url]; fail(new Error('failed to load ' + url)) }
|
||||
document.head.appendChild(s)
|
||||
})
|
||||
return _loaded[url]
|
||||
}
|
||||
|
||||
// Wait for a tag to ACTUALLY register. loadScriptOnce resolving is not proof the element exists (see
|
||||
// above), and a module script's define() runs only after its import graph settles, so the tag can
|
||||
// appear a tick or two after onload. customElements.whenDefined is the browser's own authoritative
|
||||
// answer; the timeout turns a never-registered tag into THIS tab's error overlay rather than a silent
|
||||
// blank pane that claims to be ready.
|
||||
export function whenTagDefined(tag, ms) {
|
||||
if (typeof customElements === 'undefined') return Promise.resolve()
|
||||
if (customElements.get(tag)) return Promise.resolve()
|
||||
return Promise.race([
|
||||
customElements.whenDefined(tag),
|
||||
new Promise((_, fail) => setTimeout(() => {
|
||||
if (customElements.get(tag)) return
|
||||
fail(new Error('<' + tag + '> never registered (bundle loaded but defined no element)'))
|
||||
}, ms || 15000))
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* The tree root this shell was served from, with a trailing slash, or '' when it cannot be known.
|
||||
*
|
||||
* ⚠ READS document.currentScript, so it is only valid AT MODULE EVALUATION TIME. Call it once at the
|
||||
* top of an entry file (`const TREE_BASE = deriveTreeBase()`), never later — `currentScript` is null
|
||||
* once the script has finished executing, and a late call silently returns ''.
|
||||
*/
|
||||
export function deriveTreeBase() {
|
||||
try {
|
||||
const cur = (typeof document !== 'undefined' && document.currentScript && document.currentScript.src) || ''
|
||||
if (!cur) return ''
|
||||
// Strip the trailing "<bundle>/<bundle>.js" → the tree root, with trailing slash.
|
||||
const root = cur.replace(/[^/]+\/[^/]+$/, '')
|
||||
return root.replace(/\/+$/, '') + '/'
|
||||
} catch { return '' }
|
||||
}
|
||||
|
|
@ -159,6 +159,7 @@ import { defineComponent, inject } from 'vue'
|
|||
import VerticalTabsLayout from '@map/layouts/VerticalTabsLayout.vue'
|
||||
import { SWITCHER_LANGUAGES, loadLocale, saveLocale, getLanguage } from '@map/layouts/app-wrapper-material/languages.js'
|
||||
import { translate, LOCALES, hasKey } from './src/strings.js'
|
||||
import { loadScriptOnce, whenTagDefined } from '@map/utils/embedScript.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.
|
||||
|
|
@ -680,54 +681,7 @@ function resolveTabsFromManifest(manifest, defs) {
|
|||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a bundle exactly once per URL; resolves after its script has executed.
|
||||
*
|
||||
* ★ A CLASSIC SCRIPT FIRES onload AND THEN FAILS, for a dev-server bundle. Measured 2026-09-22:
|
||||
* pointing a plain <script> at a dev entry (/plugin-designs/<bundle>/index.js, a real ES MODULE)
|
||||
* fires onload — so a loader watching onload reports SUCCESS — and only THEN throws "Cannot use
|
||||
* import statement outside a module" as an ASYNC page error. The tag is never defined,
|
||||
* document.createElement(tag) yields an inert HTMLUnknownElement, and the pane sits empty while its
|
||||
* own state reads 'ready'. onload is structurally incapable of seeing this, so it is not a usable
|
||||
* success signal by itself — which is why every mount below also waits on whenTagDefined().
|
||||
*
|
||||
* The built tree ships IIFEs, where a classic tag is correct, so this only ever bites under the dev
|
||||
* server — exactly the surface a developer works on. Rule: a rooted /plugin-designs/ entry (or any
|
||||
* .../index.js) is a dev ES module; everything else is a built IIFE.
|
||||
*
|
||||
* SRI is optional (attrs.integrity).
|
||||
*/
|
||||
const _loaded = {}
|
||||
function loadScriptOnce(url, attrs) {
|
||||
if (_loaded[url]) return _loaded[url]
|
||||
_loaded[url] = new Promise((ok, fail) => {
|
||||
const s = document.createElement('script')
|
||||
s.src = url
|
||||
if (/^\/plugin-designs\//.test(url) || /\/index\.js(\?|$)/.test(url)) s.type = 'module'
|
||||
if (attrs) for (const k in attrs) if (attrs[k]) s.setAttribute(k, attrs[k])
|
||||
s.onload = () => ok()
|
||||
s.onerror = () => { delete _loaded[url]; fail(new Error('failed to load ' + url)) }
|
||||
document.head.appendChild(s)
|
||||
})
|
||||
return _loaded[url]
|
||||
}
|
||||
|
||||
// Wait for a tag to ACTUALLY register. loadScriptOnce resolving is not proof the element exists (see
|
||||
// above), and a module script's define() runs only after its import graph settles, so the tag can
|
||||
// appear a tick or two after onload. customElements.whenDefined is the browser's own authoritative
|
||||
// answer; the timeout turns a never-registered tag into THIS tab's error overlay rather than a silent
|
||||
// blank pane that claims to be ready.
|
||||
function whenTagDefined(tag, ms) {
|
||||
if (typeof customElements === 'undefined') return Promise.resolve()
|
||||
if (customElements.get(tag)) return Promise.resolve()
|
||||
return Promise.race([
|
||||
customElements.whenDefined(tag),
|
||||
new Promise((_, fail) => setTimeout(() => {
|
||||
if (customElements.get(tag)) return
|
||||
fail(new Error('<' + tag + '> never registered (bundle loaded but defined no element)'))
|
||||
}, ms || 15000))
|
||||
])
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DoxaMapsSpa',
|
||||
|
|
|
|||
|
|
@ -30,19 +30,11 @@
|
|||
|
||||
import { defineCustomElement } from 'vue'
|
||||
import DoxaMapsSpa from './doxa-maps-spa.vue'
|
||||
import { deriveTreeBase } from '@map/utils/embedScript.js'
|
||||
|
||||
// Capture the running <script>'s own URL synchronously at IIFE load, BEFORE any async runs, so
|
||||
// document.currentScript is still this bundle's tag. Derive the tree root = two levels up
|
||||
// (.../doxa-maps/doxa-maps-spa/doxa-maps-spa.js → .../doxa-maps/). Guarded for non-browser.
|
||||
function deriveTreeBase() {
|
||||
try {
|
||||
const cur = (typeof document !== 'undefined' && document.currentScript && document.currentScript.src) || ''
|
||||
if (!cur) return ''
|
||||
// Strip the trailing "<bundle>/<bundle>.js" → the tree root, with trailing slash.
|
||||
const root = cur.replace(/[^/]+\/[^/]+$/, '')
|
||||
return root.replace(/\/+$/, '') + '/'
|
||||
} catch { return '' }
|
||||
}
|
||||
const TREE_BASE = deriveTreeBase()
|
||||
|
||||
const DoxaMapsSpaElement = defineCustomElement(DoxaMapsSpa, {
|
||||
|
|
|
|||
|
|
@ -33,18 +33,11 @@
|
|||
|
||||
import { defineCustomElement } from 'vue'
|
||||
import PluginStudio from './plugin-studio.vue'
|
||||
import { deriveTreeBase } from '@map/utils/embedScript.js'
|
||||
|
||||
// Capture the running <script>'s own URL synchronously at IIFE load, BEFORE any async runs, so
|
||||
// document.currentScript is still this bundle's tag. Derive the tree root = two levels up
|
||||
// (.../doxa-maps/plugin-studio/plugin-studio.js -> .../doxa-maps/). Guarded for non-browser.
|
||||
function deriveTreeBase() {
|
||||
try {
|
||||
const cur = (typeof document !== 'undefined' && document.currentScript && document.currentScript.src) || ''
|
||||
if (!cur) return ''
|
||||
const root = cur.replace(/[^/]+\/[^/]+$/, '')
|
||||
return root.replace(/\/+$/, '') + '/'
|
||||
} catch { return '' }
|
||||
}
|
||||
const TREE_BASE = deriveTreeBase()
|
||||
|
||||
const PluginStudioElement = defineCustomElement(PluginStudio, {
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ import VerticalTabsLayout from '@map/layouts/VerticalTabsLayout.vue'
|
|||
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'
|
||||
|
||||
// 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).
|
||||
|
|
@ -428,47 +429,7 @@ function rowLabel(bundle, p) {
|
|||
return p.profile === bundle ? humanize(bundle) : humanize(bundle) + ' · ' + humanize(p.profile)
|
||||
}
|
||||
|
||||
// Load a bundle exactly once per URL; resolves after its define() has run.
|
||||
//
|
||||
// ★ A CLASSIC SCRIPT FIRES onload AND THEN FAILS, for a dev-server bundle. Measured 2026-09-22:
|
||||
// pointing a plain <script> at the dev entry (/plugin-designs/<bundle>/index.js, a real ES
|
||||
// module) fires onload — so the old loader resolved "success" — and only THEN throws
|
||||
// "Cannot use import statement outside a module" as an async page error. The tag is never
|
||||
// defined, createElement yields an inert HTMLUnknownElement, and the pane sits empty while its
|
||||
// state reads 'ready'. onload is structurally incapable of seeing this failure, so it is not a
|
||||
// usable success signal on its own. A built tree ships IIFEs, where a classic tag is correct, so
|
||||
// this only ever bites under the dev server — exactly where the studio is developed.
|
||||
// Rule: a rooted /plugin-designs/ entry is a dev ES module; everything else is a built IIFE.
|
||||
const _loaded = {}
|
||||
function loadScriptOnce(url, attrs) {
|
||||
if (_loaded[url]) return _loaded[url]
|
||||
_loaded[url] = new Promise((ok, fail) => {
|
||||
const s = document.createElement('script')
|
||||
s.src = url
|
||||
if (/^\/plugin-designs\//.test(url) || /\/index\.js(\?|$)/.test(url)) s.type = 'module'
|
||||
if (attrs) for (const k in attrs) if (attrs[k]) s.setAttribute(k, attrs[k])
|
||||
s.onload = () => ok()
|
||||
s.onerror = () => { delete _loaded[url]; fail(new Error('failed to load ' + url)) }
|
||||
document.head.appendChild(s)
|
||||
})
|
||||
return _loaded[url]
|
||||
}
|
||||
|
||||
// Wait for a tag to actually register. loadScriptOnce resolving is NOT proof the element exists
|
||||
// (see above), and a module script's define() runs after its import graph settles, so the tag can
|
||||
// appear a tick or two after onload. whenDefined is the browser's own authoritative answer; the
|
||||
// timeout turns a never-registered tag into THIS row's error overlay instead of a silent blank pane.
|
||||
function whenTagDefined(tag, ms) {
|
||||
if (typeof customElements === 'undefined') return Promise.resolve()
|
||||
if (customElements.get(tag)) return Promise.resolve()
|
||||
return Promise.race([
|
||||
customElements.whenDefined(tag),
|
||||
new Promise((_, fail) => setTimeout(() => {
|
||||
if (customElements.get(tag)) return
|
||||
fail(new Error('<' + tag + '> never registered (bundle loaded but defined no element)'))
|
||||
}, ms || 15000))
|
||||
])
|
||||
}
|
||||
|
||||
// Corner widgets: a round chat-style bubble; open, a small panel above it (a bottom sheet on a phone).
|
||||
const WIDGET_CSS = `
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -32,7 +32,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-CKJT8BCWZubQKLenstpsz19Kd87akZiO1SGu5+Ma3byRUdyXz0gcjrtmmkQxzw7i" crossorigin="anonymous"></script>
|
||||
<script src="../../doxa-maps-spa.js" integrity="sha384-v2Dwy2XYwI0BWeBSSU+eMjQwfQOoPazHYADsRmth6eQ3xjpSiHh0GEyQgvwLIGx7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,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-CKJT8BCWZubQKLenstpsz19Kd87akZiO1SGu5+Ma3byRUdyXz0gcjrtmmkQxzw7i" crossorigin="anonymous"></script>
|
||||
<script src="../doxa-maps-spa.js" integrity="sha384-v2Dwy2XYwI0BWeBSSU+eMjQwfQOoPazHYADsRmth6eQ3xjpSiHh0GEyQgvwLIGx7" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
"label": "Country Posters — Wall + Map",
|
||||
"file": "country-posters-mfe.vue",
|
||||
"description": "Country Posters as ONE two-tab element — the countries map and the printable",
|
||||
"element": "country-posters-map",
|
||||
"element": "country-posters-mfe",
|
||||
"type": "nested-elements-mfe",
|
||||
"isMap": true,
|
||||
"iframeUrl": "./country-posters/country-posters-mfe/index.html",
|
||||
|
|
@ -321,7 +321,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-CKJT8BCWZubQKLenstpsz19Kd87akZiO1SGu5+Ma3byRUdyXz0gcjrtmmkQxzw7i",
|
||||
"integrity": "sha384-v2Dwy2XYwI0BWeBSSU+eMjQwfQOoPazHYADsRmth6eQ3xjpSiHh0GEyQgvwLIGx7",
|
||||
"elements": [
|
||||
"doxa-maps-spa"
|
||||
],
|
||||
|
|
@ -349,7 +349,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-CKJT8BCWZubQKLenstpsz19Kd87akZiO1SGu5+Ma3byRUdyXz0gcjrtmmkQxzw7i\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"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-v2Dwy2XYwI0BWeBSSU+eMjQwfQOoPazHYADsRmth6eQ3xjpSiHh0GEyQgvwLIGx7\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -956,7 +956,7 @@
|
|||
"bundle": "plugin-studio",
|
||||
"scriptUrl": "./plugin-studio/plugin-studio.js",
|
||||
"output": "dx-maps/plugin-studio/plugin-studio.js",
|
||||
"integrity": "sha384-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD",
|
||||
"integrity": "sha384-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu",
|
||||
"elements": [
|
||||
"plugin-studio"
|
||||
],
|
||||
|
|
@ -987,7 +987,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-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"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-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@
|
|||
</head>
|
||||
<body>
|
||||
<plugin-studio tree-base="."></plugin-studio>
|
||||
<script src="./plugin-studio/plugin-studio.js" integrity="sha384-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD" crossorigin="anonymous"></script>
|
||||
<script src="./plugin-studio/plugin-studio.js" integrity="sha384-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
"label": "Country Posters — Wall + Map",
|
||||
"file": "country-posters-mfe.vue",
|
||||
"description": "Country Posters as ONE two-tab element — the countries map and the printable",
|
||||
"element": "country-posters-map",
|
||||
"element": "country-posters-mfe",
|
||||
"type": "nested-elements-mfe",
|
||||
"isMap": true,
|
||||
"iframeUrl": "./country-posters/country-posters-mfe/index.html",
|
||||
|
|
@ -321,7 +321,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-CKJT8BCWZubQKLenstpsz19Kd87akZiO1SGu5+Ma3byRUdyXz0gcjrtmmkQxzw7i",
|
||||
"integrity": "sha384-v2Dwy2XYwI0BWeBSSU+eMjQwfQOoPazHYADsRmth6eQ3xjpSiHh0GEyQgvwLIGx7",
|
||||
"elements": [
|
||||
"doxa-maps-spa"
|
||||
],
|
||||
|
|
@ -349,7 +349,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-CKJT8BCWZubQKLenstpsz19Kd87akZiO1SGu5+Ma3byRUdyXz0gcjrtmmkQxzw7i\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"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-v2Dwy2XYwI0BWeBSSU+eMjQwfQOoPazHYADsRmth6eQ3xjpSiHh0GEyQgvwLIGx7\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
@ -956,7 +956,7 @@
|
|||
"bundle": "plugin-studio",
|
||||
"scriptUrl": "./plugin-studio/plugin-studio.js",
|
||||
"output": "dx-maps/plugin-studio/plugin-studio.js",
|
||||
"integrity": "sha384-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD",
|
||||
"integrity": "sha384-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu",
|
||||
"elements": [
|
||||
"plugin-studio"
|
||||
],
|
||||
|
|
@ -987,7 +987,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-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"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-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
|
||||
},
|
||||
"instances": [
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -32,7 +32,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-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD" crossorigin="anonymous"></script>
|
||||
<script src="../plugin-studio.js" integrity="sha384-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
|
|
@ -32,7 +32,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-NsG6VNbCUAcOh9jEf5+8DeaKFm7xRySJO8yIUiE0O0AQ3FhuILru4eBHgaXCPQUD" crossorigin="anonymous"></script>
|
||||
<script src="../../plugin-studio.js" integrity="sha384-hounA2cKrxqGX3ltwUElfV5XW1XSg3lOoSVUTSeOrWw1zTLzyyeR1ywb4fQ/zTsu" crossorigin="anonymous"></script>
|
||||
|
||||
<script>
|
||||
// Mapbox token resolution — the A3 ladder, in precedence order:
|
||||
|
|
|
|||
Loading…
Reference in a new issue