accessify-widget 0.3.77 → 0.3.79

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.
@@ -1,4 +1,4 @@
1
- import { d, i } from "./index-yV-nq3Z-.js";
1
+ import { d, i } from "./index-BUfTIuEG.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -1,4 +1,4 @@
1
- import { g as getCurrentWidgetLang } from "./index-yV-nq3Z-.js";
1
+ import { g as getCurrentWidgetLang } from "./index-BUfTIuEG.js";
2
2
  const IDB_NAME = "accessify-alt-text-cache";
3
3
  const IDB_STORE = "alt-texts";
4
4
  const IDB_VERSION = 2;
@@ -742,4 +742,4 @@ export {
742
742
  autoApplyCachedAltTexts,
743
743
  createAltTextModule as default
744
744
  };
745
- //# sourceMappingURL=alt-text-BDEUXN9O.js.map
745
+ //# sourceMappingURL=alt-text-D_iJlJtX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alt-text-BDEUXN9O.js","sources":["../src/features/alt-text.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Bildbeschreibung (Image Description) Feature\n// ---------------------------------------------------------------------------\n//\n// A) AUTO-APPLY (runs on widget init, no feature activation needed):\n// Loads alt texts from server manifest + IndexedDB cache and silently\n// applies them to images (alt + title). Ensures all visitors get\n// alt texts immediately.\n//\n// B) GENERATE (when user activates the feature toggle):\n// Scans for images without alt text → generates via AI → injects\n// alt + title into DOM. Title attribute provides native hover tooltip\n// on every image, consistently.\n//\n// Framer compatibility:\n// - Uses currentSrc || src (srcset-aware)\n// - Treats empty alt=\"\" on large images as \"missing\" (Framer sets alt=\"\" on all)\n// - Delayed re-scans for lazy-loaded images\n// - MutationObserver for dynamically added images\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState, AIService } from '../types';\nimport { RateLimitError } from '../services/ai-service';\nimport { getCurrentWidgetLang } from '../i18n/index';\n\n// ---------------------------------------------------------------------------\n// IndexedDB cache\n// ---------------------------------------------------------------------------\n\nconst IDB_NAME = 'accessify-alt-text-cache';\nconst IDB_STORE = 'alt-texts';\nconst IDB_VERSION = 2;\n\ninterface CachedAltText {\n key: string; src: string; altText: string; lang: string; createdAt: number;\n}\n\nfunction hashSrc(src: string): string {\n let hash = 5381;\n const n = src.toLowerCase().trim();\n for (let i = 0; i < n.length; i++) { hash = ((hash << 5) + hash) + n.charCodeAt(i); hash |= 0; }\n return Math.abs(hash).toString(36);\n}\n\n/** Normalize image URL: strip query params for cache matching (Framer adds ?width=&height=) */\nfunction normalizeImageUrl(url: string): string {\n try {\n const u = new URL(url);\n u.searchParams.delete('width');\n u.searchParams.delete('height');\n u.searchParams.delete('scale-down-to');\n return u.href;\n } catch {\n return url;\n }\n}\n\n/** Get the best available src for an image (Framer srcset aware) */\nfunction getImageSrc(img: HTMLImageElement): string {\n return img.currentSrc || img.src;\n}\n\nfunction openCache(): Promise<IDBDatabase | null> {\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) db.createObjectStore(IDB_STORE, { keyPath: 'key' });\n if (!db.objectStoreNames.contains('alt-text-reports')) db.createObjectStore('alt-text-reports', { keyPath: 'key' });\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function getAllCachedAltTexts(): Promise<Map<string, string>> {\n const db = await openCache();\n const map = new Map<string, string>();\n if (!db) return map;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).getAll();\n req.onsuccess = () => {\n for (const r of req.result as CachedAltText[]) { map.set(r.src, r.altText); }\n resolve(map);\n };\n req.onerror = () => resolve(map);\n } catch { resolve(map); }\n });\n}\n\nasync function getCachedAltText(src: string): Promise<string | null> {\n const db = await openCache();\n if (!db) return null;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const store = tx.objectStore(IDB_STORE);\n const req1 = store.get(hashSrc(src));\n req1.onsuccess = () => {\n if ((req1.result as CachedAltText | undefined)?.altText) {\n resolve(req1.result.altText);\n return;\n }\n const norm = normalizeImageUrl(src);\n if (norm !== src) {\n const req2 = store.get(hashSrc(norm));\n req2.onsuccess = () => resolve((req2.result as CachedAltText | undefined)?.altText || null);\n req2.onerror = () => resolve(null);\n } else {\n resolve(null);\n }\n };\n req1.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function setCachedAltText(src: string, altText: string, langCode: string): Promise<void> {\n const db = await openCache();\n if (!db) return;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put({ key: hashSrc(src), src, altText, lang: langCode, createdAt: Date.now() } as CachedAltText);\n tx.oncomplete = () => resolve();\n tx.onerror = () => resolve();\n } catch { resolve(); }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Server-side alt-text cache (cross-browser, cross-visitor)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_API_BASE = 'https://accessify-api.accessify.workers.dev';\n\n// Module-wide mode tracking, set on every manifest fetch. 'manual' = default,\n// never run live AI for unknown images. 'auto' = live fallback + auto-persist OK.\ntype ResimplifyMode = 'manual' | 'auto';\nlet currentAltSiteMode: ResimplifyMode = 'manual';\n\nasync function fetchServerAltTexts(siteKey: string, proxyUrl: string, lang: string): Promise<Map<string, string>> {\n const map = new Map<string, string>();\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n const res = await fetch(`${base}/v1/manifest?siteKey=${encodeURIComponent(siteKey)}&url=${encodeURIComponent(pageUrl)}&feature=alt_text&variant=${encodeURIComponent(lang)}`, {\n headers: { 'Accept': 'application/json' },\n cache: 'no-cache',\n });\n if (!res.ok) return map;\n const data = await res.json() as { blocks?: Array<{ selector: string; result: string }>; siteMode?: ResimplifyMode };\n // Update authoritative mode from server on every fetch\n currentAltSiteMode = data.siteMode === 'auto' ? 'auto' : 'manual';\n if (data.blocks) {\n for (const block of data.blocks) {\n if (block.selector && block.result) map.set(block.selector, block.result);\n }\n }\n } catch { /* fall back to IndexedDB */ }\n return map;\n}\n\nfunction persistAltTextToServer(siteKey: string, proxyUrl: string, imageUrl: string, altText: string, lang: string): void {\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n fetch(`${base}/v1/cache/persist-alt-text`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ siteKey, pageUrl, imageUrl, altText, lang }),\n }).catch(() => {});\n } catch { /* fire-and-forget */ }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-apply: runs on widget init, no feature activation needed\n// ---------------------------------------------------------------------------\n\nlet autoApplied = false;\n\n/** Silently apply cached/manifest alt texts to all images on the page */\nexport async function autoApplyCachedAltTexts(\n widgetConfig?: { siteKey?: string; proxyUrl?: string; lang?: string },\n): Promise<number> {\n if (autoApplied) return 0;\n autoApplied = true;\n\n const cache = new Map<string, string>();\n const siteKey = widgetConfig?.siteKey;\n const proxyUrl = widgetConfig?.proxyUrl || '';\n const pageLang = widgetConfig?.lang?.split('-')[0] || document.documentElement.lang?.split('-')[0] || 'en';\n\n // 1. Server manifest (freshest, cross-browser)\n if (siteKey) {\n const serverCache = await fetchServerAltTexts(siteKey, proxyUrl, pageLang);\n for (const [url, alt] of serverCache) {\n // Store BOTH original URL and normalized URL (without width/height params)\n // so lookups by currentSrc (any size) will match\n cache.set(url, alt);\n const norm = normalizeImageUrl(url);\n if (norm !== url) cache.set(norm, alt);\n setCachedAltText(url, alt, pageLang).catch(() => {});\n }\n }\n\n // 2. IndexedDB (fills gaps)\n const localCache = await getAllCachedAltTexts();\n for (const [url, alt] of localCache) {\n if (!cache.has(url)) cache.set(url, alt);\n }\n\n if (cache.size === 0) return 0;\n\n function applyToImg(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n const src = getImageSrc(img);\n const norm = normalizeImageUrl(src);\n const imgSrcNorm = normalizeImageUrl(img.src);\n const cached = cache.get(src) || cache.get(norm) || cache.get(img.src) || cache.get(imgSrcNorm);\n if (!cached) return false;\n\n const alt = img.getAttribute('alt');\n if (alt === null || alt.trim() === '') {\n img.setAttribute('alt', cached);\n img.setAttribute('data-accessify-alt', 'auto');\n }\n // Always set title for native hover tooltip\n img.setAttribute('title', cached);\n return true;\n }\n\n let applied = 0;\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (applyToImg(img)) applied++;\n });\n\n // Watch for late-loading images (Framer SPA, lazy load)\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n const imgs = node instanceof HTMLImageElement ? [node] :\n node instanceof HTMLElement ? Array.from(node.querySelectorAll<HTMLImageElement>('img')) : [];\n for (const img of imgs) applyToImg(img);\n }\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n setTimeout(() => observer.disconnect(), 30000);\n\n return applied;\n}\n\n// ---------------------------------------------------------------------------\n// Feature Module\n// ---------------------------------------------------------------------------\n\nexport default function createAltTextModule(\n aiService?: AIService,\n initialLang: string = 'de',\n serverConfig?: { siteKey?: string; proxyUrl?: string },\n): FeatureModule {\n const siteKey = serverConfig?.siteKey || '';\n const proxyUrl = serverConfig?.proxyUrl || '';\n let enabled = false;\n let domObserver: MutationObserver | null = null;\n let autoGenerating = false;\n\n // Tracked images\n let missingAltImages: HTMLImageElement[] = [];\n const processedImages = new Map<HTMLImageElement, { generatedAlt: string }>();\n\n function lang(): string { return getCurrentWidgetLang() || initialLang; }\n function isDE(): boolean { return lang().startsWith('de'); }\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n function isGenericAlt(alt: string): boolean {\n if (!alt.trim()) return true;\n if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;\n if (/^IMG_\\d+/i.test(alt)) return true;\n if (/\\.(jpg|jpeg|png|gif|webp|svg|avif)$/i.test(alt)) return true;\n return false;\n }\n\n function isDecorativeImage(img: HTMLImageElement): boolean {\n const role = img.getAttribute('role');\n if (role === 'presentation' || role === 'none') return true;\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return true;\n return false;\n }\n\n function isValidImage(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n // Skip tiny images (icons, tracking pixels, avatars)\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return false;\n // Skip images not rendered on-screen (display:none, visibility:hidden, etc.)\n const rect = img.getBoundingClientRect();\n if (rect.width < 40 || rect.height < 40) return false;\n // Skip images hidden via CSS (opacity:0, visibility:hidden)\n const style = getComputedStyle(img);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;\n // Skip images with role=\"presentation\" or aria-hidden\n if (img.getAttribute('role') === 'presentation' || img.getAttribute('aria-hidden') === 'true') return false;\n return true;\n }\n\n function needsAltText(img: HTMLImageElement): boolean {\n if (!isValidImage(img)) return false;\n const alt = img.getAttribute('alt');\n if (alt === null) return true;\n if (isGenericAlt(alt)) return true;\n if (alt === '' && !isDecorativeImage(img)) return true;\n return false;\n }\n\n function scanForMissingAlt(): HTMLImageElement[] {\n const missing: HTMLImageElement[] = [];\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (needsAltText(img)) missing.push(img);\n });\n document.querySelectorAll<HTMLElement>('picture').forEach((picture) => {\n if (picture.closest('#accessify-root') || picture.closest('accessify-widget')) return;\n const img = picture.querySelector('img');\n if (img && !missing.includes(img) && needsAltText(img)) {\n missing.push(img);\n }\n });\n return missing;\n }\n\n function gatherImageContext(img: HTMLImageElement): string {\n const parts: string[] = [];\n try {\n const url = new URL(getImageSrc(img), window.location.href);\n const filename = url.pathname.split('/').pop();\n if (filename) parts.push(`Filename: ${filename}`);\n } catch {}\n const figure = img.closest('figure');\n if (figure) {\n const caption = figure.querySelector('figcaption');\n if (caption?.textContent?.trim()) parts.push(`Caption: ${caption.textContent.trim()}`);\n }\n const container = img.parentElement?.parentElement || img.parentElement;\n if (container) {\n const heading = container.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading?.textContent?.trim()) parts.push(`Nearby heading: ${heading.textContent.trim()}`);\n }\n return parts.join('. ');\n }\n\n // -------------------------------------------------------------------------\n // Apply + Generate (title = native hover tooltip on every image)\n // -------------------------------------------------------------------------\n\n function applyAltText(img: HTMLImageElement, altText: string) {\n img.setAttribute('alt', altText);\n img.setAttribute('title', altText);\n processedImages.set(img, { generatedAlt: altText });\n if (enabled) addInfoBadge(img, altText);\n }\n\n /** Set title on every visible image that has alt text but no title yet */\n function applyTitlesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n // Skip if already has a title\n if (img.getAttribute('title')) return;\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n });\n }\n\n // -------------------------------------------------------------------------\n // Info badge — small \"i\" icon on each image with alt text\n // -------------------------------------------------------------------------\n // Badges live in a single overlay container on document.body (position:fixed\n // would need scroll tracking, so we use position:absolute on the body).\n // This keeps them completely outside any overflow:hidden zoom containers.\n // -------------------------------------------------------------------------\n\n const BADGE_ATTR = 'data-accessify-badge';\n const WRAPPER_ATTR = 'data-accessify-badge-wrap';\n const OVERLAY_ID = 'accessify-badge-overlay';\n const BADGE_STYLE_ID = 'accessify-badge-styles';\n let badgePositionRAF: number | null = null;\n let trackedBadges: Array<{ target: HTMLElement; badge: HTMLElement; tooltip: HTMLElement }> = [];\n let outsideClickHandler: ((e: Event) => void) | null = null;\n\n function getOrCreateOverlay(): HTMLElement {\n let overlay = document.getElementById(OVERLAY_ID);\n if (!overlay) {\n overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '0',\n height: '0',\n overflow: 'visible',\n pointerEvents: 'none',\n zIndex: '10000',\n });\n document.body.appendChild(overlay);\n }\n // Inject badge hover + coarse pointer styles once\n if (!document.getElementById(BADGE_STYLE_ID)) {\n const style = document.createElement('style');\n style.id = BADGE_STYLE_ID;\n style.textContent = `\n [${BADGE_ATTR}=\"badge\"]:hover + [${BADGE_ATTR}=\"tooltip\"] { display: block !important; }\n [${BADGE_ATTR}=\"badge\"]:hover { background: rgba(0,0,0,0.85) !important; }\n @media (pointer: coarse) {\n [${BADGE_ATTR}=\"badge\"] { width: 36px !important; height: 36px !important; line-height: 36px !important; font-size: 16px !important; }\n }\n `;\n document.head.appendChild(style);\n }\n return overlay;\n }\n\n function positionBadge(target: HTMLElement, badge: HTMLElement, tooltip: HTMLElement) {\n const rect = target.getBoundingClientRect();\n // Skip if element is not visible / too small / off-screen\n if (rect.width < 40 || rect.height < 40 ||\n rect.bottom < 0 || rect.top > window.innerHeight + 200 ||\n rect.right < 0 || rect.left > window.innerWidth + 200) {\n badge.style.display = 'none';\n tooltip.style.display = 'none';\n return;\n }\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const top = rect.top + scrollY + 6;\n const left = rect.left + scrollX + 6;\n badge.style.display = '';\n badge.style.top = `${top}px`;\n badge.style.left = `${left}px`;\n // Tooltip positioned below badge\n tooltip.style.top = `${top + 26}px`;\n tooltip.style.left = `${left}px`;\n }\n\n function updateAllBadgePositions() {\n for (const { target, badge, tooltip } of trackedBadges) {\n if (!document.body.contains(target)) continue;\n positionBadge(target, badge, tooltip);\n }\n }\n\n function startBadgeTracking() {\n if (badgePositionRAF !== null) return;\n const tick = () => {\n updateAllBadgePositions();\n badgePositionRAF = requestAnimationFrame(tick);\n };\n badgePositionRAF = requestAnimationFrame(tick);\n\n // Outside-click handler to close all open tooltips\n if (!outsideClickHandler) {\n outsideClickHandler = (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.getAttribute(BADGE_ATTR) === 'badge') return;\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n };\n document.addEventListener('click', outsideClickHandler, { passive: true });\n }\n }\n\n function stopBadgeTracking() {\n if (badgePositionRAF !== null) {\n cancelAnimationFrame(badgePositionRAF);\n badgePositionRAF = null;\n }\n if (outsideClickHandler) {\n document.removeEventListener('click', outsideClickHandler);\n outsideClickHandler = null;\n }\n }\n\n function addInfoBadge(target: HTMLElement, altText: string) {\n if (target.getAttribute(BADGE_ATTR)) return;\n target.setAttribute(BADGE_ATTR, '1');\n\n const overlay = getOrCreateOverlay();\n\n // Badge \"i\" circle\n const badge = document.createElement('span');\n Object.assign(badge.style, {\n position: 'absolute',\n width: '22px',\n height: '22px',\n borderRadius: '50%',\n background: 'rgba(0,0,0,0.6)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontWeight: 'bold',\n fontSize: '13px',\n lineHeight: '22px',\n textAlign: 'center',\n cursor: 'default',\n pointerEvents: 'auto',\n boxShadow: '0 1px 4px rgba(0,0,0,0.4)',\n transition: 'background 0.15s',\n });\n badge.textContent = 'i';\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('translate', 'no');\n badge.classList.add('notranslate');\n badge.setAttribute(BADGE_ATTR, 'badge');\n\n // Tooltip\n const tooltip = document.createElement('span');\n Object.assign(tooltip.style, {\n display: 'none',\n position: 'absolute',\n minWidth: '150px',\n maxWidth: '280px',\n padding: '6px 10px',\n background: 'rgba(0,0,0,0.88)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontSize: '12px',\n lineHeight: '1.4',\n borderRadius: '6px',\n pointerEvents: 'none',\n wordWrap: 'break-word',\n boxShadow: '0 2px 8px rgba(0,0,0,0.3)',\n zIndex: '1',\n });\n tooltip.textContent = altText;\n tooltip.setAttribute('translate', 'no');\n tooltip.classList.add('notranslate');\n tooltip.setAttribute(BADGE_ATTR, 'tooltip');\n\n badge.addEventListener('click', () => {\n const isOpen = tooltip.style.display === 'block';\n // Close all other open tooltips first\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n if (!isOpen) {\n badge.style.background = 'rgba(0,0,0,0.85)';\n tooltip.style.display = 'block';\n }\n });\n\n overlay.appendChild(badge);\n overlay.appendChild(tooltip);\n\n // Initial position\n positionBadge(target, badge, tooltip);\n\n // Track for continuous position updates\n trackedBadges.push({ target, badge, tooltip });\n }\n\n function removeAllBadges() {\n stopBadgeTracking();\n trackedBadges = [];\n // Remove overlay and badge styles\n document.getElementById(OVERLAY_ID)?.remove();\n document.getElementById(BADGE_STYLE_ID)?.remove();\n // Clear badge markers\n document.querySelectorAll(`[${BADGE_ATTR}]`).forEach(el => el.removeAttribute(BADGE_ATTR));\n // Legacy: unwrap any leftover wrappers from old version\n document.querySelectorAll<HTMLElement>(`[${WRAPPER_ATTR}]`).forEach(wrapper => {\n const img = wrapper.querySelector('img');\n if (img && wrapper.parentElement) {\n wrapper.parentElement.insertBefore(img, wrapper);\n wrapper.remove();\n }\n });\n }\n\n /** Add info badges to ALL visible images */\n function addBadgesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n const alt = img.getAttribute('alt') || img.getAttribute('title');\n if (alt && alt.trim()) {\n addInfoBadge(img, alt.trim());\n }\n });\n // Also for background images\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n const alt = el.getAttribute('aria-label');\n if (alt && alt.trim()) {\n addInfoBadge(el, alt.trim());\n }\n });\n // Start tracking positions (handles scroll, resize, zoom)\n if (trackedBadges.length > 0) startBadgeTracking();\n }\n\n function removeTitles() {\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-title=\"auto\"]').forEach((img) => {\n img.removeAttribute('title');\n img.removeAttribute('data-accessify-title');\n });\n // Clean up background image descriptions\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n el.removeAttribute('role');\n el.removeAttribute('aria-label');\n el.removeAttribute('title');\n el.removeAttribute('data-accessify-bg-alt');\n });\n // Remove all info badges\n removeAllBadges();\n }\n\n // -------------------------------------------------------------------------\n // Background images (CSS background-image)\n // -------------------------------------------------------------------------\n\n /** Find significant elements with CSS background-image and no accessibility info */\n function scanForBackgroundImages(): HTMLElement[] {\n const found: HTMLElement[] = [];\n // Scan ALL elements — not just specific class patterns — for background-image\n const allElements = document.querySelectorAll<HTMLElement>('*');\n for (const el of allElements) {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) continue;\n if (el.getAttribute('data-accessify-bg-alt')) continue;\n // Skip tiny or invisible elements quickly via offsetHeight (avoids getComputedStyle)\n if (el.offsetWidth < 200 || el.offsetHeight < 150) continue;\n const style = getComputedStyle(el);\n const bg = style.backgroundImage;\n if (!bg || bg === 'none') continue;\n // Must have a url() reference (not just gradients)\n const urlMatch = bg.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n if (!urlMatch) continue;\n // Skip SVG data URIs and tiny inline images\n if (urlMatch[1].startsWith('data:image/svg')) continue;\n // Skip if already has role=\"img\" with aria-label\n if (el.getAttribute('role') === 'img' && el.getAttribute('aria-label')) continue;\n found.push(el);\n }\n return found;\n }\n\n function getBackgroundImageUrl(el: HTMLElement): string | null {\n const bg = getComputedStyle(el).backgroundImage;\n const match = bg?.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n return match ? match[1] : null;\n }\n\n function applyBgAlt(el: HTMLElement, altText: string) {\n el.setAttribute('role', 'img');\n el.setAttribute('aria-label', altText);\n el.setAttribute('title', altText);\n el.setAttribute('data-accessify-bg-alt', 'auto');\n if (enabled) addInfoBadge(el, altText);\n }\n\n async function generateBgAlts() {\n if (!aiService || !enabled) return;\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info('[Accessify] alt-text: siteMode=manual — skipping live generation for background images');\n }\n return;\n }\n const bgElements = scanForBackgroundImages();\n for (const el of bgElements) {\n if (!enabled) break;\n const src = getBackgroundImageUrl(el);\n if (!src) continue;\n // Check cache first\n const cached = await getCachedAltText(src);\n if (cached) {\n applyBgAlt(el, cached);\n continue;\n }\n // Generate via AI\n try {\n const ctx = gatherBgContext(el);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyBgAlt(el, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Bg alt-text generation failed:', src, err);\n }\n }\n }\n\n function gatherBgContext(el: HTMLElement): string {\n const parts: string[] = [];\n // Tag and class hints\n parts.push(`Element: <${el.tagName.toLowerCase()}>`);\n if (el.className) parts.push(`Class: ${el.className}`);\n // Text inside\n const text = el.textContent?.trim().slice(0, 100);\n if (text) parts.push(`Overlay text: ${text}`);\n // Nearby heading\n const heading = el.querySelector('h1, h2, h3');\n if (heading?.textContent?.trim()) parts.push(`Heading: ${heading.textContent.trim()}`);\n return parts.join('. ');\n }\n\n async function generateAll() {\n if (autoGenerating || !enabled || !aiService) return;\n autoGenerating = true;\n const CONCURRENCY = 3;\n\n // Phase 1: apply from IndexedDB cache\n const uncached: HTMLImageElement[] = [];\n for (const img of missingAltImages) {\n if (!enabled) { autoGenerating = false; return; }\n if (processedImages.has(img)) continue;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) {\n applyAltText(img, cached);\n } else {\n uncached.push(img);\n }\n }\n\n if (!enabled) { autoGenerating = false; return; }\n if (!uncached.length) { autoGenerating = false; return; }\n\n // SAFETY GATE: only proceed with live AI if site is in 'auto' mode.\n // In 'manual' (default), leave images without generated alt text — the\n // owner must trigger a crawl or switch modes from the dashboard.\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info(\n `[Accessify] alt-text: siteMode=manual — ${uncached.length} image(s) left untouched. ` +\n `Trigger a crawl from the dashboard or enable auto mode.`,\n );\n }\n autoGenerating = false;\n return;\n }\n\n // Phase 2: AI generation in parallel batches\n for (let i = 0; i < uncached.length; i += CONCURRENCY) {\n if (!enabled) { autoGenerating = false; return; }\n const batch = uncached.slice(i, i + CONCURRENCY);\n await Promise.all(batch.map(async (img) => {\n if (!enabled) return;\n try {\n const src = getImageSrc(img);\n const ctx = gatherImageContext(img);\n const alt = await aiService!.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', getImageSrc(img), err);\n }\n }));\n }\n\n autoGenerating = false;\n }\n\n async function generateSingle(img: HTMLImageElement) {\n if (!aiService || !enabled) return;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) { applyAltText(img, cached); return; }\n\n // Mode gate — only live-generate when site is in 'auto' mode\n if (currentAltSiteMode !== 'auto') return;\n\n try {\n const ctx = gatherImageContext(img);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', src, err);\n }\n }\n\n // -------------------------------------------------------------------------\n // Dynamic image registration\n // -------------------------------------------------------------------------\n\n function tryRegisterImage(img: HTMLImageElement) {\n if (!enabled) return;\n if (!isValidImage(img)) return;\n if (missingAltImages.includes(img)) return;\n\n function addIfValid() {\n if (!enabled || missingAltImages.includes(img)) return;\n if (img.naturalWidth < 20 || img.naturalHeight < 20) return;\n\n if (needsAltText(img)) {\n missingAltImages.push(img);\n generateSingle(img);\n } else {\n // Image has alt but maybe no title/badge yet — add both\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n if (!img.getAttribute('title')) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n addInfoBadge(img, alt.trim());\n }\n }\n }\n\n if (img.complete && img.naturalWidth > 0) addIfValid();\n else img.addEventListener('load', addIfValid, { once: true });\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Recognize images that were auto-applied from cache/manifest\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-alt=\"auto\"]').forEach((img) => {\n if (img.closest('#accessify-root')) return;\n if (!processedImages.has(img)) {\n processedImages.set(img, { generatedAlt: img.getAttribute('alt') || '' });\n missingAltImages.push(img);\n }\n });\n\n // Scan for truly missing alt texts\n const missing = scanForMissingAlt();\n for (const img of missing) {\n if (!missingAltImages.includes(img)) {\n missingAltImages.push(img);\n }\n }\n\n // Start AI generation in background (img + background images)\n generateAll();\n generateBgAlts();\n\n // Set title on ALL images (consistent hover tooltip everywhere)\n applyTitlesToAllImages();\n\n // Add info badges to show alt text is available\n addBadgesToAllImages();\n\n // Register not-yet-loaded images\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!img.complete) tryRegisterImage(img);\n });\n\n // Delayed re-scans for late-loading images and AI-generated alt texts\n for (const delay of [2000, 5000, 10000]) {\n setTimeout(() => {\n if (enabled) {\n document.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n applyTitlesToAllImages();\n addBadgesToAllImages();\n }\n }, delay);\n }\n\n // Watch for new images\n domObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n if (node instanceof HTMLImageElement) tryRegisterImage(node);\n else if (node instanceof HTMLElement) {\n node.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n }\n }\n }\n });\n domObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function deactivate() {\n enabled = false;\n autoGenerating = false;\n domObserver?.disconnect();\n domObserver = null;\n\n // Remove auto-added titles (but keep alt texts — those are useful)\n removeTitles();\n missingAltImages = [];\n }\n\n // Run auto-apply immediately when the module is created\n autoApplyCachedAltTexts({ siteKey, proxyUrl, lang: initialLang }).catch(() => {});\n\n return {\n id: 'alt-text',\n name: () => (isDE() ? 'Bildbeschreibung' : 'Image Description'),\n description: isDE() ? 'Bildbeschreibungen per Hover anzeigen und fehlende automatisch erzeugen' : 'Show image descriptions on hover and auto-generate missing ones',\n icon: 'alt-text',\n category: 'ai',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'alt-text',\n enabled,\n value: {\n missingCount: missingAltImages.filter((img) => !processedImages.has(img)).length,\n processedCount: processedImages.size,\n },\n }),\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"alt-text-D_iJlJtX.js","sources":["../src/features/alt-text.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Bildbeschreibung (Image Description) Feature\n// ---------------------------------------------------------------------------\n//\n// A) AUTO-APPLY (runs on widget init, no feature activation needed):\n// Loads alt texts from server manifest + IndexedDB cache and silently\n// applies them to images (alt + title). Ensures all visitors get\n// alt texts immediately.\n//\n// B) GENERATE (when user activates the feature toggle):\n// Scans for images without alt text → generates via AI → injects\n// alt + title into DOM. Title attribute provides native hover tooltip\n// on every image, consistently.\n//\n// Framer compatibility:\n// - Uses currentSrc || src (srcset-aware)\n// - Treats empty alt=\"\" on large images as \"missing\" (Framer sets alt=\"\" on all)\n// - Delayed re-scans for lazy-loaded images\n// - MutationObserver for dynamically added images\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState, AIService } from '../types';\nimport { RateLimitError } from '../services/ai-service';\nimport { getCurrentWidgetLang } from '../i18n/index';\n\n// ---------------------------------------------------------------------------\n// IndexedDB cache\n// ---------------------------------------------------------------------------\n\nconst IDB_NAME = 'accessify-alt-text-cache';\nconst IDB_STORE = 'alt-texts';\nconst IDB_VERSION = 2;\n\ninterface CachedAltText {\n key: string; src: string; altText: string; lang: string; createdAt: number;\n}\n\nfunction hashSrc(src: string): string {\n let hash = 5381;\n const n = src.toLowerCase().trim();\n for (let i = 0; i < n.length; i++) { hash = ((hash << 5) + hash) + n.charCodeAt(i); hash |= 0; }\n return Math.abs(hash).toString(36);\n}\n\n/** Normalize image URL: strip query params for cache matching (Framer adds ?width=&height=) */\nfunction normalizeImageUrl(url: string): string {\n try {\n const u = new URL(url);\n u.searchParams.delete('width');\n u.searchParams.delete('height');\n u.searchParams.delete('scale-down-to');\n return u.href;\n } catch {\n return url;\n }\n}\n\n/** Get the best available src for an image (Framer srcset aware) */\nfunction getImageSrc(img: HTMLImageElement): string {\n return img.currentSrc || img.src;\n}\n\nfunction openCache(): Promise<IDBDatabase | null> {\n return new Promise((resolve) => {\n try {\n const req = indexedDB.open(IDB_NAME, IDB_VERSION);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE)) db.createObjectStore(IDB_STORE, { keyPath: 'key' });\n if (!db.objectStoreNames.contains('alt-text-reports')) db.createObjectStore('alt-text-reports', { keyPath: 'key' });\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function getAllCachedAltTexts(): Promise<Map<string, string>> {\n const db = await openCache();\n const map = new Map<string, string>();\n if (!db) return map;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const req = tx.objectStore(IDB_STORE).getAll();\n req.onsuccess = () => {\n for (const r of req.result as CachedAltText[]) { map.set(r.src, r.altText); }\n resolve(map);\n };\n req.onerror = () => resolve(map);\n } catch { resolve(map); }\n });\n}\n\nasync function getCachedAltText(src: string): Promise<string | null> {\n const db = await openCache();\n if (!db) return null;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readonly');\n const store = tx.objectStore(IDB_STORE);\n const req1 = store.get(hashSrc(src));\n req1.onsuccess = () => {\n if ((req1.result as CachedAltText | undefined)?.altText) {\n resolve(req1.result.altText);\n return;\n }\n const norm = normalizeImageUrl(src);\n if (norm !== src) {\n const req2 = store.get(hashSrc(norm));\n req2.onsuccess = () => resolve((req2.result as CachedAltText | undefined)?.altText || null);\n req2.onerror = () => resolve(null);\n } else {\n resolve(null);\n }\n };\n req1.onerror = () => resolve(null);\n } catch { resolve(null); }\n });\n}\n\nasync function setCachedAltText(src: string, altText: string, langCode: string): Promise<void> {\n const db = await openCache();\n if (!db) return;\n return new Promise((resolve) => {\n try {\n const tx = db.transaction(IDB_STORE, 'readwrite');\n tx.objectStore(IDB_STORE).put({ key: hashSrc(src), src, altText, lang: langCode, createdAt: Date.now() } as CachedAltText);\n tx.oncomplete = () => resolve();\n tx.onerror = () => resolve();\n } catch { resolve(); }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Server-side alt-text cache (cross-browser, cross-visitor)\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_API_BASE = 'https://accessify-api.accessify.workers.dev';\n\n// Module-wide mode tracking, set on every manifest fetch. 'manual' = default,\n// never run live AI for unknown images. 'auto' = live fallback + auto-persist OK.\ntype ResimplifyMode = 'manual' | 'auto';\nlet currentAltSiteMode: ResimplifyMode = 'manual';\n\nasync function fetchServerAltTexts(siteKey: string, proxyUrl: string, lang: string): Promise<Map<string, string>> {\n const map = new Map<string, string>();\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n const res = await fetch(`${base}/v1/manifest?siteKey=${encodeURIComponent(siteKey)}&url=${encodeURIComponent(pageUrl)}&feature=alt_text&variant=${encodeURIComponent(lang)}`, {\n headers: { 'Accept': 'application/json' },\n cache: 'no-cache',\n });\n if (!res.ok) return map;\n const data = await res.json() as { blocks?: Array<{ selector: string; result: string }>; siteMode?: ResimplifyMode };\n // Update authoritative mode from server on every fetch\n currentAltSiteMode = data.siteMode === 'auto' ? 'auto' : 'manual';\n if (data.blocks) {\n for (const block of data.blocks) {\n if (block.selector && block.result) map.set(block.selector, block.result);\n }\n }\n } catch { /* fall back to IndexedDB */ }\n return map;\n}\n\nfunction persistAltTextToServer(siteKey: string, proxyUrl: string, imageUrl: string, altText: string, lang: string): void {\n try {\n const base = proxyUrl || DEFAULT_API_BASE;\n const pageUrl = window.location.origin + window.location.pathname;\n fetch(`${base}/v1/cache/persist-alt-text`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ siteKey, pageUrl, imageUrl, altText, lang }),\n }).catch(() => {});\n } catch { /* fire-and-forget */ }\n}\n\n// ---------------------------------------------------------------------------\n// Auto-apply: runs on widget init, no feature activation needed\n// ---------------------------------------------------------------------------\n\nlet autoApplied = false;\n\n/** Silently apply cached/manifest alt texts to all images on the page */\nexport async function autoApplyCachedAltTexts(\n widgetConfig?: { siteKey?: string; proxyUrl?: string; lang?: string },\n): Promise<number> {\n if (autoApplied) return 0;\n autoApplied = true;\n\n const cache = new Map<string, string>();\n const siteKey = widgetConfig?.siteKey;\n const proxyUrl = widgetConfig?.proxyUrl || '';\n const pageLang = widgetConfig?.lang?.split('-')[0] || document.documentElement.lang?.split('-')[0] || 'en';\n\n // 1. Server manifest (freshest, cross-browser)\n if (siteKey) {\n const serverCache = await fetchServerAltTexts(siteKey, proxyUrl, pageLang);\n for (const [url, alt] of serverCache) {\n // Store BOTH original URL and normalized URL (without width/height params)\n // so lookups by currentSrc (any size) will match\n cache.set(url, alt);\n const norm = normalizeImageUrl(url);\n if (norm !== url) cache.set(norm, alt);\n setCachedAltText(url, alt, pageLang).catch(() => {});\n }\n }\n\n // 2. IndexedDB (fills gaps)\n const localCache = await getAllCachedAltTexts();\n for (const [url, alt] of localCache) {\n if (!cache.has(url)) cache.set(url, alt);\n }\n\n if (cache.size === 0) return 0;\n\n function applyToImg(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n const src = getImageSrc(img);\n const norm = normalizeImageUrl(src);\n const imgSrcNorm = normalizeImageUrl(img.src);\n const cached = cache.get(src) || cache.get(norm) || cache.get(img.src) || cache.get(imgSrcNorm);\n if (!cached) return false;\n\n const alt = img.getAttribute('alt');\n if (alt === null || alt.trim() === '') {\n img.setAttribute('alt', cached);\n img.setAttribute('data-accessify-alt', 'auto');\n }\n // Always set title for native hover tooltip\n img.setAttribute('title', cached);\n return true;\n }\n\n let applied = 0;\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (applyToImg(img)) applied++;\n });\n\n // Watch for late-loading images (Framer SPA, lazy load)\n const observer = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n const imgs = node instanceof HTMLImageElement ? [node] :\n node instanceof HTMLElement ? Array.from(node.querySelectorAll<HTMLImageElement>('img')) : [];\n for (const img of imgs) applyToImg(img);\n }\n }\n });\n observer.observe(document.body, { childList: true, subtree: true });\n setTimeout(() => observer.disconnect(), 30000);\n\n return applied;\n}\n\n// ---------------------------------------------------------------------------\n// Feature Module\n// ---------------------------------------------------------------------------\n\nexport default function createAltTextModule(\n aiService?: AIService,\n initialLang: string = 'de',\n serverConfig?: { siteKey?: string; proxyUrl?: string },\n): FeatureModule {\n const siteKey = serverConfig?.siteKey || '';\n const proxyUrl = serverConfig?.proxyUrl || '';\n let enabled = false;\n let domObserver: MutationObserver | null = null;\n let autoGenerating = false;\n\n // Tracked images\n let missingAltImages: HTMLImageElement[] = [];\n const processedImages = new Map<HTMLImageElement, { generatedAlt: string }>();\n\n function lang(): string { return getCurrentWidgetLang() || initialLang; }\n function isDE(): boolean { return lang().startsWith('de'); }\n\n // -------------------------------------------------------------------------\n // Helpers\n // -------------------------------------------------------------------------\n\n function isGenericAlt(alt: string): boolean {\n if (!alt.trim()) return true;\n if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;\n if (/^IMG_\\d+/i.test(alt)) return true;\n if (/\\.(jpg|jpeg|png|gif|webp|svg|avif)$/i.test(alt)) return true;\n return false;\n }\n\n function isDecorativeImage(img: HTMLImageElement): boolean {\n const role = img.getAttribute('role');\n if (role === 'presentation' || role === 'none') return true;\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return true;\n return false;\n }\n\n function isValidImage(img: HTMLImageElement): boolean {\n if (img.closest('#accessify-root') || img.closest('accessify-widget')) return false;\n // Skip tiny images (icons, tracking pixels, avatars)\n if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return false;\n // Skip images not rendered on-screen (display:none, visibility:hidden, etc.)\n const rect = img.getBoundingClientRect();\n if (rect.width < 40 || rect.height < 40) return false;\n // Skip images hidden via CSS (opacity:0, visibility:hidden)\n const style = getComputedStyle(img);\n if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;\n // Skip images with role=\"presentation\" or aria-hidden\n if (img.getAttribute('role') === 'presentation' || img.getAttribute('aria-hidden') === 'true') return false;\n return true;\n }\n\n function needsAltText(img: HTMLImageElement): boolean {\n if (!isValidImage(img)) return false;\n const alt = img.getAttribute('alt');\n if (alt === null) return true;\n if (isGenericAlt(alt)) return true;\n if (alt === '' && !isDecorativeImage(img)) return true;\n return false;\n }\n\n function scanForMissingAlt(): HTMLImageElement[] {\n const missing: HTMLImageElement[] = [];\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (needsAltText(img)) missing.push(img);\n });\n document.querySelectorAll<HTMLElement>('picture').forEach((picture) => {\n if (picture.closest('#accessify-root') || picture.closest('accessify-widget')) return;\n const img = picture.querySelector('img');\n if (img && !missing.includes(img) && needsAltText(img)) {\n missing.push(img);\n }\n });\n return missing;\n }\n\n function gatherImageContext(img: HTMLImageElement): string {\n const parts: string[] = [];\n try {\n const url = new URL(getImageSrc(img), window.location.href);\n const filename = url.pathname.split('/').pop();\n if (filename) parts.push(`Filename: ${filename}`);\n } catch {}\n const figure = img.closest('figure');\n if (figure) {\n const caption = figure.querySelector('figcaption');\n if (caption?.textContent?.trim()) parts.push(`Caption: ${caption.textContent.trim()}`);\n }\n const container = img.parentElement?.parentElement || img.parentElement;\n if (container) {\n const heading = container.querySelector('h1, h2, h3, h4, h5, h6');\n if (heading?.textContent?.trim()) parts.push(`Nearby heading: ${heading.textContent.trim()}`);\n }\n return parts.join('. ');\n }\n\n // -------------------------------------------------------------------------\n // Apply + Generate (title = native hover tooltip on every image)\n // -------------------------------------------------------------------------\n\n function applyAltText(img: HTMLImageElement, altText: string) {\n img.setAttribute('alt', altText);\n img.setAttribute('title', altText);\n processedImages.set(img, { generatedAlt: altText });\n if (enabled) addInfoBadge(img, altText);\n }\n\n /** Set title on every visible image that has alt text but no title yet */\n function applyTitlesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n // Skip if already has a title\n if (img.getAttribute('title')) return;\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n });\n }\n\n // -------------------------------------------------------------------------\n // Info badge — small \"i\" icon on each image with alt text\n // -------------------------------------------------------------------------\n // Badges live in a single overlay container on document.body (position:fixed\n // would need scroll tracking, so we use position:absolute on the body).\n // This keeps them completely outside any overflow:hidden zoom containers.\n // -------------------------------------------------------------------------\n\n const BADGE_ATTR = 'data-accessify-badge';\n const WRAPPER_ATTR = 'data-accessify-badge-wrap';\n const OVERLAY_ID = 'accessify-badge-overlay';\n const BADGE_STYLE_ID = 'accessify-badge-styles';\n let badgePositionRAF: number | null = null;\n let trackedBadges: Array<{ target: HTMLElement; badge: HTMLElement; tooltip: HTMLElement }> = [];\n let outsideClickHandler: ((e: Event) => void) | null = null;\n\n function getOrCreateOverlay(): HTMLElement {\n let overlay = document.getElementById(OVERLAY_ID);\n if (!overlay) {\n overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '0',\n height: '0',\n overflow: 'visible',\n pointerEvents: 'none',\n zIndex: '10000',\n });\n document.body.appendChild(overlay);\n }\n // Inject badge hover + coarse pointer styles once\n if (!document.getElementById(BADGE_STYLE_ID)) {\n const style = document.createElement('style');\n style.id = BADGE_STYLE_ID;\n style.textContent = `\n [${BADGE_ATTR}=\"badge\"]:hover + [${BADGE_ATTR}=\"tooltip\"] { display: block !important; }\n [${BADGE_ATTR}=\"badge\"]:hover { background: rgba(0,0,0,0.85) !important; }\n @media (pointer: coarse) {\n [${BADGE_ATTR}=\"badge\"] { width: 36px !important; height: 36px !important; line-height: 36px !important; font-size: 16px !important; }\n }\n `;\n document.head.appendChild(style);\n }\n return overlay;\n }\n\n function positionBadge(target: HTMLElement, badge: HTMLElement, tooltip: HTMLElement) {\n const rect = target.getBoundingClientRect();\n // Skip if element is not visible / too small / off-screen\n if (rect.width < 40 || rect.height < 40 ||\n rect.bottom < 0 || rect.top > window.innerHeight + 200 ||\n rect.right < 0 || rect.left > window.innerWidth + 200) {\n badge.style.display = 'none';\n tooltip.style.display = 'none';\n return;\n }\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n const top = rect.top + scrollY + 6;\n const left = rect.left + scrollX + 6;\n badge.style.display = '';\n badge.style.top = `${top}px`;\n badge.style.left = `${left}px`;\n // Tooltip positioned below badge\n tooltip.style.top = `${top + 26}px`;\n tooltip.style.left = `${left}px`;\n }\n\n function updateAllBadgePositions() {\n for (const { target, badge, tooltip } of trackedBadges) {\n if (!document.body.contains(target)) continue;\n positionBadge(target, badge, tooltip);\n }\n }\n\n function startBadgeTracking() {\n if (badgePositionRAF !== null) return;\n const tick = () => {\n updateAllBadgePositions();\n badgePositionRAF = requestAnimationFrame(tick);\n };\n badgePositionRAF = requestAnimationFrame(tick);\n\n // Outside-click handler to close all open tooltips\n if (!outsideClickHandler) {\n outsideClickHandler = (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.getAttribute(BADGE_ATTR) === 'badge') return;\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n };\n document.addEventListener('click', outsideClickHandler, { passive: true });\n }\n }\n\n function stopBadgeTracking() {\n if (badgePositionRAF !== null) {\n cancelAnimationFrame(badgePositionRAF);\n badgePositionRAF = null;\n }\n if (outsideClickHandler) {\n document.removeEventListener('click', outsideClickHandler);\n outsideClickHandler = null;\n }\n }\n\n function addInfoBadge(target: HTMLElement, altText: string) {\n if (target.getAttribute(BADGE_ATTR)) return;\n target.setAttribute(BADGE_ATTR, '1');\n\n const overlay = getOrCreateOverlay();\n\n // Badge \"i\" circle\n const badge = document.createElement('span');\n Object.assign(badge.style, {\n position: 'absolute',\n width: '22px',\n height: '22px',\n borderRadius: '50%',\n background: 'rgba(0,0,0,0.6)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontWeight: 'bold',\n fontSize: '13px',\n lineHeight: '22px',\n textAlign: 'center',\n cursor: 'default',\n pointerEvents: 'auto',\n boxShadow: '0 1px 4px rgba(0,0,0,0.4)',\n transition: 'background 0.15s',\n });\n badge.textContent = 'i';\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('translate', 'no');\n badge.classList.add('notranslate');\n badge.setAttribute(BADGE_ATTR, 'badge');\n\n // Tooltip\n const tooltip = document.createElement('span');\n Object.assign(tooltip.style, {\n display: 'none',\n position: 'absolute',\n minWidth: '150px',\n maxWidth: '280px',\n padding: '6px 10px',\n background: 'rgba(0,0,0,0.88)',\n color: '#fff',\n fontFamily: 'sans-serif',\n fontSize: '12px',\n lineHeight: '1.4',\n borderRadius: '6px',\n pointerEvents: 'none',\n wordWrap: 'break-word',\n boxShadow: '0 2px 8px rgba(0,0,0,0.3)',\n zIndex: '1',\n });\n tooltip.textContent = altText;\n tooltip.setAttribute('translate', 'no');\n tooltip.classList.add('notranslate');\n tooltip.setAttribute(BADGE_ATTR, 'tooltip');\n\n badge.addEventListener('click', () => {\n const isOpen = tooltip.style.display === 'block';\n // Close all other open tooltips first\n for (const entry of trackedBadges) {\n entry.tooltip.style.display = 'none';\n entry.badge.style.background = 'rgba(0,0,0,0.6)';\n }\n if (!isOpen) {\n badge.style.background = 'rgba(0,0,0,0.85)';\n tooltip.style.display = 'block';\n }\n });\n\n overlay.appendChild(badge);\n overlay.appendChild(tooltip);\n\n // Initial position\n positionBadge(target, badge, tooltip);\n\n // Track for continuous position updates\n trackedBadges.push({ target, badge, tooltip });\n }\n\n function removeAllBadges() {\n stopBadgeTracking();\n trackedBadges = [];\n // Remove overlay and badge styles\n document.getElementById(OVERLAY_ID)?.remove();\n document.getElementById(BADGE_STYLE_ID)?.remove();\n // Clear badge markers\n document.querySelectorAll(`[${BADGE_ATTR}]`).forEach(el => el.removeAttribute(BADGE_ATTR));\n // Legacy: unwrap any leftover wrappers from old version\n document.querySelectorAll<HTMLElement>(`[${WRAPPER_ATTR}]`).forEach(wrapper => {\n const img = wrapper.querySelector('img');\n if (img && wrapper.parentElement) {\n wrapper.parentElement.insertBefore(img, wrapper);\n wrapper.remove();\n }\n });\n }\n\n /** Add info badges to ALL visible images */\n function addBadgesToAllImages() {\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!isValidImage(img)) return;\n const alt = img.getAttribute('alt') || img.getAttribute('title');\n if (alt && alt.trim()) {\n addInfoBadge(img, alt.trim());\n }\n });\n // Also for background images\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n const alt = el.getAttribute('aria-label');\n if (alt && alt.trim()) {\n addInfoBadge(el, alt.trim());\n }\n });\n // Start tracking positions (handles scroll, resize, zoom)\n if (trackedBadges.length > 0) startBadgeTracking();\n }\n\n function removeTitles() {\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-title=\"auto\"]').forEach((img) => {\n img.removeAttribute('title');\n img.removeAttribute('data-accessify-title');\n });\n // Clean up background image descriptions\n document.querySelectorAll<HTMLElement>('[data-accessify-bg-alt]').forEach((el) => {\n el.removeAttribute('role');\n el.removeAttribute('aria-label');\n el.removeAttribute('title');\n el.removeAttribute('data-accessify-bg-alt');\n });\n // Remove all info badges\n removeAllBadges();\n }\n\n // -------------------------------------------------------------------------\n // Background images (CSS background-image)\n // -------------------------------------------------------------------------\n\n /** Find significant elements with CSS background-image and no accessibility info */\n function scanForBackgroundImages(): HTMLElement[] {\n const found: HTMLElement[] = [];\n // Scan ALL elements — not just specific class patterns — for background-image\n const allElements = document.querySelectorAll<HTMLElement>('*');\n for (const el of allElements) {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) continue;\n if (el.getAttribute('data-accessify-bg-alt')) continue;\n // Skip tiny or invisible elements quickly via offsetHeight (avoids getComputedStyle)\n if (el.offsetWidth < 200 || el.offsetHeight < 150) continue;\n const style = getComputedStyle(el);\n const bg = style.backgroundImage;\n if (!bg || bg === 'none') continue;\n // Must have a url() reference (not just gradients)\n const urlMatch = bg.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n if (!urlMatch) continue;\n // Skip SVG data URIs and tiny inline images\n if (urlMatch[1].startsWith('data:image/svg')) continue;\n // Skip if already has role=\"img\" with aria-label\n if (el.getAttribute('role') === 'img' && el.getAttribute('aria-label')) continue;\n found.push(el);\n }\n return found;\n }\n\n function getBackgroundImageUrl(el: HTMLElement): string | null {\n const bg = getComputedStyle(el).backgroundImage;\n const match = bg?.match(/url\\([\"']?([^\"')]+)[\"']?\\)/);\n return match ? match[1] : null;\n }\n\n function applyBgAlt(el: HTMLElement, altText: string) {\n el.setAttribute('role', 'img');\n el.setAttribute('aria-label', altText);\n el.setAttribute('title', altText);\n el.setAttribute('data-accessify-bg-alt', 'auto');\n if (enabled) addInfoBadge(el, altText);\n }\n\n async function generateBgAlts() {\n if (!aiService || !enabled) return;\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info('[Accessify] alt-text: siteMode=manual — skipping live generation for background images');\n }\n return;\n }\n const bgElements = scanForBackgroundImages();\n for (const el of bgElements) {\n if (!enabled) break;\n const src = getBackgroundImageUrl(el);\n if (!src) continue;\n // Check cache first\n const cached = await getCachedAltText(src);\n if (cached) {\n applyBgAlt(el, cached);\n continue;\n }\n // Generate via AI\n try {\n const ctx = gatherBgContext(el);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyBgAlt(el, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Bg alt-text generation failed:', src, err);\n }\n }\n }\n\n function gatherBgContext(el: HTMLElement): string {\n const parts: string[] = [];\n // Tag and class hints\n parts.push(`Element: <${el.tagName.toLowerCase()}>`);\n if (el.className) parts.push(`Class: ${el.className}`);\n // Text inside\n const text = el.textContent?.trim().slice(0, 100);\n if (text) parts.push(`Overlay text: ${text}`);\n // Nearby heading\n const heading = el.querySelector('h1, h2, h3');\n if (heading?.textContent?.trim()) parts.push(`Heading: ${heading.textContent.trim()}`);\n return parts.join('. ');\n }\n\n async function generateAll() {\n if (autoGenerating || !enabled || !aiService) return;\n autoGenerating = true;\n const CONCURRENCY = 3;\n\n // Phase 1: apply from IndexedDB cache\n const uncached: HTMLImageElement[] = [];\n for (const img of missingAltImages) {\n if (!enabled) { autoGenerating = false; return; }\n if (processedImages.has(img)) continue;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) {\n applyAltText(img, cached);\n } else {\n uncached.push(img);\n }\n }\n\n if (!enabled) { autoGenerating = false; return; }\n if (!uncached.length) { autoGenerating = false; return; }\n\n // SAFETY GATE: only proceed with live AI if site is in 'auto' mode.\n // In 'manual' (default), leave images without generated alt text — the\n // owner must trigger a crawl or switch modes from the dashboard.\n if (currentAltSiteMode !== 'auto') {\n if ((window as any).__ACCESSIFY_DEBUG) {\n console.info(\n `[Accessify] alt-text: siteMode=manual — ${uncached.length} image(s) left untouched. ` +\n `Trigger a crawl from the dashboard or enable auto mode.`,\n );\n }\n autoGenerating = false;\n return;\n }\n\n // Phase 2: AI generation in parallel batches\n for (let i = 0; i < uncached.length; i += CONCURRENCY) {\n if (!enabled) { autoGenerating = false; return; }\n const batch = uncached.slice(i, i + CONCURRENCY);\n await Promise.all(batch.map(async (img) => {\n if (!enabled) return;\n try {\n const src = getImageSrc(img);\n const ctx = gatherImageContext(img);\n const alt = await aiService!.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', getImageSrc(img), err);\n }\n }));\n }\n\n autoGenerating = false;\n }\n\n async function generateSingle(img: HTMLImageElement) {\n if (!aiService || !enabled) return;\n const src = getImageSrc(img);\n const cached = await getCachedAltText(src);\n if (cached) { applyAltText(img, cached); return; }\n\n // Mode gate — only live-generate when site is in 'auto' mode\n if (currentAltSiteMode !== 'auto') return;\n\n try {\n const ctx = gatherImageContext(img);\n const alt = await aiService.generateAltText(src, ctx, lang());\n if (alt && enabled) {\n applyAltText(img, alt);\n setCachedAltText(src, alt, lang()).catch(() => {});\n if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());\n }\n } catch (err) {\n console.warn('[Accessify] Alt-text generation failed:', src, err);\n }\n }\n\n // -------------------------------------------------------------------------\n // Dynamic image registration\n // -------------------------------------------------------------------------\n\n function tryRegisterImage(img: HTMLImageElement) {\n if (!enabled) return;\n if (!isValidImage(img)) return;\n if (missingAltImages.includes(img)) return;\n\n function addIfValid() {\n if (!enabled || missingAltImages.includes(img)) return;\n if (img.naturalWidth < 20 || img.naturalHeight < 20) return;\n\n if (needsAltText(img)) {\n missingAltImages.push(img);\n generateSingle(img);\n } else {\n // Image has alt but maybe no title/badge yet — add both\n const alt = img.getAttribute('alt');\n if (alt && alt.trim()) {\n if (!img.getAttribute('title')) {\n img.setAttribute('title', alt);\n img.setAttribute('data-accessify-title', 'auto');\n }\n addInfoBadge(img, alt.trim());\n }\n }\n }\n\n if (img.complete && img.naturalWidth > 0) addIfValid();\n else img.addEventListener('load', addIfValid, { once: true });\n }\n\n // -------------------------------------------------------------------------\n // Lifecycle\n // -------------------------------------------------------------------------\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Recognize images that were auto-applied from cache/manifest\n document.querySelectorAll<HTMLImageElement>('img[data-accessify-alt=\"auto\"]').forEach((img) => {\n if (img.closest('#accessify-root')) return;\n if (!processedImages.has(img)) {\n processedImages.set(img, { generatedAlt: img.getAttribute('alt') || '' });\n missingAltImages.push(img);\n }\n });\n\n // Scan for truly missing alt texts\n const missing = scanForMissingAlt();\n for (const img of missing) {\n if (!missingAltImages.includes(img)) {\n missingAltImages.push(img);\n }\n }\n\n // Start AI generation in background (img + background images)\n generateAll();\n generateBgAlts();\n\n // Set title on ALL images (consistent hover tooltip everywhere)\n applyTitlesToAllImages();\n\n // Add info badges to show alt text is available\n addBadgesToAllImages();\n\n // Register not-yet-loaded images\n document.querySelectorAll<HTMLImageElement>('img').forEach((img) => {\n if (!img.complete) tryRegisterImage(img);\n });\n\n // Delayed re-scans for late-loading images and AI-generated alt texts\n for (const delay of [2000, 5000, 10000]) {\n setTimeout(() => {\n if (enabled) {\n document.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n applyTitlesToAllImages();\n addBadgesToAllImages();\n }\n }, delay);\n }\n\n // Watch for new images\n domObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n for (const node of m.addedNodes) {\n if (node instanceof HTMLImageElement) tryRegisterImage(node);\n else if (node instanceof HTMLElement) {\n node.querySelectorAll<HTMLImageElement>('img').forEach(tryRegisterImage);\n }\n }\n }\n });\n domObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function deactivate() {\n enabled = false;\n autoGenerating = false;\n domObserver?.disconnect();\n domObserver = null;\n\n // Remove auto-added titles (but keep alt texts — those are useful)\n removeTitles();\n missingAltImages = [];\n }\n\n // Run auto-apply immediately when the module is created\n autoApplyCachedAltTexts({ siteKey, proxyUrl, lang: initialLang }).catch(() => {});\n\n return {\n id: 'alt-text',\n name: () => (isDE() ? 'Bildbeschreibung' : 'Image Description'),\n description: isDE() ? 'Bildbeschreibungen per Hover anzeigen und fehlende automatisch erzeugen' : 'Show image descriptions on hover and auto-generate missing ones',\n icon: 'alt-text',\n category: 'ai',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'alt-text',\n enabled,\n value: {\n missingCount: missingAltImages.filter((img) => !processedImages.has(img)).length,\n processedCount: processedImages.size,\n },\n }),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -6644,17 +6644,17 @@ function FeatureGrid($$anchor, $$props) {
6644
6644
  const FEATURE_LOADERS = {
6645
6645
  contrast: () => import("./contrast-CqsOs6Uo.js"),
6646
6646
  "text-size": () => import("./text-size-m_mHNPWo.js"),
6647
- "keyboard-nav": () => import("./keyboard-nav-Bykt8VwT.js"),
6647
+ "keyboard-nav": () => import("./keyboard-nav-C3G7ZKjD.js"),
6648
6648
  "link-highlight": () => import("./link-highlight-D9gxFmiG.js"),
6649
6649
  "reading-guide": () => import("./reading-guide-C_jxzorm.js"),
6650
6650
  "reading-mask": () => import("./reading-mask-B_NxbhTN.js"),
6651
6651
  "animation-stop": () => import("./animation-stop-_C-YdTs3.js"),
6652
6652
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6653
6653
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6654
- "page-structure": () => import("./page-structure-CuafhkRb.js"),
6654
+ "page-structure": () => import("./page-structure-BuEeO_fi.js"),
6655
6655
  tts: () => import("./tts-zrXtEd07.js"),
6656
6656
  "text-simplify": () => import("./text-simplify-H4aHr88a.js"),
6657
- "alt-text": () => import("./alt-text-BDEUXN9O.js")
6657
+ "alt-text": () => import("./alt-text-D_iJlJtX.js")
6658
6658
  };
