accessify-widget 0.3.89 → 0.3.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessify.min.js +1 -1
- package/dist/accessify.min.js.map +1 -1
- package/dist/accessify.mjs +1 -1
- package/dist/{index-ENC35r_t.js → index-Dl6o_Udg.js} +4 -4
- package/dist/{index-ENC35r_t.js.map → index-Dl6o_Udg.js.map} +1 -1
- package/dist/{keyboard-nav-C1Q3z15G.js → keyboard-nav-MhI2buKX.js} +2 -2
- package/dist/{keyboard-nav-C1Q3z15G.js.map → keyboard-nav-MhI2buKX.js.map} +1 -1
- package/dist/{page-structure-Cx-NvY0X.js → page-structure-B6gDlVA_.js} +2 -2
- package/dist/{page-structure-Cx-NvY0X.js.map → page-structure-B6gDlVA_.js.map} +1 -1
- package/dist/{text-simplify-DlypCXzp.js → text-simplify-DTHoxw4e.js} +20 -77
- package/dist/text-simplify-DTHoxw4e.js.map +1 -0
- package/dist/widget.js +1 -1
- package/dist/widget.js.map +1 -1
- package/package.json +1 -1
- package/dist/text-simplify-DlypCXzp.js.map +0 -1
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"text-simplify-DlypCXzp.js","sources":["../src/features/text-simplify.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Text Simplification Feature (Safe Replace Engine)\n// ---------------------------------------------------------------------------\n// Phase 1: Manifest-based precomputed simplification\n// 1. Fetch manifest from /v1/manifest for current page\n// 2. Apply cached variants instantly via leaf-node replacement\n// 3. Live-fallback only for blocks not in manifest\n// Phase 2: Layout-safe replacement with guards + observers\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState, AIService } from '../types';\n\ntype SimplifyLevel = 'einfache' | 'leichte';\n\ninterface TextSimplifyState {\n level: SimplifyLevel;\n}\n\ninterface SavedTextNode {\n node: Text;\n original: string;\n}\n\ninterface SavedParagraph {\n el: HTMLElement;\n originalHtml: string;\n savedTextNodes: SavedTextNode[];\n ancestorPatches: AncestorPatch[];\n}\n\ninterface AncestorPatch {\n el: HTMLElement;\n property: string;\n originalValue: string;\n}\n\ninterface ManifestBlock {\n selector: string;\n blockHash: string;\n result: string;\n originalText?: string; // For staleness check on dynamic pages\n}\n\ntype ResimplifyMode = 'manual' | 'auto';\n\ninterface RuntimeManifest {\n url: string;\n siteKey: string;\n feature: string;\n variant: string;\n blocks: ManifestBlock[];\n generatedAt: string;\n contentHash: string;\n siteMode?: ResimplifyMode; // undefined = treated as manual (safe default)\n}\n\nexport default function createTextSimplifyModule(\n aiService?: AIService,\n lang: string = 'de',\n options?: { siteKey?: string; proxyUrl?: string; simplificationLevel?: SimplifyLevel } | SimplifyLevel,\n): FeatureModule {\n let enabled = false;\n const defaultLevel = typeof options === 'string' ? options\n : (options as any)?.simplificationLevel || undefined;\n let level: SimplifyLevel = defaultLevel || 'einfache';\n let savedParagraphs: SavedParagraph[] = [];\n let abortController: AbortController | null = null;\n let overlayEl: HTMLDivElement | null = null;\n let skippedBlocks = 0;\n\n let resizeObserver: ResizeObserver | null = null;\n let mutationObserver: MutationObserver | null = null;\n // Current site's re-simplify mode. Set from manifest response on every run.\n // 'manual' (default) = never call live AI for unknown blocks.\n // 'auto' = live AI fallback + D1 auto-persist is allowed.\n let currentSiteMode: ResimplifyMode = 'manual';\n\n // Map from element to pre-replacement dimensions for resize revert checks\n const preReplaceDimensions = new Map<HTMLElement, { scrollHeight: number; clientHeight: number }>();\n\n const STORAGE_KEY = 'accessify-text-simplify';\n const SIMPLIFIED_ATTR = 'data-accessify-simplified';\n const ORIGINAL_ATTR = 'data-accessify-original';\n const BLOCK_HASH_ATTR = 'data-accessify-block-hash';\n\n // -------------------------------------------------------------------------\n // Client-side IndexedDB cache for instant reload\n // -------------------------------------------------------------------------\n\n const CLIENT_CACHE_DB = 'accessify-simplify-cache';\n const CLIENT_CACHE_STORE = 'blocks';\n const CLIENT_CACHE_VERSION = 1;\n\n function openClientCache(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(CLIENT_CACHE_DB, CLIENT_CACHE_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(CLIENT_CACHE_STORE)) {\n db.createObjectStore(CLIENT_CACHE_STORE);\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n }\n\n async function getClientCached(key: string): Promise<string | null> {\n try {\n const db = await openClientCache();\n return new Promise((resolve) => {\n const tx = db.transaction(CLIENT_CACHE_STORE, 'readonly');\n const store = tx.objectStore(CLIENT_CACHE_STORE);\n const req = store.get(key);\n req.onsuccess = () => resolve(req.result ?? null);\n req.onerror = () => resolve(null);\n });\n } catch { return null; }\n }\n\n async function setClientCached(key: string, value: string): Promise<void> {\n try {\n const db = await openClientCache();\n const tx = db.transaction(CLIENT_CACHE_STORE, 'readwrite');\n tx.objectStore(CLIENT_CACHE_STORE).put(value, key);\n } catch { /* ignore */ }\n }\n\n async function deleteClientCached(key: string): Promise<void> {\n try {\n const db = await openClientCache();\n const tx = db.transaction(CLIENT_CACHE_STORE, 'readwrite');\n tx.objectStore(CLIENT_CACHE_STORE).delete(key);\n } catch { /* ignore */ }\n }\n\n /** Clear ALL client-cached entries for the current page+level.\n * Used when a new server manifest is available to prevent stale hallucinations. */\n async function clearClientCacheForPage(): Promise<void> {\n try {\n const db = await openClientCache();\n const tx = db.transaction(CLIENT_CACHE_STORE, 'readwrite');\n const store = tx.objectStore(CLIENT_CACHE_STORE);\n const pageUrl = window.location.origin + window.location.pathname;\n const prefix = `${pageUrl}:simplify:${level}:`;\n\n // IDBObjectStore doesn't support prefix queries natively,\n // so we iterate all keys and delete matching ones\n const req = store.openCursor();\n req.onsuccess = () => {\n const cursor = req.result;\n if (!cursor) return;\n if (typeof cursor.key === 'string' && cursor.key.startsWith(prefix)) {\n cursor.delete();\n }\n cursor.continue();\n };\n } catch { /* ignore */ }\n }\n\n function clientCacheKey(blockHash: string): string {\n const pageUrl = window.location.origin + window.location.pathname;\n return `${pageUrl}:simplify:${level}:${blockHash}`;\n }\n\n // -------------------------------------------------------------------------\n // Resolve config from the script tag or global config\n // -------------------------------------------------------------------------\n\n function getConfig(): { siteKey?: string; proxyUrl?: string } {\n const script = document.querySelector('script[data-site-key]');\n const siteKey = script?.getAttribute('data-site-key') ||\n (window as any).Accessify?.config?.siteKey || '';\n const proxyUrl = script?.getAttribute('data-proxy-url') ||\n (window as any).Accessify?.config?.proxyUrl || '';\n return { siteKey: siteKey || undefined, proxyUrl: proxyUrl || undefined };\n }\n\n // -------------------------------------------------------------------------\n // Find text-heavy elements on the page\n // -------------------------------------------------------------------------\n\n /**\n * FAQ/Accordion safety: these containers must NOT be treated as a single\n * simplify block. Instead, we descend into their children (question vs answer).\n */\n // FAQ / Accordion / Disclosure containers — must NEVER be simplified as one block.\n // Covers: native <details>, ARIA patterns, common class-name conventions,\n // component libraries (Radix, Headless UI, MUI, Bootstrap), and generic\n // collapsible widgets. Matched via .closest() so only the *container* is detected.\n const FAQ_CONTAINER_SELECTORS = [\n 'details',\n '[role=\"region\"][aria-labelledby]',\n '[aria-expanded]',\n '[data-state=\"open\"]',\n '[data-state=\"closed\"]',\n '[class*=\"accordion\" i]',\n '[class*=\"faq\" i]',\n '[class*=\"disclosure\" i]',\n '[class*=\"expandable\" i]',\n '[class*=\"collapsible\" i]',\n '[class*=\"collapse\" i]',\n ].join(', ');\n const FAQ_SKIP_SELECTORS = 'summary, [role=\"button\"], .accordion-header, .accordion__header, .faq-question';\n\n /** Lines that are photo credits, attributions, or metadata — not actual content.\n * These should NOT be simplified (risk of hallucination on short context). */\n const CREDIT_LINE_PATTERN = /^(Bild|Foto|Photo|Image|Fotocredit|Credit|Text|Autor|Author|Quelle|Source|Copyright|©|\\(c\\))\\s*[:·\\-–—]/i;\n\n function getTextElements(): HTMLElement[] {\n const selectors = 'h1, h2, h3, h4, h5, h6, p, li, td, th, blockquote, figcaption, .hero-subtitle, summary, dt, dd';\n const elements: HTMLElement[] = [];\n const seen = new Set<HTMLElement>();\n\n // Scan the entire page — the manifest acts as the real filter.\n // Only blocks whose hash matches a manifest entry get replaced;\n // everything else (nav, footer, sidebar) is skipped automatically.\n // This avoids brittle content-root heuristics that break on Framer,\n // Webflow, Shopify, and other non-standard DOM structures.\n document.body.querySelectorAll(selectors).forEach((el) => {\n const htmlEl = el as HTMLElement;\n if (htmlEl.closest('#accessify-root')) return;\n // Skip truly hidden elements, but allow Framer scroll-animated ones\n // (they have offsetParent===null due to opacity:0 / will-change but ARE real content)\n if (htmlEl.offsetParent === null && htmlEl.style.position !== 'fixed') {\n const isFramerAnimated = htmlEl.closest('[data-framer-appear-id]') || htmlEl.closest('[data-framer-name]');\n if (!isFramerAnimated) return;\n }\n // Freeze the original text on first encounter — this ensures we always\n // hash the real page text, never text that was already replaced by us.\n // This prevents the \"simplified text stored as original\" corruption loop.\n if (!htmlEl.dataset.accessifyOriginal) {\n htmlEl.dataset.accessifyOriginal = htmlEl.textContent?.trim() || '';\n }\n const text = htmlEl.dataset.accessifyOriginal;\n if (text.length < 20) return;\n // Skip short photo credits / attribution lines (high hallucination risk)\n if (text.length < 60 && CREDIT_LINE_PATTERN.test(text)) return;\n if (seen.has(htmlEl)) return;\n\n // FAQ safety: skip elements whose parent is an FAQ container if the\n // element itself is a question/toggle (those are handled separately)\n // This prevents question+answer from being merged into one block.\n const inFaqContainer = htmlEl.closest(FAQ_CONTAINER_SELECTORS);\n if (inFaqContainer) {\n // Inside an FAQ container: only collect leaf text elements,\n // not the container itself. Skip if this element contains\n // both question and answer content (too risky to simplify as one).\n const childBlocks = htmlEl.querySelectorAll('p, li, dd, dt, summary');\n if (childBlocks.length > 1) {\n // This element wraps multiple sub-blocks — skip it, let children be collected\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.log('[Accessify] FAQ: skipping wrapper, will collect children:', htmlEl.tagName);\n }\n return;\n }\n }\n\n let dominated = false;\n for (const s of seen) {\n if (s.contains(htmlEl)) { dominated = true; break; }\n }\n if (dominated) return;\n seen.add(htmlEl);\n elements.push(htmlEl);\n });\n\n return elements;\n }\n\n // -------------------------------------------------------------------------\n // Block hash — DJB2, same as server side\n // -------------------------------------------------------------------------\n\n function hashText(text: string): string {\n const normalized = text.replace(/\\s+/g, ' ').trim().toLowerCase();\n let hash = 5381;\n for (let i = 0; i < normalized.length; i++) {\n hash = ((hash << 5) + hash + normalized.charCodeAt(i)) & 0x7fffffff;\n }\n return hash.toString(36);\n }\n\n // -------------------------------------------------------------------------\n // Staleness check — compare current page text with DB original\n // -------------------------------------------------------------------------\n\n /**\n * Fast character-diff count between two normalized strings.\n * Uses Levenshtein distance for short strings, falls back to\n * a simple diff-count for longer texts (performance).\n */\n function charDiff(a: string, b: string): number {\n const na = a.replace(/\\s+/g, ' ').trim();\n const nb = b.replace(/\\s+/g, ' ').trim();\n\n // Fast path: identical\n if (na === nb) return 0;\n\n // For very long strings, use a quick heuristic (length diff + sample comparison)\n if (na.length > 500 || nb.length > 500) {\n const lenDiff = Math.abs(na.length - nb.length);\n if (lenDiff > 3) return lenDiff;\n // Compare char-by-char up to the shorter length\n let diffs = lenDiff;\n const minLen = Math.min(na.length, nb.length);\n for (let i = 0; i < minLen; i++) {\n if (na[i] !== nb[i]) diffs++;\n if (diffs > 3) return diffs; // early exit\n }\n return diffs;\n }\n\n // Levenshtein distance for shorter strings (accurate)\n const m = na.length;\n const n = nb.length;\n // Early exit if length diff alone exceeds threshold\n if (Math.abs(m - n) > 3) return Math.abs(m - n);\n\n const dp: number[] = Array.from({ length: n + 1 }, (_, i) => i);\n for (let i = 1; i <= m; i++) {\n let prev = dp[0];\n dp[0] = i;\n for (let j = 1; j <= n; j++) {\n const temp = dp[j];\n dp[j] = na[i - 1] === nb[j - 1]\n ? prev\n : 1 + Math.min(prev, dp[j], dp[j - 1]);\n prev = temp;\n }\n // Early exit if minimum possible distance exceeds threshold\n if (Math.min(...dp) > 3) return 4;\n }\n return dp[n];\n }\n\n const STALENESS_THRESHOLD = 3; // max char-diff to still accept cached version\n\n // -------------------------------------------------------------------------\n // Leaf text node replacement — preserves inline markup\n // -------------------------------------------------------------------------\n\n function getLeafTextNodes(root: Node): Text[] {\n const textNodes: Text[] = [];\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);\n let node: Text | null;\n while ((node = walker.nextNode() as Text | null)) {\n const trimmed = node.nodeValue?.trim();\n if (trimmed && trimmed.length > 0) {\n textNodes.push(node);\n }\n }\n return textNodes;\n }\n\n /**\n * Replace leaf text nodes within an element with simplified text.\n * The simplified text is distributed across existing text nodes proportionally,\n * preserving the surrounding inline markup structure.\n *\n * Strategy: if there is only one meaningful text node, replace it directly.\n * If there are multiple text nodes, split the simplified text into sentences\n * and distribute them proportionally across the existing text nodes.\n */\n function replaceLeafTextNodes(el: HTMLElement, simplifiedText: string): void {\n const textNodes = getLeafTextNodes(el);\n if (textNodes.length === 0) return;\n\n if (textNodes.length === 1) {\n // Single text node — straightforward replacement\n textNodes[0].nodeValue = simplifiedText;\n return;\n }\n\n // Multiple text nodes: distribute simplified text proportionally\n // Split simplified text into segments by sentence boundaries\n const sentences = simplifiedText.match(/[^.!?]+[.!?]*\\s*/g) || [simplifiedText];\n\n // Calculate original character weight per text node\n const totalOriginalLen = textNodes.reduce((sum, n) => sum + (n.nodeValue?.trim().length || 0), 0);\n\n if (totalOriginalLen === 0) {\n // Fallback: put all simplified text in first node, clear others\n textNodes[0].nodeValue = simplifiedText;\n for (let i = 1; i < textNodes.length; i++) {\n textNodes[i].nodeValue = '';\n }\n return;\n }\n\n // Distribute sentences across text nodes based on character weight\n let sentenceIndex = 0;\n for (let i = 0; i < textNodes.length; i++) {\n const nodeWeight = (textNodes[i].nodeValue?.trim().length || 0) / totalOriginalLen;\n const sentenceCount = Math.max(1, Math.round(nodeWeight * sentences.length));\n\n const chunk = sentences.slice(sentenceIndex, sentenceIndex + sentenceCount).join('');\n textNodes[i].nodeValue = chunk || '';\n sentenceIndex += sentenceCount;\n }\n\n // If there are leftover sentences, append to the last non-empty node\n if (sentenceIndex < sentences.length) {\n const lastNode = textNodes[textNodes.length - 1];\n lastNode.nodeValue = (lastNode.nodeValue || '') + sentences.slice(sentenceIndex).join('');\n }\n }\n\n // -------------------------------------------------------------------------\n // Layout Guard — detect overflow/clipping after replacement\n // -------------------------------------------------------------------------\n\n function measureElement(el: HTMLElement): { scrollHeight: number; clientHeight: number } {\n return { scrollHeight: el.scrollHeight, clientHeight: el.clientHeight };\n }\n\n /**\n * Check if an element or its ancestors have overflow:hidden with fixed height\n * that would clip expanded content.\n */\n function findClippingAncestor(el: HTMLElement): HTMLElement | null {\n let current: HTMLElement | null = el;\n while (current && current !== document.body) {\n const style = getComputedStyle(current);\n const overflow = style.overflow + ' ' + style.overflowY;\n const hasHiddenOverflow = overflow.includes('hidden') || overflow.includes('clip');\n const hasFixedHeight = style.maxHeight !== 'none' || (\n style.height !== 'auto' && style.height !== '' && !style.height.includes('%')\n );\n if (hasHiddenOverflow && hasFixedHeight) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n }\n\n /**\n * Check layout safety after a replacement. Returns true if safe, false if clipping detected.\n * Attempts minimal ancestor patches to resolve clipping before giving up.\n */\n function checkLayoutSafety(el: HTMLElement): { safe: boolean; patches: AncestorPatch[] } {\n const patches: AncestorPatch[] = [];\n\n // Check the element itself for overflow\n const after = measureElement(el);\n const isElementOverflowing = after.scrollHeight > after.clientHeight + 2; // 2px tolerance\n\n if (!isElementOverflowing) {\n // Also check for clipping ancestors\n const clipAncestor = findClippingAncestor(el);\n if (!clipAncestor) return { safe: true, patches: [] };\n\n const ancestorAfter = measureElement(clipAncestor);\n if (ancestorAfter.scrollHeight <= ancestorAfter.clientHeight + 2) {\n return { safe: true, patches: [] };\n }\n\n // Try patching the ancestor\n return tryAncestorPatches(clipAncestor, patches);\n }\n\n // Element itself is overflowing — check if a parent is clipping it\n const clipAncestor = findClippingAncestor(el);\n if (!clipAncestor) {\n // No clipping ancestor — overflow is fine (content just grows naturally)\n return { safe: true, patches: [] };\n }\n\n return tryAncestorPatches(clipAncestor, patches);\n }\n\n function tryAncestorPatches(\n ancestor: HTMLElement,\n patches: AncestorPatch[],\n ): { safe: boolean; patches: AncestorPatch[] } {\n const style = getComputedStyle(ancestor);\n\n // Try removing max-height\n if (style.maxHeight !== 'none') {\n patches.push({\n el: ancestor,\n property: 'maxHeight',\n originalValue: ancestor.style.maxHeight,\n });\n ancestor.style.maxHeight = 'none';\n }\n\n // Try setting overflow to visible\n if (style.overflow.includes('hidden') || style.overflowY.includes('hidden')) {\n patches.push({\n el: ancestor,\n property: 'overflow',\n originalValue: ancestor.style.overflow,\n });\n ancestor.style.overflow = 'visible';\n }\n\n // Re-check after patches\n const afterPatch = measureElement(ancestor);\n if (afterPatch.scrollHeight <= afterPatch.clientHeight + 2) {\n return { safe: true, patches };\n }\n\n // Patches didn't fix it — revert them\n revertPatches(patches);\n return { safe: false, patches: [] };\n }\n\n function revertPatches(patches: AncestorPatch[]) {\n for (const patch of patches) {\n (patch.el.style as any)[patch.property] = patch.originalValue;\n }\n }\n\n // -------------------------------------------------------------------------\n // Observers — ResizeObserver + MutationObserver\n // -------------------------------------------------------------------------\n\n function setupResizeObserver() {\n if (resizeObserver) return;\n\n resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n if (!el.hasAttribute(SIMPLIFIED_ATTR)) continue;\n\n const saved = savedParagraphs.find((sp) => sp.el === el);\n if (!saved) continue;\n\n // Check if a layout change caused clipping\n const clipAncestor = findClippingAncestor(el);\n if (clipAncestor) {\n const dims = measureElement(clipAncestor);\n if (dims.scrollHeight > dims.clientHeight + 2) {\n // External layout change caused clipping — revert this block\n console.warn(\n '[Accessify] ResizeObserver detected clipping after external layout change, reverting block:',\n el,\n );\n revertSingleBlock(saved);\n skippedBlocks++;\n }\n }\n }\n });\n }\n\n function setupMutationObserver() {\n if (mutationObserver) return;\n\n mutationObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n // Check if any removed nodes were tracked simplified blocks\n for (const removed of mutation.removedNodes) {\n if (!(removed instanceof HTMLElement)) continue;\n const idx = savedParagraphs.findIndex((sp) => sp.el === removed || removed.contains(sp.el));\n if (idx !== -1) {\n const saved = savedParagraphs[idx];\n // Element was removed from DOM by the page itself — clean up tracking\n resizeObserver?.unobserve(saved.el);\n saved.el.removeAttribute(SIMPLIFIED_ATTR);\n saved.el.removeAttribute(ORIGINAL_ATTR);\n saved.el.removeAttribute(BLOCK_HASH_ATTR);\n if (saved.el.dataset.accessifyOrigTransform) {\n saved.el.style.textTransform = saved.el.dataset.accessifyOrigTransform;\n delete saved.el.dataset.accessifyOrigTransform;\n }\n revertPatches(saved.ancestorPatches);\n savedParagraphs.splice(idx, 1);\n }\n }\n\n // Check if a simplified element's content was changed externally\n if (mutation.type === 'characterData' || mutation.type === 'childList') {\n const target = mutation.target instanceof HTMLElement\n ? mutation.target\n : mutation.target.parentElement;\n if (!target) continue;\n\n const simplifiedEl = target.closest(`[${SIMPLIFIED_ATTR}]`) as HTMLElement | null;\n if (simplifiedEl) {\n const saved = savedParagraphs.find((sp) => sp.el === simplifiedEl);\n if (saved && !simplifiedEl.hasAttribute('data-accessify-replacing')) {\n // External mutation on a simplified block — clean up\n console.warn(\n '[Accessify] External mutation detected on simplified block, cleaning up tracking:',\n simplifiedEl,\n );\n resizeObserver?.unobserve(saved.el);\n saved.el.removeAttribute(SIMPLIFIED_ATTR);\n saved.el.removeAttribute(ORIGINAL_ATTR);\n saved.el.removeAttribute(BLOCK_HASH_ATTR);\n if (saved.el.dataset.accessifyOrigTransform) {\n saved.el.style.textTransform = saved.el.dataset.accessifyOrigTransform;\n delete saved.el.dataset.accessifyOrigTransform;\n }\n revertPatches(saved.ancestorPatches);\n savedParagraphs = savedParagraphs.filter((sp) => sp.el !== simplifiedEl);\n }\n }\n }\n }\n });\n\n mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n\n function disconnectObservers() {\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n if (mutationObserver) {\n mutationObserver.disconnect();\n mutationObserver = null;\n }\n preReplaceDimensions.clear();\n }\n\n // -------------------------------------------------------------------------\n // Safe replacement — leaf nodes + layout guard\n // -------------------------------------------------------------------------\n\n function safeReplace(\n el: HTMLElement,\n simplifiedText: string,\n blockHash?: string,\n ): boolean {\n // Save original — both innerHTML (fallback) and individual text nodes (preferred)\n const originalHtml = el.innerHTML;\n const textNodesBefore = getLeafTextNodes(el);\n const savedTextNodes: SavedTextNode[] = textNodesBefore.map(n => ({\n node: n,\n original: n.data,\n }));\n\n // Guard flag to prevent MutationObserver from treating our own replacement as external\n el.setAttribute('data-accessify-replacing', 'true');\n\n // Perform leaf text node replacement (preserves inline markup)\n // ONLY sets textNode.nodeValue — never modifies DOM structure\n replaceLeafTextNodes(el, simplifiedText);\n\n // Check layout safety\n const { safe, patches } = checkLayoutSafety(el);\n\n if (!safe) {\n // Revert — restore via text node .data (React/Framer-safe)\n for (const saved of savedTextNodes) {\n if (saved.node.parentNode) saved.node.data = saved.original;\n }\n setTimeout(() => el.removeAttribute('data-accessify-replacing'), 0);\n console.warn(\n '[Accessify] Block skipped — layout clipping detected after replacement:',\n el.textContent?.slice(0, 60),\n );\n skippedBlocks++;\n return false;\n }\n\n // Replacement is safe — finalize\n el.setAttribute(SIMPLIFIED_ATTR, 'true');\n el.setAttribute(ORIGINAL_ATTR, originalHtml);\n if (blockHash) {\n el.setAttribute(BLOCK_HASH_ATTR, blockHash);\n }\n\n // Reset CSS text-transform so simplified text displays as-authored\n // (many sites apply uppercase/capitalize to headings/buttons)\n // Use setProperty with !important to override site CSS that uses !important\n const computed = window.getComputedStyle(el);\n if (computed.textTransform && computed.textTransform !== 'none') {\n el.dataset.accessifyOrigTransform = computed.textTransform;\n el.style.setProperty('text-transform', 'none', 'important');\n }\n\n // Walk up ancestors and reset inherited text-transform (e.g. uppercase on parent container)\n // Stop at sectioning elements to avoid global side-effects\n let ancestor = el.parentElement;\n const stopTags = new Set(['ARTICLE', 'SECTION', 'MAIN', 'BODY', 'HTML']);\n while (ancestor && !stopTags.has(ancestor.tagName)) {\n if (ancestor.closest('#accessify-root')) break;\n const ancestorComputed = window.getComputedStyle(ancestor);\n if (ancestorComputed.textTransform && ancestorComputed.textTransform !== 'none') {\n if (!ancestor.dataset.accessifyOrigTransform) {\n ancestor.dataset.accessifyOrigTransform = ancestorComputed.textTransform;\n ancestor.style.setProperty('text-transform', 'none', 'important');\n }\n } else {\n break; // no inherited text-transform from here up\n }\n ancestor = ancestor.parentElement;\n }\n\n // Normalize heading styles so simplified content reads as body text\n const headingTags = new Set(['H1', 'H2', 'H3', 'H4', 'H5', 'H6']);\n if (headingTags.has(el.tagName)) {\n el.dataset.accessifyOrigFontSize = el.style.fontSize || '';\n el.dataset.accessifyOrigFontWeight = el.style.fontWeight || '';\n const bodyComputed = window.getComputedStyle(document.body);\n const bodyFontSize = bodyComputed.fontSize || '16px';\n el.style.setProperty('font-size', bodyFontSize, 'important');\n el.style.setProperty('font-weight', 'normal', 'important');\n }\n\n savedParagraphs.push({ el, originalHtml, savedTextNodes, ancestorPatches: patches });\n\n // Observe for future layout changes\n resizeObserver?.observe(el);\n\n // Remove guard flag AFTER MutationObserver has processed current mutations\n setTimeout(() => el.removeAttribute('data-accessify-replacing'), 0);\n\n return true;\n }\n\n /**\n * Revert a single block — used by ResizeObserver when external layout changes cause clipping.\n */\n function revertSingleBlock(saved: SavedParagraph) {\n // Prefer text-node restore (React/Framer-safe: no DOM structure change)\n if (saved.savedTextNodes.length > 0) {\n for (const sn of saved.savedTextNodes) {\n if (sn.node.parentNode) sn.node.data = sn.original;\n }\n } else {\n // Fallback to innerHTML if text nodes are gone (framework re-rendered)\n saved.el.innerHTML = saved.originalHtml;\n }\n saved.el.removeAttribute(SIMPLIFIED_ATTR);\n saved.el.removeAttribute(ORIGINAL_ATTR);\n saved.el.removeAttribute(BLOCK_HASH_ATTR);\n // Restore original text-transform if we overrode it\n if (saved.el.dataset.accessifyOrigTransform) {\n saved.el.style.textTransform = saved.el.dataset.accessifyOrigTransform;\n delete saved.el.dataset.accessifyOrigTransform;\n }\n // Restore heading styles if we normalized them\n if (saved.el.dataset.accessifyOrigFontSize !== undefined) {\n saved.el.style.fontSize = saved.el.dataset.accessifyOrigFontSize;\n delete saved.el.dataset.accessifyOrigFontSize;\n }\n if (saved.el.dataset.accessifyOrigFontWeight !== undefined) {\n saved.el.style.fontWeight = saved.el.dataset.accessifyOrigFontWeight;\n delete saved.el.dataset.accessifyOrigFontWeight;\n }\n // Clean up ancestor text-transform overrides (only if no other simplified blocks reference them)\n document.querySelectorAll<HTMLElement>('[data-accessify-orig-transform]').forEach(ancestorEl => {\n if (ancestorEl.closest('#accessify-root')) return;\n if (!ancestorEl.hasAttribute(SIMPLIFIED_ATTR)) {\n const hasSimplifiedChild = ancestorEl.querySelector(`[${SIMPLIFIED_ATTR}]`);\n if (!hasSimplifiedChild) {\n ancestorEl.style.textTransform = ancestorEl.dataset.accessifyOrigTransform!;\n delete ancestorEl.dataset.accessifyOrigTransform;\n }\n }\n });\n revertPatches(saved.ancestorPatches);\n resizeObserver?.unobserve(saved.el);\n savedParagraphs = savedParagraphs.filter((sp) => sp.el !== saved.el);\n }\n\n // -------------------------------------------------------------------------\n // Fetch manifest from API\n // -------------------------------------------------------------------------\n\n // In-memory manifest cache to avoid refetching on toggle\n const manifestCache = new Map<string, RuntimeManifest | null>();\n\n async function fetchManifest(siteKey: string, proxyUrl?: string): Promise<RuntimeManifest | null> {\n const cacheKey = `${siteKey}:${level}`;\n if (manifestCache.has(cacheKey)) return manifestCache.get(cacheKey)!;\n\n const base = proxyUrl || 'https://accessify-api.accessify.workers.dev';\n const pageUrl = encodeURIComponent(window.location.origin + window.location.pathname);\n const url = `${base}/v1/manifest?siteKey=${siteKey}&url=${pageUrl}&feature=simplify&variant=${level}`;\n\n try {\n const res = await fetch(url, { cache: 'no-cache' });\n if (!res.ok) { manifestCache.set(cacheKey, null); return null; }\n const data = await res.json() as RuntimeManifest & { miss?: boolean };\n // Always update mode from server — this is the authoritative signal that\n // tells the widget whether live AI fallback is permitted for this site.\n currentSiteMode = data.siteMode === 'auto' ? 'auto' : 'manual';\n const result = data.blocks?.length ? data : null;\n manifestCache.set(cacheKey, result);\n return result;\n } catch {\n manifestCache.set(cacheKey, null);\n return null;\n }\n }\n\n // -------------------------------------------------------------------------\n // Apply manifest blocks to the page (safe replacement)\n // -------------------------------------------------------------------------\n\n function applyManifestBlocks(\n manifest: RuntimeManifest,\n elements: HTMLElement[],\n ): { applied: HTMLElement[]; remaining: HTMLElement[]; stale: HTMLElement[] } {\n const applied: HTMLElement[] = [];\n const remaining: HTMLElement[] = [];\n const stale: HTMLElement[] = [];\n\n // Build lookups by block hash AND by CSS selector for fuzzy matching\n const byHash = new Map<string, ManifestBlock>();\n const bySelector = new Map<string, ManifestBlock>();\n for (const block of manifest.blocks) {\n byHash.set(block.blockHash, block);\n if (block.selector) {\n bySelector.set(block.selector, block);\n }\n }\n\n for (const el of elements) {\n const text = el.dataset.accessifyOriginal || el.textContent?.trim() || '';\n const elHash = hashText(text);\n\n // --- Phase A: Exact hash match (text unchanged) ---\n const exactMatch = byHash.get(elHash);\n if (exactMatch?.result) {\n const success = safeReplace(el, exactMatch.result, elHash);\n if (success) {\n applied.push(el);\n } else {\n remaining.push(el);\n }\n continue;\n }\n\n // --- Phase B: Selector-based fuzzy match (text may have changed slightly) ---\n // Try to find this element in the manifest by CSS selector\n let fuzzyMatch: ManifestBlock | undefined;\n for (const [selector, block] of bySelector) {\n try {\n if (el.matches(selector) || el.closest(selector) === el) {\n fuzzyMatch = block;\n break;\n }\n } catch { /* invalid selector, skip */ }\n }\n\n if (fuzzyMatch?.result && fuzzyMatch.originalText) {\n const diff = charDiff(text, fuzzyMatch.originalText);\n if (diff <= STALENESS_THRESHOLD) {\n // Minor change (typo fix, date update) — cached simplification still valid\n const success = safeReplace(el, fuzzyMatch.result, elHash);\n if (success) {\n applied.push(el);\n } else {\n remaining.push(el);\n }\n } else {\n // Text changed significantly — simplification is stale, needs AI refresh\n console.info(\n `[Accessify] Stale block (diff=${diff}):`,\n text.slice(0, 50) + '…',\n );\n stale.push(el);\n }\n continue;\n }\n\n // No match at all — goes to live AI or stays unsimplified\n remaining.push(el);\n }\n\n return { applied, remaining, stale };\n }\n\n // -------------------------------------------------------------------------\n // Live fallback auto-persist — write back to D1+KV\n // -------------------------------------------------------------------------\n\n /** Build a minimal CSS selector for a DOM element so the server can store it */\n function buildSelector(el: HTMLElement): string {\n const tag = el.tagName.toLowerCase();\n // If element has an id, use that (most specific)\n if (el.id) return `#${CSS.escape(el.id)}`;\n // Otherwise use nth-of-type within parent\n const parent = el.parentElement;\n if (!parent) return tag;\n const siblings = Array.from(parent.children).filter(c => c.tagName === el.tagName);\n if (siblings.length === 1) return tag;\n const idx = siblings.indexOf(el) + 1;\n return `${tag}:nth-of-type(${idx})`;\n }\n\n /** Batch buffer: collect blocks, flush once after simplification completes */\n const persistQueue: Array<{\n blockHash: string;\n originalText: string;\n result: string;\n selector: string;\n }> = [];\n let persistFlushTimer: ReturnType<typeof setTimeout> | null = null;\n const persistedHashes = new Set<string>(); // deduplicate across toggle cycles\n\n function persistToManifest(\n siteKey: string,\n blockHash: string,\n originalText: string,\n simplifiedText: string,\n selector: string,\n proxyUrl?: string,\n ): void {\n // Skip if already persisted this session\n if (persistedHashes.has(blockHash)) return;\n persistedHashes.add(blockHash);\n\n persistQueue.push({ blockHash, originalText, result: simplifiedText, selector });\n\n // Debounce: flush 2s after last persist call (batches rapid-fire calls)\n if (persistFlushTimer) clearTimeout(persistFlushTimer);\n persistFlushTimer = setTimeout(() => flushPersistQueue(siteKey, proxyUrl), 2000);\n }\n\n function flushPersistQueue(siteKey: string, proxyUrl?: string): void {\n if (persistQueue.length === 0) return;\n const base = proxyUrl || 'https://accessify-api.accessify.workers.dev';\n const pageUrl = window.location.origin + window.location.pathname;\n const blocks = persistQueue.splice(0);\n\n fetch(`${base}/v1/cache/persist`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Site-Key': siteKey,\n },\n body: JSON.stringify({\n siteKey,\n url: pageUrl,\n feature: 'simplify',\n variant: level,\n blocks,\n }),\n }).then((res) => {\n if (res.ok) {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.log(`[Accessify] Persisted ${blocks.length} blocks to D1+KV`);\n }\n } else {\n console.warn(`[Accessify] Persist failed: ${res.status}`);\n }\n }).catch((err) => {\n console.warn('[Accessify] Failed to persist live simplification:', err);\n });\n }\n\n // -------------------------------------------------------------------------\n // Loading overlay on individual elements\n // -------------------------------------------------------------------------\n\n function markLoading(el: HTMLElement) {\n el.style.opacity = '0.5';\n el.style.transition = 'opacity 0.3s ease';\n }\n\n function clearLoading(el: HTMLElement) {\n el.style.opacity = '';\n el.style.transition = '';\n }\n\n // -------------------------------------------------------------------------\n // Global progress indicator\n // -------------------------------------------------------------------------\n\n function showProgress(_current: number, _total: number, _skipped: number = 0) {\n // Progress overlay disabled — text appears silently as it's ready\n }\n\n function showDone(_count: number, _fromCache: number) {\n // Silently remove progress overlay — no \"done\" banner needed\n removeProgress();\n }\n\n function showError(msg: string) {\n if (overlayEl) {\n // Build via textContent so any provider/network error text is never\n // interpreted as HTML — prevents script injection via error messages.\n overlayEl.textContent = '';\n const icon = document.createElement('span');\n icon.style.color = '#ef4444';\n icon.textContent = '\\u2715 ';\n overlayEl.appendChild(icon);\n overlayEl.appendChild(document.createTextNode(String(msg ?? '')));\n overlayEl.style.color = '#ef4444';\n setTimeout(() => removeProgress(), 5000);\n }\n }\n\n function removeProgress() {\n overlayEl?.remove();\n overlayEl = null;\n document.getElementById('accessify-autospin-style')?.remove();\n }\n\n // -------------------------------------------------------------------------\n // AI Disclaimer Banner — shown on the actual page (outside shadow DOM)\n // -------------------------------------------------------------------------\n const DISCLAIMER_ID = 'accessify-ai-disclaimer';\n\n function showDisclaimer() {\n if (document.getElementById(DISCLAIMER_ID)) return;\n const text = lang.startsWith('de')\n ? 'KI-vereinfachter Text'\n : 'AI-simplified text';\n\n const banner = document.createElement('div');\n banner.id = DISCLAIMER_ID;\n banner.setAttribute('role', 'status');\n banner.setAttribute('aria-live', 'polite');\n banner.textContent = text;\n Object.assign(banner.style, {\n position: 'fixed',\n bottom: '12px',\n left: '12px',\n zIndex: '2147483640',\n padding: '6px 12px',\n background: 'rgba(30,41,59,0.85)',\n color: '#94a3b8',\n fontSize: '11px',\n fontFamily: '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n borderRadius: '6px',\n pointerEvents: 'none',\n });\n document.body.appendChild(banner);\n }\n\n function removeDisclaimer() {\n document.getElementById(DISCLAIMER_ID)?.remove();\n }\n\n // -------------------------------------------------------------------------\n // Core: simplify page — manifest first, live fallback for misses\n // -------------------------------------------------------------------------\n\n async function simplifyPage() {\n const elements = getTextElements();\n if (elements.length === 0) return;\n\n abortController = new AbortController();\n savedParagraphs = [];\n skippedBlocks = 0;\n\n // Set up observers\n setupResizeObserver();\n setupMutationObserver();\n\n const { siteKey, proxyUrl } = getConfig();\n let fromCache = 0;\n let remaining = elements;\n // Track stale blocks — these MUST be re-generated by AI; if AI fails, skip them\n const staleBlocks = new Set<HTMLElement>();\n\n const DEBUG = !!(window as any).__ACCESSIFY_DEBUG;\n\n // -- Phase 1: Try manifest (instant, no AI calls) -------------------------\n if (siteKey) {\n showProgress(0, elements.length);\n const manifest = await fetchManifest(siteKey, proxyUrl);\n\n if (DEBUG) console.log(`[Accessify] Manifest: ${manifest?.blocks?.length ?? 0} blocks for ${elements.length} elements`);\n\n if (manifest?.blocks?.length) {\n // Server manifest is authoritative — clear old client cache to prevent\n // stale hallucinations from previous live AI runs overriding server data\n await clearClientCacheForPage();\n\n const result = applyManifestBlocks(manifest, elements);\n fromCache = result.applied.length;\n if (DEBUG) console.log(`[Accessify] Manifest hit: ${fromCache}, stale: ${result.stale.length}, remaining: ${result.remaining.length}`);\n // Stale blocks get prepended to remaining so AI handles them\n for (const el of result.stale) staleBlocks.add(el);\n remaining = [...result.stale, ...result.remaining];\n\n // Populate client cache with (correct) manifest results\n for (const block of manifest.blocks) {\n if (block.result) {\n setClientCached(clientCacheKey(block.blockHash), block.result);\n }\n }\n\n if (remaining.length === 0) {\n // All blocks were in the manifest — done instantly\n showDone(fromCache, fromCache);\n return;\n }\n }\n }\n\n // -- Phase 1.5: Check client-side IndexedDB cache --------------------------\n {\n const stillRemaining: HTMLElement[] = [];\n for (const el of remaining) {\n const text = el.dataset.accessifyOriginal || el.textContent?.trim() || '';\n if (text.length < 20) { stillRemaining.push(el); continue; }\n const blockHash = hashText(text);\n const cached = await getClientCached(clientCacheKey(blockHash));\n if (cached) {\n const success = safeReplace(el, cached, blockHash);\n if (success) {\n fromCache++;\n } else {\n stillRemaining.push(el);\n }\n } else {\n stillRemaining.push(el);\n }\n }\n remaining = stillRemaining;\n\n if (remaining.length === 0) {\n showDone(fromCache, fromCache);\n return;\n }\n }\n\n // -- Phase 2: Live fallback for remaining blocks --------------------------\n // SAFETY GATE: When a manifest was loaded with blocks, only stale blocks\n // (content changed since last crawl) should go to live AI. All other\n // remaining blocks (elements not in manifest = nav, footer, sidebar, etc.)\n // are SKIPPED — they were not extracted during crawl and are NOT content.\n //\n // This prevents Framer / SPA sites (which lack <article>/<main>) from\n // sending 100+ nav/footer/sidebar elements to live AI at ~$0.01 each.\n //\n // Without a manifest, the old behaviour applies:\n // manual mode → skip all live AI\n // auto mode → live AI for everything (first visit before any crawl)\n const manifestWasLoaded = fromCache > 0 || (siteKey && staleBlocks.size > 0);\n\n if (manifestWasLoaded && remaining.length > 0) {\n // Manifest exists — only stale blocks go to AI, skip the rest\n const nonStaleRemaining = remaining.filter(el => !staleBlocks.has(el));\n if (nonStaleRemaining.length > 0 && DEBUG) {\n console.info(\n `[Accessify] Manifest loaded — skipping ${nonStaleRemaining.length} non-manifest block(s) (nav/footer/sidebar). ` +\n `Only ${staleBlocks.size} stale block(s) will use live AI.`,\n );\n }\n // Clear loading on non-stale blocks we won't process\n for (const el of nonStaleRemaining) clearLoading(el);\n // Only keep stale blocks for AI\n remaining = remaining.filter(el => staleBlocks.has(el));\n\n if (remaining.length === 0) {\n // All manifest blocks applied, no stale blocks — done\n showDone(fromCache, fromCache);\n showDisclaimer();\n return;\n }\n } else if (currentSiteMode !== 'auto' && remaining.length > 0) {\n // No manifest — manual mode: skip all live AI\n if (DEBUG) {\n console.info(\n `[Accessify] siteMode=${currentSiteMode} — skipping live AI for ${remaining.length} uncached block(s). ` +\n `Site owner: trigger a crawl from the dashboard or switch to 'auto' mode.`,\n );\n }\n if (staleBlocks.size > 0) skippedBlocks += staleBlocks.size;\n // Clear loading state on blocks we won't touch\n for (const el of remaining) clearLoading(el);\n if (fromCache > 0) {\n showDone(fromCache, fromCache);\n showDisclaimer();\n } else {\n removeProgress();\n }\n return;\n }\n\n // If no AI service available: stale blocks must be skipped (never show outdated text),\n // non-stale remaining blocks also can't be simplified → show appropriate message\n if (!aiService && remaining.length > 0) {\n // Skip all stale blocks — outdated simplifications must NOT be shown\n if (staleBlocks.size > 0) {\n skippedBlocks += staleBlocks.size;\n console.info(`[Accessify] ${staleBlocks.size} stale block(s) skipped — no AI service to regenerate`);\n }\n if (fromCache > 0) {\n showDone(fromCache, fromCache);\n } else {\n showProgress(0, 1);\n showError(lang.startsWith('de')\n ? 'Kein API-Key konfiguriert'\n : 'No API key configured');\n }\n return;\n }\n\n // Mark remaining elements as loading\n for (const el of remaining) {\n markLoading(el);\n }\n\n const totalElements = elements.length;\n let completed = fromCache;\n let totalSimplified = fromCache;\n const isStale = (el: HTMLElement) => staleBlocks.has(el);\n\n showProgress(completed, totalElements, skippedBlocks);\n\n for (const el of remaining) {\n if (abortController.signal.aborted) break;\n\n const text = el.dataset.accessifyOriginal || el.textContent?.trim() || '';\n if (text.length < 20) {\n clearLoading(el);\n completed++;\n showProgress(completed, totalElements, skippedBlocks);\n continue;\n }\n\n // Skip short credit/attribution lines in live AI (hallucination risk)\n if (text.length < 60 && CREDIT_LINE_PATTERN.test(text)) {\n clearLoading(el);\n completed++;\n skippedBlocks++;\n showProgress(completed, totalElements, skippedBlocks);\n continue;\n }\n\n const blockHash = hashText(text);\n\n try {\n const simplified = await aiService!.simplifyText(text, level, lang);\n if (abortController?.signal.aborted) return;\n\n if (simplified && simplified !== text) {\n const success = safeReplace(el, simplified, blockHash);\n if (success) {\n totalSimplified++;\n\n // Cache client-side for instant reload\n setClientCached(clientCacheKey(blockHash), simplified);\n\n // Auto-persist live result back to manifest (non-blocking)\n if (siteKey) {\n persistToManifest(siteKey, blockHash, text, simplified, buildSelector(el), proxyUrl);\n }\n }\n }\n } catch (err: any) {\n // Abort immediately on auth errors — no point retrying\n if (err?.message?.includes('401') || err?.message?.includes('403')) {\n console.warn('[Accessify] AI auth failed, stopping live simplification');\n // Stale blocks that haven't been processed yet must be counted as skipped\n for (const r of remaining) {\n if (isStale(r) && !r.hasAttribute(SIMPLIFIED_ATTR)) skippedBlocks++;\n }\n clearLoading(el);\n completed++;\n break;\n }\n if (err?.message?.includes('429')) {\n // Rate limited — retry once after delay\n await new Promise((r) => setTimeout(r, 8000));\n try {\n const retry = await aiService!.simplifyText(text, level, lang);\n if (abortController?.signal.aborted) return;\n if (retry && retry !== text) {\n const success = safeReplace(el, retry, blockHash);\n if (success) {\n totalSimplified++;\n setClientCached(clientCacheKey(blockHash), retry);\n if (siteKey) {\n persistToManifest(siteKey, blockHash, text, retry, buildSelector(el), proxyUrl);\n }\n }\n }\n } catch {\n // Stale block that failed AI regeneration → skip it entirely\n if (isStale(el)) {\n skippedBlocks++;\n console.warn('[Accessify] Stale block skipped — AI retry failed:', text.slice(0, 50));\n }\n }\n } else {\n // Any other AI error on a stale block → skip (don't show outdated text)\n if (isStale(el)) {\n skippedBlocks++;\n console.warn('[Accessify] Stale block skipped — AI error:', text.slice(0, 50));\n } else {\n console.warn('[Accessify] Failed to simplify:', err);\n }\n }\n } finally {\n clearLoading(el);\n completed++;\n if (!abortController?.signal.aborted) {\n showProgress(completed, totalElements, skippedBlocks);\n // Throttle: small delay between requests to respect free-tier rate limits\n await new Promise((r) => setTimeout(r, 600));\n }\n }\n }\n\n // Clean up any remaining loading indicators (e.g. after auth-error break)\n for (const el of remaining) {\n clearLoading(el);\n }\n\n if (!abortController?.signal.aborted) {\n showDone(totalSimplified, fromCache);\n // Show AI disclaimer on the page\n if (totalSimplified > 0 || fromCache > 0) {\n showDisclaimer();\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Restore original text — clean teardown\n // -------------------------------------------------------------------------\n\n function restorePage() {\n // Disconnect observers first to avoid triggering them during restore\n disconnectObservers();\n\n for (const { el, originalHtml, savedTextNodes, ancestorPatches } of savedParagraphs) {\n // Prefer text-node restore (React/Framer-safe: no DOM structure change)\n if (savedTextNodes.length > 0) {\n let allRestored = true;\n for (const sn of savedTextNodes) {\n if (sn.node.parentNode) {\n sn.node.data = sn.original; // NUR .data setzen!\n } else {\n allRestored = false;\n }\n }\n // Fallback to innerHTML only if text nodes were removed by framework re-render\n if (!allRestored) {\n el.innerHTML = originalHtml;\n }\n } else {\n el.innerHTML = originalHtml;\n }\n\n el.removeAttribute(ORIGINAL_ATTR);\n el.removeAttribute(SIMPLIFIED_ATTR);\n el.removeAttribute(BLOCK_HASH_ATTR);\n el.removeAttribute('data-accessify-replacing');\n clearLoading(el);\n\n // Restore original text-transform if we overrode it\n if (el.dataset.accessifyOrigTransform) {\n el.style.textTransform = el.dataset.accessifyOrigTransform;\n delete el.dataset.accessifyOrigTransform;\n }\n // Restore heading styles if we normalized them\n if (el.dataset.accessifyOrigFontSize !== undefined) {\n el.style.fontSize = el.dataset.accessifyOrigFontSize;\n delete el.dataset.accessifyOrigFontSize;\n }\n if (el.dataset.accessifyOrigFontWeight !== undefined) {\n el.style.fontWeight = el.dataset.accessifyOrigFontWeight;\n delete el.dataset.accessifyOrigFontWeight;\n }\n\n // Revert any ancestor patches (max-height, overflow changes)\n revertPatches(ancestorPatches);\n }\n\n // Clean up ancestor text-transform overrides\n document.querySelectorAll<HTMLElement>('[data-accessify-orig-transform]').forEach(ancestorEl => {\n if (ancestorEl.closest('#accessify-root')) return;\n ancestorEl.style.textTransform = ancestorEl.dataset.accessifyOrigTransform!;\n delete ancestorEl.dataset.accessifyOrigTransform;\n });\n\n savedParagraphs = [];\n skippedBlocks = 0;\n }\n\n // -------------------------------------------------------------------------\n // Preferences\n // -------------------------------------------------------------------------\n\n function loadPreferences() {\n try {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (saved) {\n const parsed = JSON.parse(saved);\n if (parsed.level === 'einfache' || parsed.level === 'leichte') {\n level = parsed.level;\n }\n }\n } catch { /* use defaults */ }\n }\n\n function savePreferences() {\n localStorage.setItem(STORAGE_KEY, JSON.stringify({ level }));\n }\n\n // -------------------------------------------------------------------------\n // Module lifecycle\n // -------------------------------------------------------------------------\n\n // -------------------------------------------------------------------------\n // SPA navigation detection — re-simplify on URL change\n // -------------------------------------------------------------------------\n\n let lastUrl = '';\n let navigationCleanup: (() => void) | null = null;\n\n function setupNavigationWatcher() {\n lastUrl = location.href;\n\n const onUrlChange = () => {\n if (!enabled || location.href === lastUrl) return;\n lastUrl = location.href;\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.log('[Accessify] URL changed, re-simplifying:', lastUrl);\n }\n // Abort current run, restore old page, re-simplify new content\n abortController?.abort();\n restorePage();\n removeProgress();\n // Small delay for new DOM to settle\n setTimeout(() => { if (enabled) simplifyPage(); }, 500);\n };\n\n // popstate fires on back/forward\n window.addEventListener('popstate', onUrlChange);\n\n // Intercept pushState / replaceState for SPA routers\n const origPush = history.pushState.bind(history);\n const origReplace = history.replaceState.bind(history);\n history.pushState = function(...args: any) {\n origPush(...args);\n onUrlChange();\n };\n history.replaceState = function(...args: any) {\n origReplace(...args);\n onUrlChange();\n };\n\n navigationCleanup = () => {\n window.removeEventListener('popstate', onUrlChange);\n history.pushState = origPush;\n history.replaceState = origReplace;\n };\n }\n\n function activate() {\n if (enabled) return;\n enabled = true;\n loadPreferences();\n setupNavigationWatcher();\n simplifyPage();\n }\n\n function deactivate() {\n enabled = false;\n abortController?.abort();\n abortController = null;\n navigationCleanup?.();\n navigationCleanup = null;\n restorePage();\n removeProgress();\n removeDisclaimer();\n }\n\n return {\n id: 'text-simplify',\n name: () => (lang.startsWith('de') ? 'Text vereinfachen' : 'Simplify Text'),\n description: lang.startsWith('de')\n ? 'Text in Einfache Sprache umwandeln'\n : 'Simplify text for easier understanding',\n icon: 'simplify-text',\n category: 'ai',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'text-simplify',\n enabled,\n value: { level } as TextSimplifyState,\n }),\n setState: (newState: Partial<TextSimplifyState>) => {\n if (newState.level && (newState.level === 'einfache' || newState.level === 'leichte')) {\n level = newState.level;\n savePreferences();\n }\n },\n };\n}\n"],"names":["clipAncestor"],"mappings":"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"}
|