diff --git a/shared/static/scripts/sx.js b/shared/static/scripts/sx.js index 0ecf760..43ac749 100644 --- a/shared/static/scripts/sx.js +++ b/shared/static/scripts/sx.js @@ -1342,9 +1342,56 @@ var text = s.textContent; if (!text || !text.trim()) continue; - // data-components: load as component definitions + // data-components: load as component definitions (with localStorage caching) if (s.hasAttribute("data-components")) { - Sx.loadComponents(text); + var hash = s.getAttribute("data-hash"); + if (hash) { + var hasInline = text && text.trim(); + try { + var cachedHash = localStorage.getItem("sx-components-hash"); + if (cachedHash === hash) { + // Cache hit + if (hasInline) { + // Server sent full source (cookie was missing/stale) — update cache + localStorage.setItem("sx-components-src", text); + Sx.loadComponents(text); + } else { + // Server omitted source — load from cache + var cached = localStorage.getItem("sx-components-src"); + if (cached) { + Sx.loadComponents(cached); + } else { + // Cache entry missing — clear cookie and reload to get full source + _clearSxCompCookie(); + location.reload(); + return; + } + } + } else { + // Cache miss — hash mismatch + if (hasInline) { + // Server sent full source — parse and cache + localStorage.setItem("sx-components-hash", hash); + localStorage.setItem("sx-components-src", text); + Sx.loadComponents(text); + } else { + // Server omitted source but our cache is stale — clear and reload + localStorage.removeItem("sx-components-hash"); + localStorage.removeItem("sx-components-src"); + _clearSxCompCookie(); + location.reload(); + return; + } + } + } catch (e) { + // localStorage unavailable — fall back to inline + if (hasInline) Sx.loadComponents(text); + } + _setSxCompCookie(hash); + } else { + // Legacy: no hash attribute — just load inline + if (text && text.trim()) Sx.loadComponents(text); + } continue; } @@ -2396,6 +2443,18 @@ return text; } + // --------------------------------------------------------------------------- + // sx-comp-hash cookie helpers (component caching) + // --------------------------------------------------------------------------- + + function _setSxCompCookie(hash) { + document.cookie = "sx-comp-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax"; + } + + function _clearSxCompCookie() { + document.cookie = "sx-comp-hash=;path=/;max-age=0;SameSite=Lax"; + } + if (typeof document !== "undefined") { var init = function () { console.log("[sx.js] v" + Sx.VERSION + " init"); diff --git a/shared/sx/helpers.py b/shared/sx/helpers.py index 69f48bb..8c0f827 100644 --- a/shared/sx/helpers.py +++ b/shared/sx/helpers.py @@ -483,7 +483,7 @@ details.group{{overflow:hidden}}details.group>summary{{list-style:none}}details. - + @@ -499,19 +499,26 @@ def sx_page(ctx: dict, page_sx: str, *, renders everything client-side. CSS rules are scanned from the sx source and component defs, then injected as a