6659
6659
  let contrastMode = /* @__PURE__ */ state(proxy(readStoredContrastMode()));
6660
6660
  let textSize = /* @__PURE__ */ state(proxy(readStoredTextSize()));
@@ -6971,8 +6971,8 @@ function FeatureGrid($$anchor, $$props) {
6971
6971
  pop();
6972
6972
  }
6973
6973
  delegate(["click"]);
6974
- var root_1$1 = /* @__PURE__ */ from_html(`<span aria-hidden="true">&middot;</span> <a target="_blank" rel="noopener noreferrer"> </a>`, 1);
6975
- var root$1 = /* @__PURE__ */ from_html(`<div class="accessify-footer"><div class="accessify-footer-links"><a target="_blank" rel="noopener noreferrer">Accessify Dashboard</a> <!></div> <button class="accessify-footer-close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> <span> </span></button></div>`);
6974
+ var root_1$1 = /* @__PURE__ */ from_html(`<span aria-hidden="true">&middot;</span> <a target="_blank" rel="noopener noreferrer"> <span class="sr-only">↗</span></a>`, 1);
6975
+ var root$1 = /* @__PURE__ */ from_html(`<div class="accessify-footer"><div class="accessify-footer-links"><a target="_blank" rel="noopener noreferrer">Accessify Dashboard <span class="sr-only">↗</span></a> <!></div> <button class="accessify-footer-close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> <span> </span></button></div>`);
6976
6976
  function PanelFooter($$anchor, $$props) {
6977
6977
  push($$props, true);
6978
6978
  let lang = prop($$props, "lang", 3, "en");
@@ -6988,7 +6988,7 @@ function PanelFooter($$anchor, $$props) {
6988
6988
  template_effect(
6989
6989
  ($0) => {
6990
6990
  set_attribute(a_1, "href", $$props.statementUrl);
6991
- set_text(text, $0);
6991
+ set_text(text, `${$0 ?? ""} `);
6992
6992
  },
6993
6993
  [() => t("widget.statement", lang())]
6994
6994
  );
@@ -7382,7 +7382,7 @@ function createTextTransformService() {
7382
7382
  var root_3 = /* @__PURE__ */ from_svg(`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>`);
7383
7383
  var root_2 = /* @__PURE__ */ from_html(`<button class="accessify-lang-option" role="option"><span> </span> <!></button>`);
7384
7384
  var root_1 = /* @__PURE__ */ from_html(`<div id="accessify-lang-list" class="accessify-lang-list" role="listbox"></div>`);
7385
- var root = /* @__PURE__ */ from_html(`<div class="sr-only" role="status" aria-live="polite" aria-atomic="true"> </div> <!> <div class="accessify-panel" role="dialog"><!> <div class="accessify-body"><div class="accessify-lang-dropdown"><button class="accessify-lang-toggle" aria-controls="accessify-lang-list"><span class="accessify-lang-toggle-left"><!> <span> </span></span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></button> <!></div> <div class="accessify-section-divider"></div> <!> <div class="accessify-section-divider"></div> <!></div> <!></div>`, 1);
7385
+ var root = /* @__PURE__ */ from_html(`<div class="sr-only" role="status" aria-live="polite" aria-atomic="true"> </div> <!> <div class="accessify-panel" role="dialog" aria-modal="true"><!> <div class="accessify-body"><div class="accessify-lang-dropdown"><button class="accessify-lang-toggle" aria-controls="accessify-lang-list"><span class="accessify-lang-toggle-left"><!> <span> </span></span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></button> <!></div> <div class="accessify-section-divider"></div> <!> <div class="accessify-section-divider"></div> <!></div> <!></div>`, 1);
7386
7386
  function WidgetApp($$anchor, $$props) {
7387
7387
  push($$props, true);
7388
7388
  let config2 = prop($$props, "config", 7);
@@ -8075,10 +8075,10 @@ function createWidgetStyles(config2) {
8075
8075
  display: inline-flex; align-items: center; justify-content: center;
8076
8076
  width: 22px; height: 22px; border-radius: 999px;
8077
8077
  color: var(--text-dim); cursor: help; background: none; border: none;
8078
- opacity: 0.5; transition: opacity var(--fast), color var(--fast);
8078
+ opacity: 0.65; transition: opacity var(--fast), color var(--fast);
8079
8079
  }
8080
8080
  .accessify-card-info svg { width: 14px; height: 14px; }
8081
- .accessify-card-info:hover, .accessify-card-info:active { opacity: 1; color: var(--accent); }
8081
+ .accessify-card-info:hover, .accessify-card-info:active, .accessify-card-info:focus-visible { opacity: 1; color: var(--accent); }
8082
8082
 
8083
8083
  /* ─── Section Divider ─── */
8084
8084
  .accessify-section-divider {
@@ -8181,6 +8181,7 @@ const DEFAULT_CONFIG = {
8181
8181
  let widgetInstance = null;
8182
8182
  let containerEl = null;
8183
8183
  let config = { ...DEFAULT_CONFIG };
8184
+ let cleanupListeners = null;
8184
8185
  async function fetchSiteConfig(siteKey, proxyUrl) {
8185
8186
  try {
8186
8187
  const base = proxyUrl || "https://accessify-api.accessify.workers.dev";
@@ -8283,13 +8284,14 @@ async function init(userConfig = {}) {
8283
8284
  if (handled) e.stopImmediatePropagation();
8284
8285
  }, true);
8285
8286
  }
8286
- window.addEventListener("accessify:reposition", ((e) => {
8287
+ const handleReposition = ((e) => {
8287
8288
  const newPos = e.detail?.position;
8288
8289
  if (newPos && config) {
8289
8290
  config.position = newPos;
8290
8291
  sheet.replaceSync(createWidgetStyles(config));
8291
8292
  }
8292
- }));
8293
+ });
8294
+ window.addEventListener("accessify:reposition", handleReposition);
8293
8295
  const ALLOWED_PREVIEW_ORIGINS = [
8294
8296
  "https://accessify-dashboard.pages.dev",
8295
8297
  "https://accessify.dev",
@@ -8310,7 +8312,7 @@ async function init(userConfig = {}) {
8310
8312
  }
8311
8313
  return false;
8312
8314
  }
8313
- window.addEventListener("message", (e) => {
8315
+ const handleMessage = (e) => {
8314
8316
  if (!isAllowedPreviewOrigin(e.origin)) return;
8315
8317
  if (e.data?.type === "accessify:preview-config") {
8316
8318
  const preview = e.data.config || {};
@@ -8323,13 +8325,20 @@ async function init(userConfig = {}) {
8323
8325
  if (panel) panel.setAttribute("aria-hidden", "false");
8324
8326
  if (trigger) trigger.setAttribute("aria-expanded", "true");
8325
8327
  }
8326
- });
8328
+ };
8329
+ window.addEventListener("message", handleMessage);
8330
+ cleanupListeners = () => {
8331
+ window.removeEventListener("accessify:reposition", handleReposition);
8332
+ window.removeEventListener("message", handleMessage);
8333
+ };
8327
8334
  document.body.appendChild(containerEl);
8328
- import("./alt-text-BDEUXN9O.js").then((m) => m.autoApplyCachedAltTexts(config)).catch(() => {
8335
+ import("./alt-text-D_iJlJtX.js").then((m) => m.autoApplyCachedAltTexts(config)).catch(() => {
8329
8336
  });
8330
8337
  config.onReady?.();
8331
8338
  }
8332
8339
  function destroy() {
8340
+ cleanupListeners?.();
8341
+ cleanupListeners = null;
8333
8342
  if (widgetInstance) {
8334
8343
  unmount(widgetInstance);
8335
8344
  widgetInstance = null;
@@ -8368,4 +8377,4 @@ export {
8368
8377
  init as i,
8369
8378
  t
8370
8379
  };
8371
- //# sourceMappingURL=index-yV-nq3Z-.js.map
8380
+ //# sourceMappingURL=index-BUfTIuEG.js.map