68 lines
2.7 KiB
TypeScript
68 lines
2.7 KiB
TypeScript
/**
|
|
* Form-Widget bootstrap loader (Phase 05 Task #58).
|
|
*
|
|
* Tenants embed this on their site with:
|
|
*
|
|
* <script src="https://<host>/embed/widget.js" data-form-key="abc123"
|
|
* data-host="https://forms.example.com"
|
|
* async></script>
|
|
*
|
|
* The loader:
|
|
* 1. Reads `data-form-key` and optional `data-host` from its own <script> tag.
|
|
* 2. Inserts a sandboxed <iframe> pointing at `<host>/embed/forms/<formKey>`.
|
|
* 3. Listens for postMessage events from the iframe:
|
|
* - `tcform:resize` -> updates iframe height for dynamic content
|
|
* - `tcform:submitted` / `tcform:error` -> re-emits as
|
|
* CustomEvents on document for parent-site code to listen on.
|
|
*
|
|
* Build-target: hand-crafted minified ES5-compatible JS in
|
|
* `apps/web/public/embed/widget.js`. This file is the readable source
|
|
* kept for documentation + tests. Keep both in sync.
|
|
*/
|
|
|
|
(function () {
|
|
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
const script = (document.currentScript as HTMLScriptElement | null) ?? findSelf();
|
|
if (!script) return;
|
|
|
|
const formKey = script.getAttribute("data-form-key");
|
|
if (!formKey) return;
|
|
|
|
const explicitHost = script.getAttribute("data-host");
|
|
const defaultHost = new URL(script.src).origin;
|
|
const host = explicitHost ?? defaultHost;
|
|
|
|
const iframe = document.createElement("iframe");
|
|
iframe.src = host + "/embed/forms/" + encodeURIComponent(formKey) + "?origin=" + encodeURIComponent(location.origin);
|
|
iframe.setAttribute("title", "Form");
|
|
iframe.setAttribute("loading", "lazy");
|
|
iframe.setAttribute("sandbox", "allow-scripts allow-forms allow-same-origin");
|
|
iframe.style.cssText = "border:0;width:100%;min-height:200px;max-width:100%;display:block";
|
|
|
|
const parent = script.parentNode;
|
|
if (!parent) return;
|
|
parent.insertBefore(iframe, script.nextSibling);
|
|
|
|
window.addEventListener("message", (event) => {
|
|
if (event.source !== iframe.contentWindow) return;
|
|
const data = event.data;
|
|
if (!data || typeof data !== "object" || typeof data.type !== "string") return;
|
|
if (data.type === "tcform:resize" && typeof data.height === "number") {
|
|
iframe.style.height = Math.max(100, Math.min(8000, data.height)) + "px";
|
|
return;
|
|
}
|
|
if (data.type === "tcform:submitted" || data.type === "tcform:error") {
|
|
document.dispatchEvent(new CustomEvent(data.type, { detail: data }));
|
|
}
|
|
});
|
|
|
|
function findSelf(): HTMLScriptElement | null {
|
|
const scripts = document.getElementsByTagName("script");
|
|
for (let i = scripts.length - 1; i >= 0; i--) {
|
|
const s = scripts[i];
|
|
if (s.src && s.src.indexOf("/embed/widget.js") !== -1) return s;
|
|
}
|
|
return null;
|
|
}
|
|
})();
|