accessify-widget 0.3.81 → 0.3.82
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/{alt-text-By2PvE1U.js → alt-text-Dg2ted6-.js} +5 -3
- package/dist/alt-text-Dg2ted6-.js.map +1 -0
- package/dist/{animation-stop-C2Ced0LV.js → animation-stop-C4OcBKkR.js} +32 -10
- package/dist/animation-stop-C4OcBKkR.js.map +1 -0
- package/dist/{index-B8IGMa5t.js → index-Bdke9nRb.js} +14 -9
- package/dist/{index-B8IGMa5t.js.map → index-Bdke9nRb.js.map} +1 -1
- package/dist/{keyboard-nav-BZXsqIA2.js → keyboard-nav-AFyqDbnd.js} +2 -2
- package/dist/{keyboard-nav-BZXsqIA2.js.map → keyboard-nav-AFyqDbnd.js.map} +1 -1
- package/dist/{page-structure-BKyxP7oX.js → page-structure-BpCqEHJ6.js} +7 -3
- package/dist/page-structure-BpCqEHJ6.js.map +1 -0
- package/dist/{text-simplify-H4aHr88a.js → text-simplify-7XhQbbXL.js} +5 -3
- package/dist/{text-simplify-H4aHr88a.js.map → text-simplify-7XhQbbXL.js.map} +1 -1
- package/dist/{tts-zrXtEd07.js → tts-64TqRR7s.js} +9 -6
- package/dist/tts-64TqRR7s.js.map +1 -0
- package/dist/widget.js +1 -1
- package/dist/widget.js.map +1 -1
- package/package.json +10 -10
- package/LICENSE +0 -21
- package/dist/alt-text-By2PvE1U.js.map +0 -1
- package/dist/animation-stop-C2Ced0LV.js.map +0 -1
- package/dist/page-structure-BKyxP7oX.js.map +0 -1
- package/dist/tts-zrXtEd07.js.map +0 -1
package/dist/accessify.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as getCurrentWidgetLang } from "./index-
|
|
1
|
+
import { g as getCurrentWidgetLang } from "./index-Bdke9nRb.js";
|
|
2
2
|
const IDB_NAME = "accessify-alt-text-cache";
|
|
3
3
|
const IDB_STORE = "alt-texts";
|
|
4
4
|
const IDB_VERSION = 2;
|
|
@@ -309,7 +309,9 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
|
|
|
309
309
|
height: "0",
|
|
310
310
|
overflow: "visible",
|
|
311
311
|
pointerEvents: "none",
|
|
312
|
-
zIndex: "10000"
|
|
312
|
+
zIndex: "10000",
|
|
313
|
+
// Hide badge overlay on mobile — badges flood the viewport
|
|
314
|
+
display: window.innerWidth <= 640 ? "none" : ""
|
|
313
315
|
});
|
|
314
316
|
document.body.appendChild(overlay);
|
|
315
317
|
}
|
|
@@ -742,4 +744,4 @@ export {
|
|
|
742
744
|
autoApplyCachedAltTexts,
|
|
743
745
|
createAltTextModule as default
|
|
744
746
|
};
|
|
745
|
-
//# sourceMappingURL=alt-text-
|
|
747
|
+
//# sourceMappingURL=alt-text-Dg2ted6-.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alt-text-Dg2ted6-.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 // Hide badge overlay on mobile — badges flood the viewport\n display: window.innerWidth <= 640 ? 'none' : '',\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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"}
|
|
@@ -3,12 +3,14 @@ function createAnimationStopModule() {
|
|
|
3
3
|
const STYLE_ID = "a11y-stop-animations";
|
|
4
4
|
const STORAGE_KEY = "accessify-animation-stop";
|
|
5
5
|
let mutationObserver = null;
|
|
6
|
+
let mutationDebounceTimer = null;
|
|
6
7
|
let scanInterval = null;
|
|
7
8
|
let scrollHandler = null;
|
|
8
9
|
let originalVideoPlay = null;
|
|
9
10
|
let originalAnimate = null;
|
|
10
11
|
let pausedVideos = [];
|
|
11
12
|
let gifOriginals = /* @__PURE__ */ new Map();
|
|
13
|
+
let delayedTimers = [];
|
|
12
14
|
const VISUAL_ONLY_PROPS = /* @__PURE__ */ new Set([
|
|
13
15
|
"transform",
|
|
14
16
|
"scale",
|
|
@@ -189,9 +191,10 @@ function createAnimationStopModule() {
|
|
|
189
191
|
function forceHiddenElementsVisible() {
|
|
190
192
|
const viewH = window.innerHeight;
|
|
191
193
|
const margin = viewH * 1.5;
|
|
192
|
-
const all = document.querySelectorAll(
|
|
194
|
+
const all = document.querySelectorAll(
|
|
195
|
+
'[style*="opacity"], [style*="transform"], [style*="visibility"], [style*="clip-path"], [data-framer-appear-id]'
|
|
196
|
+
);
|
|
193
197
|
for (const el of all) {
|
|
194
|
-
if (el.tagName === "SCRIPT" || el.tagName === "STYLE" || el.tagName === "NOSCRIPT" || el.tagName === "META" || el.tagName === "LINK") continue;
|
|
195
198
|
if (el.closest("#accessify-root") || el.closest("accessify-widget")) continue;
|
|
196
199
|
if (el.dataset.a11yOrigStyle) continue;
|
|
197
200
|
const computed = window.getComputedStyle(el);
|
|
@@ -269,6 +272,9 @@ function createAnimationStopModule() {
|
|
|
269
272
|
if (frozen.transform && el.style.transform !== frozen.transform) {
|
|
270
273
|
el.style.transform = frozen.transform;
|
|
271
274
|
}
|
|
275
|
+
if (frozen.opacity && el.style.opacity !== frozen.opacity) {
|
|
276
|
+
el.style.opacity = frozen.opacity;
|
|
277
|
+
}
|
|
272
278
|
} catch {
|
|
273
279
|
}
|
|
274
280
|
});
|
|
@@ -398,11 +404,16 @@ function createAnimationStopModule() {
|
|
|
398
404
|
}
|
|
399
405
|
}
|
|
400
406
|
if (hasNewContent) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
407
|
+
if (mutationDebounceTimer) clearTimeout(mutationDebounceTimer);
|
|
408
|
+
mutationDebounceTimer = setTimeout(() => {
|
|
409
|
+
mutationDebounceTimer = null;
|
|
410
|
+
if (!enabled) return;
|
|
411
|
+
finishAllAnimations();
|
|
412
|
+
forceHiddenElementsVisible();
|
|
413
|
+
pauseAllVideos();
|
|
414
|
+
freezeAllGifs();
|
|
415
|
+
pauseSVG();
|
|
416
|
+
}, 150);
|
|
406
417
|
}
|
|
407
418
|
});
|
|
408
419
|
mutationObserver.observe(document.body, { childList: true, subtree: true });
|
|
@@ -410,13 +421,21 @@ function createAnimationStopModule() {
|
|
|
410
421
|
function teardownObserver() {
|
|
411
422
|
mutationObserver?.disconnect();
|
|
412
423
|
mutationObserver = null;
|
|
424
|
+
if (mutationDebounceTimer) {
|
|
425
|
+
clearTimeout(mutationDebounceTimer);
|
|
426
|
+
mutationDebounceTimer = null;
|
|
427
|
+
}
|
|
413
428
|
}
|
|
414
429
|
function startPeriodicScan() {
|
|
415
430
|
if (scanInterval) return;
|
|
416
431
|
scanInterval = setInterval(() => {
|
|
417
432
|
if (!enabled) return;
|
|
433
|
+
try {
|
|
434
|
+
if (document.getAnimations?.().length === 0) return;
|
|
435
|
+
} catch {
|
|
436
|
+
}
|
|
418
437
|
finishAllAnimations();
|
|
419
|
-
},
|
|
438
|
+
}, 2e3);
|
|
420
439
|
}
|
|
421
440
|
function stopPeriodicScan() {
|
|
422
441
|
if (scanInterval) {
|
|
@@ -441,7 +460,7 @@ function createAnimationStopModule() {
|
|
|
441
460
|
setupObserver();
|
|
442
461
|
startPeriodicScan();
|
|
443
462
|
for (const delay of [50, 200, 500, 1e3, 2e3, 4e3]) {
|
|
444
|
-
setTimeout(() => {
|
|
463
|
+
const id = setTimeout(() => {
|
|
445
464
|
if (!enabled) return;
|
|
446
465
|
finishAllAnimations();
|
|
447
466
|
forceHiddenElementsVisible();
|
|
@@ -449,11 +468,14 @@ function createAnimationStopModule() {
|
|
|
449
468
|
pauseAllVideos();
|
|
450
469
|
freezeAllGifs();
|
|
451
470
|
}, delay);
|
|
471
|
+
delayedTimers.push(id);
|
|
452
472
|
}
|
|
453
473
|
localStorage.setItem(STORAGE_KEY, "true");
|
|
454
474
|
}
|
|
455
475
|
function deactivate() {
|
|
456
476
|
enabled = false;
|
|
477
|
+
for (const id of delayedTimers) clearTimeout(id);
|
|
478
|
+
delayedTimers = [];
|
|
457
479
|
stopPeriodicScan();
|
|
458
480
|
teardownObserver();
|
|
459
481
|
restoreAnimate();
|
|
@@ -485,4 +507,4 @@ function createAnimationStopModule() {
|
|
|
485
507
|
export {
|
|
486
508
|
createAnimationStopModule as default
|
|
487
509
|
};
|
|
488
|
-
//# sourceMappingURL=animation-stop-
|
|
510
|
+
//# sourceMappingURL=animation-stop-C4OcBKkR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animation-stop-C4OcBKkR.js","sources":["../src/features/animation-stop.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\n/**\n * Animation Stop – V4 (Clean 3-Layer Approach)\n *\n * Layer 1: CSS injection — kill all CSS animations/transitions via 0.001ms duration\n * Layer 2: Web Animations API — finish() all running WAAPI animations (Framer Motion etc.)\n * Layer 3: JS library detection — GSAP globalTimeline, inline-style freeze for rAF-based libs\n * Layer 4: Media — pause videos, freeze GIFs, stop SVG SMIL, stop marquees\n *\n * + MutationObserver for dynamic content\n * + Periodic re-scan (every 500ms) for frameworks that create new animations\n *\n * DOES NOT:\n * - Monkey-patch IntersectionObserver (breaks lazy loading)\n * - Override requestAnimationFrame (breaks entire page)\n * - Override Element.prototype.animate() (too invasive)\n * - Override matchMedia (too invasive)\n * - Set opacity:1 !important via CSS (breaks modals/hidden elements)\n * - Use animation:none or transition:none (breaks JS events)\n */\nexport default function createAnimationStopModule(): FeatureModule {\n let enabled = false;\n const STYLE_ID = 'a11y-stop-animations';\n const STORAGE_KEY = 'accessify-animation-stop';\n\n // --- State ---\n let mutationObserver: MutationObserver | null = null;\n let mutationDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let scanInterval: ReturnType<typeof setInterval> | null = null;\n let scrollHandler: (() => void) | null = null;\n let originalVideoPlay: typeof HTMLVideoElement.prototype.play | null = null;\n let originalAnimate: typeof Element.prototype.animate | null = null;\n let pausedVideos: HTMLVideoElement[] = [];\n let gifOriginals = new Map<HTMLImageElement, string>();\n let delayedTimers: ReturnType<typeof setTimeout>[] = [];\n\n // =========================================================================\n // Layer 0: Element.prototype.animate() intercept\n //\n // This is THE critical piece for Framer Motion. Framer uses WAAPI\n // (Element.prototype.animate()) for ALL visual animations — hover,\n // appear, scroll, transitions. CSS rules do NOT affect WAAPI.\n // We intercept at creation time and force duration to 0.001ms\n // so every animation completes instantly.\n // =========================================================================\n\n /**\n * Detect animations whose keyframes only modify transform-like or filter\n * properties. These are the signature of interaction animations (hover\n * zoom, click scale, focus rings) that Framer Motion and similar libs\n * create on-the-fly. We must CANCEL these instead of FINISHING them,\n * otherwise the element lands in the visible end-state (e.g. scale(1.05)).\n */\n const VISUAL_ONLY_PROPS = new Set([\n 'transform', 'scale', 'rotate', 'translate',\n 'filter', 'backdropFilter', 'backdrop-filter',\n 'webkitTransform', 'webkitFilter', '-webkit-transform', '-webkit-filter',\n 'offset', 'easing', 'composite',\n ]);\n function isVisualOnlyKeyframes(\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n ): boolean {\n if (!keyframes) return false;\n try {\n if (Array.isArray(keyframes)) {\n for (const kf of keyframes) {\n if (!kf || typeof kf !== 'object') return false;\n for (const key of Object.keys(kf)) {\n if (!VISUAL_ONLY_PROPS.has(key)) return false;\n }\n }\n return true;\n }\n // PropertyIndexedKeyframes\n for (const key of Object.keys(keyframes)) {\n if (!VISUAL_ONLY_PROPS.has(key)) return false;\n }\n return true;\n } catch {\n return false;\n }\n }\n\n function patchAnimate() {\n if (originalAnimate) return;\n originalAnimate = Element.prototype.animate;\n\n Element.prototype.animate = function (\n this: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n options?: number | KeyframeAnimationOptions,\n ): Animation {\n if (!enabled) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Never interfere with the widget's own animations. The widget lives\n // in shadow DOM under #accessify-root — walk up through shadow roots\n // and skip if we find the accessify host.\n try {\n let node: Node | null = this;\n while (node) {\n if ((node as Element).id === 'accessify-root') {\n return originalAnimate!.call(this, keyframes, options);\n }\n const parent = (node as any).parentNode || (node as any).host;\n if (parent === node) break;\n node = parent;\n }\n } catch { /* ignore */ }\n\n const visualOnly = isVisualOnlyKeyframes(keyframes);\n\n // Force instant completion: duration 0.001ms, no delay, 1 iteration, fill forwards\n let opts: KeyframeAnimationOptions;\n if (typeof options === 'number') {\n opts = { duration: 0.001, fill: 'forwards' as FillMode };\n } else {\n opts = {\n ...(options || {}),\n duration: 0.001,\n delay: 0,\n iterations: 1,\n fill: 'forwards' as FillMode,\n };\n // Remove iterationStart, endDelay etc. that could interfere\n delete (opts as any).iterationStart;\n delete (opts as any).endDelay;\n }\n\n const anim = originalAnimate!.call(this, keyframes, opts);\n try {\n if (visualOnly) {\n anim.cancel();\n } else {\n anim.finish();\n }\n } catch { /* ignore */ }\n return anim;\n };\n }\n\n function restoreAnimate() {\n if (originalAnimate) {\n Element.prototype.animate = originalAnimate;\n originalAnimate = null;\n }\n }\n\n // =========================================================================\n // Layer 1: CSS Injection\n // =========================================================================\n\n function injectStyles() {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n *, *::before, *::after {\n animation-duration: 0.001ms !important;\n animation-iteration-count: 1 !important;\n animation-delay: 0s !important;\n animation-fill-mode: forwards !important;\n transition-duration: 0.001ms !important;\n transition-delay: 0s !important;\n scroll-behavior: auto !important;\n animation-timeline: auto !important;\n scroll-timeline: none !important;\n }\n /* Neutralize interaction transforms (hover zoom, click scale, focus\n lift). Without this, CSS like \\`.card:hover { transform: scale(1.05) }\\`\n still visibly changes the element — just instantly. Users who\n disable animations expect NO motion including the end-state. */\n *:not(#accessify-root):not(#accessify-root *):hover,\n *:not(#accessify-root):not(#accessify-root *):focus,\n *:not(#accessify-root):not(#accessify-root *):focus-within,\n *:not(#accessify-root):not(#accessify-root *):focus-visible,\n *:not(#accessify-root):not(#accessify-root *):active {\n transform: none !important;\n scale: none !important;\n rotate: none !important;\n translate: none !important;\n }\n `;\n document.head.appendChild(style);\n }\n\n function removeStyles() {\n document.getElementById(STYLE_ID)?.remove();\n }\n\n // =========================================================================\n // Layer 2: Web Animations API — finish all WAAPI animations\n // =========================================================================\n\n function isWidgetAnimation(anim: Animation): boolean {\n try {\n const target = (anim.effect as any)?.target as Element | null;\n if (!target) return false;\n let node: Node | null = target;\n while (node) {\n if ((node as Element).id === 'accessify-root') return true;\n const parent = (node as any).parentNode || (node as any).host;\n if (parent === node) break;\n node = parent;\n }\n } catch { /* ignore */ }\n return false;\n }\n\n function finishAllAnimations() {\n try {\n const animations = document.getAnimations?.();\n if (!animations) return;\n for (const anim of animations) {\n if (isWidgetAnimation(anim)) continue;\n try {\n anim.finish();\n } catch {\n try { anim.cancel(); } catch { /* ignore */ }\n }\n }\n } catch { /* getAnimations not supported */ }\n }\n\n // =========================================================================\n // Layer 3: JS animation library detection + inline style freeze\n // =========================================================================\n\n function patchGSAP() {\n const g = (window as any).gsap;\n if (g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(0);\n (window as any)._a11yGsapPatched = true;\n } catch { /* ignore */ }\n }\n }\n\n function restoreGSAP() {\n const g = (window as any).gsap;\n if ((window as any)._a11yGsapPatched && g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(1);\n delete (window as any)._a11yGsapPatched;\n } catch { /* ignore */ }\n }\n }\n\n /**\n * Force hidden-by-animation elements visible.\n * Only touches INLINE styles — never sets CSS !important on opacity etc.\n * which would break modals and intentionally hidden elements.\n */\n function forceHiddenElementsVisible() {\n // Only process elements near the viewport to avoid layout chaos on\n // Framer/scroll-animated pages where dozens of off-screen elements\n // are hidden via opacity:0 / translateY as part of scroll reveals.\n const viewH = window.innerHeight;\n const margin = viewH * 1.5; // 1.5x viewport ahead\n\n const all = document.querySelectorAll<HTMLElement>(\n '[style*=\"opacity\"], [style*=\"transform\"], [style*=\"visibility\"], [style*=\"clip-path\"], [data-framer-appear-id]'\n );\n for (const el of all) {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) continue;\n if (el.dataset.a11yOrigStyle) continue; // Already processed\n\n const computed = window.getComputedStyle(el);\n if (computed.display === 'none') continue; // Intentionally hidden\n\n // Skip elements far below the current scroll position —\n // they will be handled when the user scrolls to them (periodic re-scan).\n const rect = el.getBoundingClientRect();\n if (rect.top > viewH + margin) continue; // Too far below viewport\n // Also skip if entirely above viewport (already scrolled past)\n if (rect.bottom < -margin) continue;\n\n const inline = el.style;\n let needsFix = false;\n const originals: Record<string, string> = {};\n\n // Inline opacity 0 or near-0 (computed, not stylesheet)\n const opacityVal = parseFloat(computed.opacity);\n if (opacityVal < 0.1 && inline.opacity !== '') {\n originals.opacity = inline.opacity;\n el.style.opacity = '1';\n needsFix = true;\n } else if (opacityVal < 0.1 && el.hasAttribute('data-framer-appear-id')) {\n // Framer appear elements: opacity set via WAAPI or framework\n originals.opacity = inline.opacity || '';\n el.style.opacity = '1';\n needsFix = true;\n }\n\n // Inline transform with translate that moves element off-screen\n if (inline.transform && /translate[XY]\\([^0]/.test(inline.transform)) {\n originals.transform = inline.transform;\n el.style.transform = 'none';\n needsFix = true;\n }\n\n // Inline visibility hidden\n if (inline.visibility === 'hidden') {\n originals.visibility = inline.visibility;\n el.style.visibility = 'visible';\n needsFix = true;\n }\n\n // Inline clip-path that hides element\n if (inline.clipPath && inline.clipPath !== 'none') {\n originals.clipPath = inline.clipPath;\n el.style.clipPath = 'none';\n needsFix = true;\n }\n\n if (needsFix) {\n el.dataset.a11yOrigStyle = JSON.stringify(originals);\n }\n }\n }\n\n function restoreHiddenElements() {\n document.querySelectorAll<HTMLElement>('[data-a11y-orig-style]').forEach(el => {\n try {\n const orig: Record<string, string> = JSON.parse(el.dataset.a11yOrigStyle || '{}');\n for (const [prop, val] of Object.entries(orig)) {\n if (val === '') {\n el.style.removeProperty(prop);\n } else {\n (el.style as any)[prop] = val;\n }\n }\n } catch { /* malformed JSON */ }\n delete el.dataset.a11yOrigStyle;\n });\n }\n\n /**\n * Freeze inline-animated styles so scroll-handlers can't update them.\n * Takes a snapshot of current inline transforms and enforces them on scroll.\n */\n function freezeScrollAnimations() {\n document.querySelectorAll<HTMLElement>('[style]').forEach(el => {\n if (el.closest('#accessify-root') || el.closest('accessify-widget')) return;\n if (el.dataset.a11yFrozenStyle) return;\n const s = el.style;\n if (s.transform || s.opacity) {\n el.dataset.a11yFrozenStyle = JSON.stringify({\n transform: s.transform || '',\n opacity: s.opacity || '',\n });\n }\n });\n\n if (!scrollHandler) {\n scrollHandler = () => {\n if (!enabled) return;\n document.querySelectorAll<HTMLElement>('[data-a11y-frozen-style]').forEach(el => {\n try {\n const frozen = JSON.parse(el.dataset.a11yFrozenStyle || '{}');\n if (frozen.transform && el.style.transform !== frozen.transform) {\n el.style.transform = frozen.transform;\n }\n if (frozen.opacity && el.style.opacity !== frozen.opacity) {\n el.style.opacity = frozen.opacity;\n }\n } catch { /* ignore */ }\n });\n };\n window.addEventListener('scroll', scrollHandler, { passive: true, capture: true });\n }\n }\n\n function unfreezeScrollAnimations() {\n if (scrollHandler) {\n window.removeEventListener('scroll', scrollHandler, true);\n scrollHandler = null;\n }\n document.querySelectorAll<HTMLElement>('[data-a11y-frozen-style]').forEach(el => {\n delete el.dataset.a11yFrozenStyle;\n });\n }\n\n // =========================================================================\n // Layer 4: Media\n // =========================================================================\n\n function pauseAllVideos() {\n document.querySelectorAll<HTMLVideoElement>('video').forEach(v => {\n if (!v.paused) {\n v.dataset.a11yPaused = 'true';\n v.pause();\n pausedVideos.push(v);\n }\n });\n }\n\n function interceptVideoPlay() {\n if (originalVideoPlay) return;\n originalVideoPlay = HTMLVideoElement.prototype.play;\n HTMLVideoElement.prototype.play = function () {\n if (enabled) return Promise.resolve();\n return originalVideoPlay!.call(this);\n };\n }\n\n function restoreVideoPlay() {\n if (originalVideoPlay) {\n HTMLVideoElement.prototype.play = originalVideoPlay;\n originalVideoPlay = null;\n }\n }\n\n function resumeAllVideos() {\n restoreVideoPlay();\n document.querySelectorAll<HTMLVideoElement>('video[data-a11y-paused]').forEach(v => {\n try { v.play(); } catch { /* gone */ }\n delete v.dataset.a11yPaused;\n });\n pausedVideos = [];\n }\n\n function freezeGif(img: HTMLImageElement) {\n const src = (img.currentSrc || img.src || '').toLowerCase();\n if (!src.match(/\\.gif(\\?|$)/i)) return;\n if (gifOriginals.has(img)) return;\n\n const doFreeze = () => {\n try {\n const w = img.naturalWidth || img.width;\n const h = img.naturalHeight || img.height;\n if (w === 0 || h === 0) return;\n const c = document.createElement('canvas');\n c.width = w; c.height = h;\n const ctx = c.getContext('2d');\n if (!ctx) return;\n ctx.drawImage(img, 0, 0);\n gifOriginals.set(img, img.src);\n img.src = c.toDataURL('image/png');\n } catch { /* CORS */ }\n };\n\n if (img.complete && img.naturalWidth > 0) doFreeze();\n else img.addEventListener('load', doFreeze, { once: true });\n }\n\n function freezeAllGifs() {\n document.querySelectorAll<HTMLImageElement>('img').forEach(freezeGif);\n }\n\n function restoreAllGifs() {\n for (const [img, src] of gifOriginals) {\n try { img.src = src; } catch { /* gone */ }\n }\n gifOriginals.clear();\n }\n\n function pauseSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).pauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function resumeSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).unpauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function stopMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).stop?.(); } catch { /* ignore */ }\n });\n }\n\n function startMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).start?.(); } catch { /* ignore */ }\n });\n }\n\n // =========================================================================\n // MutationObserver — dynamic content\n // =========================================================================\n\n function setupObserver() {\n if (mutationObserver) return;\n mutationObserver = new MutationObserver(mutations => {\n if (!enabled) return;\n let hasNewContent = false;\n for (const m of mutations) {\n if (m.addedNodes.length > 0) { hasNewContent = true; break; }\n }\n if (hasNewContent) {\n // Debounce to avoid layout thrashing on rapid DOM changes\n if (mutationDebounceTimer) clearTimeout(mutationDebounceTimer);\n mutationDebounceTimer = setTimeout(() => {\n mutationDebounceTimer = null;\n if (!enabled) return;\n finishAllAnimations();\n forceHiddenElementsVisible();\n pauseAllVideos();\n freezeAllGifs();\n pauseSVG();\n }, 150);\n }\n });\n mutationObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function teardownObserver() {\n mutationObserver?.disconnect();\n mutationObserver = null;\n if (mutationDebounceTimer) {\n clearTimeout(mutationDebounceTimer);\n mutationDebounceTimer = null;\n }\n }\n\n // =========================================================================\n // Periodic re-scan — frameworks create new animations constantly\n // =========================================================================\n\n function startPeriodicScan() {\n if (scanInterval) return;\n scanInterval = setInterval(() => {\n if (!enabled) return;\n try {\n if (document.getAnimations?.().length === 0) return;\n } catch { /* not supported, scan anyway */ }\n finishAllAnimations();\n }, 2000);\n }\n\n function stopPeriodicScan() {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n }\n\n // =========================================================================\n // Lifecycle\n // =========================================================================\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Layer 0: Intercept Element.animate() — catches ALL new WAAPI animations instantly\n patchAnimate();\n\n // Layer 1: CSS\n injectStyles();\n\n // Layer 2: Kill all currently running WAAPI animations\n finishAllAnimations();\n\n // Layer 3: JS libs + inline style fixes\n patchGSAP();\n forceHiddenElementsVisible();\n freezeScrollAnimations();\n\n // Layer 4: Media\n pauseAllVideos();\n interceptVideoPlay();\n freezeAllGifs();\n pauseSVG();\n stopMarquees();\n\n // Observers\n setupObserver();\n startPeriodicScan();\n\n // Delayed re-scans for async rendering frameworks\n for (const delay of [50, 200, 500, 1000, 2000, 4000]) {\n const id = setTimeout(() => {\n if (!enabled) return;\n finishAllAnimations();\n forceHiddenElementsVisible();\n freezeScrollAnimations();\n pauseAllVideos();\n freezeAllGifs();\n }, delay);\n delayedTimers.push(id);\n }\n\n localStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function deactivate() {\n enabled = false;\n\n // Clear delayed re-scan timers\n for (const id of delayedTimers) clearTimeout(id);\n delayedTimers = [];\n\n stopPeriodicScan();\n teardownObserver();\n restoreAnimate();\n unfreezeScrollAnimations();\n restoreGSAP();\n restoreHiddenElements();\n startMarquees();\n resumeSVG();\n restoreAllGifs();\n resumeAllVideos();\n removeStyles();\n\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'animation-stop',\n name: () => 'Stop Animations',\n description: 'Pause all animations, transitions, and auto-playing videos (WCAG 2.3.1)',\n icon: 'animation-stop',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'animation-stop', enabled }),\n setState: (state: { enabled: boolean }) => {\n if (state.enabled) activate();\n else deactivate();\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-
|
|
6647
|
+
"keyboard-nav": () => import("./keyboard-nav-AFyqDbnd.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
|
-
"animation-stop": () => import("./animation-stop-
|
|
6651
|
+
"animation-stop": () => import("./animation-stop-C4OcBKkR.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-
|
|
6655
|
-
tts: () => import("./tts-
|
|
6656
|
-
"text-simplify": () => import("./text-simplify-
|
|
6657
|
-
"alt-text": () => import("./alt-text-
|
|
6654
|
+
"page-structure": () => import("./page-structure-BpCqEHJ6.js"),
|
|
6655
|
+
tts: () => import("./tts-64TqRR7s.js"),
|
|
6656
|
+
"text-simplify": () => import("./text-simplify-7XhQbbXL.js"),
|
|
6657
|
+
"alt-text": () => import("./alt-text-Dg2ted6-.js")
|
|
6658
6658
|
};
|
|
6659
6659
|
let contrastMode = /* @__PURE__ */ state(proxy(readStoredContrastMode()));
|
|
6660
6660
|
let textSize = /* @__PURE__ */ state(proxy(readStoredTextSize()));
|
|
@@ -8067,7 +8067,11 @@ function createWidgetStyles(config2) {
|
|
|
8067
8067
|
background: var(--surface-dim); color: var(--accent);
|
|
8068
8068
|
}
|
|
8069
8069
|
.accessify-card-icon svg { width: 28px; height: 28px; stroke-width: 2.5; }
|
|
8070
|
-
.accessify-card-label {
|
|
8070
|
+
.accessify-card-label {
|
|
8071
|
+
font-size: 12px; font-weight: 600; line-height: 1.25;
|
|
8072
|
+
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
|
|
8073
|
+
overflow: hidden; word-break: break-word;
|
|
8074
|
+
}
|
|
8071
8075
|
|
|
8072
8076
|
/* Info icon + tooltip */
|
|
8073
8077
|
.accessify-card-info {
|
|
@@ -8135,6 +8139,7 @@ function createWidgetStyles(config2) {
|
|
|
8135
8139
|
.accessify-stepper-btn { width: 44px; min-height: 44px; }
|
|
8136
8140
|
.accessify-stepper { height: 44px; }
|
|
8137
8141
|
.accessify-footer-close { min-height: 44px; padding: 8px 16px; }
|
|
8142
|
+
.accessify-drag-handle { display: none; }
|
|
8138
8143
|
}
|
|
8139
8144
|
`;
|
|
8140
8145
|
}
|
|
@@ -8332,7 +8337,7 @@ async function init(userConfig = {}) {
|
|
|
8332
8337
|
window.removeEventListener("message", handleMessage);
|
|
8333
8338
|
};
|
|
8334
8339
|
document.body.appendChild(containerEl);
|
|
8335
|
-
import("./alt-text-
|
|
8340
|
+
import("./alt-text-Dg2ted6-.js").then((m) => m.autoApplyCachedAltTexts(config)).catch(() => {
|
|
8336
8341
|
});
|
|
8337
8342
|
config.onReady?.();
|
|
8338
8343
|
}
|
|
@@ -8377,4 +8382,4 @@ export {
|
|
|
8377
8382
|
init as i,
|
|
8378
8383
|
t
|
|
8379
8384
|
};
|
|
8380
|
-
//# sourceMappingURL=index-
|
|
8385
|
+
//# sourceMappingURL=index-Bdke9nRb.js.map
|