"use strict"; (() => { // src/behaviors/closeDialogOnAnchorClick/index.ts function closeDialogOnAnchorClick(doc) { const handler = (event) => { if (event.defaultPrevented) return; if (event.button !== 0) return; if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; const { target } = event; if (!(target instanceof Element)) return; const anchor = target.closest('a[href^="#"]'); if (!anchor) return; const dialog = anchor.closest("dialog"); if (!dialog?.open) return; const href = anchor.getAttribute("href"); const view = doc.defaultView; if (!href || href === "#" || !view) return; event.preventDefault(); const targetHash = anchor.hash; dialog.addEventListener("close", () => { view.requestAnimationFrame(() => { if (view.location.hash === targetHash) { const raw = targetHash.slice(1); let id; try { id = decodeURIComponent(raw); } catch { id = raw; } doc.getElementById(id)?.scrollIntoView(); return; } view.location.hash = targetHash; }); }, { once: true }); dialog.close(); }; doc.addEventListener("click", handler); } // src/behaviors/spaRouter/index.ts function updateSdkData(newDoc, currentDoc) { const newSdkData = newDoc.querySelector("#sdk-website-data"); const currentSdkData = currentDoc.querySelector("#sdk-website-data"); if (!newSdkData || !currentSdkData) { return; } const view = currentDoc.defaultView; if (!view) { return; } if (view.WebsiteSdkRegistry) { view.WebsiteSdkRegistry.reset(); } currentSdkData.textContent = newSdkData.textContent; if (view.WebsiteSdkRegistry && newSdkData.textContent) { try { const sdkData = JSON.parse(newSdkData.textContent); const { websiteData, sdkEntries } = sdkData; if (websiteData?.publishedWebsiteId) { view.WebsiteSdkRegistry.init({ publishedWebsiteId: websiteData.publishedWebsiteId }, document); } if (Array.isArray(sdkEntries)) { sdkEntries.forEach((sdk) => { view.WebsiteSdkRegistry.initSectionSdk({ sectionId: sdk.sectionId, sdkName: sdk.sdkName, configuration: sdk.configuration, sdkKey: sdk.sdkKey }); }); } } catch (error) { console.log(error); } } } function updateMetaTag(attribute, value, newDoc, currentDoc) { const newTag = newDoc.querySelector(`meta[${attribute}="${value}"]`); const currentTag = currentDoc.querySelector(`meta[${attribute}="${value}"]`); if (newTag && currentTag) { currentTag.setAttribute("content", newTag.getAttribute("content") || ""); } else if (newTag && !currentTag) { currentDoc.head.append(newTag.cloneNode(true)); } } function updateMetaTags(newDoc, currentDoc) { updateMetaTag("name", "description", newDoc, currentDoc); updateMetaTag("property", "og:title", newDoc, currentDoc); updateMetaTag("property", "og:description", newDoc, currentDoc); updateMetaTag("property", "og:image", newDoc, currentDoc); updateMetaTag("property", "og:url", newDoc, currentDoc); updateMetaTag("name", "twitter:card", newDoc, currentDoc); updateMetaTag("name", "twitter:title", newDoc, currentDoc); updateMetaTag("name", "twitter:description", newDoc, currentDoc); updateMetaTag("name", "twitter:image", newDoc, currentDoc); const newCanonical = newDoc.querySelector('link[rel="canonical"]'); const currentCanonical = currentDoc.querySelector('link[rel="canonical"]'); if (newCanonical && currentCanonical) { currentCanonical.setAttribute("href", newCanonical.getAttribute("href") || ""); } else if (newCanonical && !currentCanonical) { currentDoc.head.append(newCanonical.cloneNode(true)); } } function getContentElement(doc) { return doc.querySelector("#app"); } function createExecutableScript(doc, source) { const script = doc.createElement("script"); Array.from(source.attributes).forEach((attr) => { script.setAttribute(attr.name, attr.value); }); script.textContent = source.textContent; return script; } function syncBodyScripts(newDoc, currentDoc) { const newAppElement = getContentElement(newDoc); currentDoc.body.querySelectorAll("script[data-spa-script]").forEach((script) => script.remove()); Array.from(newDoc.body.querySelectorAll("script")).filter((script) => !newAppElement?.contains(script)).forEach((script) => { const executable = createExecutableScript(currentDoc, script); executable.setAttribute("data-spa-script", ""); currentDoc.body.appendChild(executable); }); } async function preloadCss(cssPath) { if (!cssPath) { return; } await fetch(cssPath).catch((error) => console.log(`Failed to load css by path "${cssPath}"`, error)); } async function fetchPage(route) { return fetch(route).then((response) => { if (!response.ok) { throw new Error(`Failed to fetch page: ${response.status}`); } return response.text(); }).then((html) => html.replace(/]*>[\s\S]*?<\/noscript>/gi, "")); } function swapMainStyles(doc, cssPath) { const currentStylesElement = doc.querySelector("#main-styles"); if (!currentStylesElement) { console.log("main styles element is not found"); return; } if (currentStylesElement.getAttribute("href") === cssPath) { return; } currentStylesElement.setAttribute("href", cssPath); } async function loadPage(doc, path, routes, assetsMap, pageCache) { const route = routes[path] || routes["/"]; const cssPath = assetsMap[path]?.cssPath || assetsMap["/"]?.cssPath || ""; if (!cssPath) { console.log(`cssPath is not found for route ${route}`); } try { const cached = pageCache.get(path); const htmlPromise = cached ? Promise.resolve(cached.html) : fetchPage(route); const cssPromise = cached ? Promise.resolve() : preloadCss(cssPath); const [html] = await Promise.all([htmlPromise, cssPromise]); const parser = new DOMParser(); const newDoc = parser.parseFromString(html, "text/html"); const newContent = getContentElement(newDoc); const currentContent = getContentElement(doc); if (!newContent || !currentContent) { throw new Error("Invalid page structure: content element is not found!"); } swapMainStyles(doc, cssPath); currentContent.innerHTML = newContent.innerHTML; updateSdkData(newDoc, doc); const newTitle = newDoc.querySelector("title")?.textContent; if (newTitle) { doc.title = newTitle; } updateMetaTags(newDoc, doc); syncBodyScripts(newDoc, doc); if (!cached) { const sdkDataElement = newDoc.querySelector("#sdk-website-data"); pageCache.set(path, { html, title: newTitle || "", appContent: newContent.innerHTML, sdkData: sdkDataElement?.textContent || null }); } } catch (error) { console.log(error); } } function navigate(doc, path, routes, assetsMap, pageCache) { const view = doc.defaultView; if (!view) { return; } view.history.pushState({}, "", path); loadPage(doc, path, routes, assetsMap, pageCache); } function spaRouter(doc) { const dataElement = doc.querySelector("#spa-router-data"); if (!dataElement) { return; } let routerData; try { routerData = JSON.parse(dataElement.textContent || "{}"); } catch (error) { return; } const { routes, assetsMap } = routerData; const mainStylesElement = doc.querySelector("#main-styles"); if (!mainStylesElement) { return; } const view = doc.defaultView; if (!view) { return; } const pageCache = /* @__PURE__ */ new Map(); doc.addEventListener("click", (e) => { const target = e.target; const link = target.closest("a[data-page-link]"); if (!link) { return; } e.preventDefault(); const href = link.getAttribute("href"); if (href) { navigate(doc, href, routes, assetsMap, pageCache); } }); view.addEventListener("popstate", () => { loadPage(doc, view.location.pathname, routes, assetsMap, pageCache); }); } // behaviors-virtual:virtual:behaviors var virtual_behaviors_default = [closeDialogOnAnchorClick, spaRouter]; // src/behaviors/index.ts function initWebsiteBehaviors(doc = document) { virtual_behaviors_default.forEach((behavior) => behavior(doc)); } initWebsiteBehaviors(); })();