accessify-widget 0.3.71 → 0.3.74

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.
@@ -4749,7 +4749,7 @@ const deJson = {
4749
4749
  "profile.cognitive": "Kognitive Unterstützung",
4750
4750
  "profile.cognitive.desc": "Lesehilfen, Abstände und einfachere Schrift",
4751
4751
  "profile.seizureSafe": "Anfallssicher",
4752
- "profile.seizureSafe.desc": "Animationen stoppen und Reize reduzieren",
4752
+ "profile.seizureSafe.desc": "Animationen pausieren und Reize reduzieren",
4753
4753
  "profile.adhdFriendly": "ADHS-freundlich",
4754
4754
  "profile.adhdFriendly.desc": "Ablenkungen reduzieren und Fokus verbessern",
4755
4755
  "feature.contrast": "Kontrast",
@@ -4764,7 +4764,7 @@ const deJson = {
4764
4764
  "feature.readingGuide.desc": "Horizontales Lineal zum zeilenweisen Lesen",
4765
4765
  "feature.focusHighlight": "Fokus-Hervorhebung",
4766
4766
  "feature.focusHighlight.desc": "Sichtbare Umrandung fokussierter Elemente",
4767
- "feature.animationStop": "Animationen stoppen",
4767
+ "feature.animationStop": "Animationen pausieren",
4768
4768
  "feature.animationStop.desc": "Alle Animationen und Videos pausieren",
4769
4769
  "feature.bigCursor": "Großer Mauszeiger",
4770
4770
  "feature.bigCursor.desc": "Vergrößerter Mauszeiger für bessere Sichtbarkeit",
@@ -4840,7 +4840,7 @@ const enJson = {
4840
4840
  "profile.cognitive": "Cognitive Support",
4841
4841
  "profile.cognitive.desc": "Reading aids, spacing, and simpler fonts",
4842
4842
  "profile.seizureSafe": "Seizure Safe",
4843
- "profile.seizureSafe.desc": "Stop animations and reduce stimuli",
4843
+ "profile.seizureSafe.desc": "Pause animations and reduce stimuli",
4844
4844
  "profile.adhdFriendly": "ADHD Friendly",
4845
4845
  "profile.adhdFriendly.desc": "Reduce distractions and improve focus",
4846
4846
  "feature.contrast": "Contrast",
@@ -4855,7 +4855,7 @@ const enJson = {
4855
4855
  "feature.readingGuide.desc": "Horizontal ruler for line-by-line reading",
4856
4856
  "feature.focusHighlight": "Focus Highlight",
4857
4857
  "feature.focusHighlight.desc": "Visible outline on focused elements",
4858
- "feature.animationStop": "Stop Animations",
4858
+ "feature.animationStop": "Pause Animations",
4859
4859
  "feature.animationStop.desc": "Pause all animations and videos",
4860
4860
  "feature.bigCursor": "Big Cursor",
4861
4861
  "feature.bigCursor.desc": "Enlarged cursor for better visibility",
@@ -6642,17 +6642,17 @@ function FeatureGrid($$anchor, $$props) {
6642
6642
  const FEATURE_LOADERS = {
6643
6643
  contrast: () => import("./contrast-CqsOs6Uo.js"),
6644
6644
  "text-size": () => import("./text-size-m_mHNPWo.js"),
6645
- "keyboard-nav": () => import("./keyboard-nav-C9qVZ3e8.js"),
6645
+ "keyboard-nav": () => import("./keyboard-nav-BMIfQKyz.js"),
6646
6646
  "link-highlight": () => import("./link-highlight-D9gxFmiG.js"),
6647
6647
  "reading-guide": () => import("./reading-guide-C_jxzorm.js"),
6648
6648
  "reading-mask": () => import("./reading-mask-B_NxbhTN.js"),
6649
6649
  "animation-stop": () => import("./animation-stop-DrDe9Q9n.js"),
6650
6650
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6651
6651
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6652
- "page-structure": () => import("./page-structure-DL3Xdzlm.js"),
6653
- tts: () => import("./tts-CjszLRnb.js"),
6652
+ "page-structure": () => import("./page-structure-BimA9vQz.js"),
6653
+ tts: () => import("./tts-zrXtEd07.js"),
6654
6654
  "text-simplify": () => import("./text-simplify-BIFpqadq.js"),
6655
- "alt-text": () => Promise.resolve().then(() => altText)
6655
+ "alt-text": () => import("./alt-text-CoS2ISqs.js")
6656
6656
  };
6657
6657
  let contrastMode = /* @__PURE__ */ state(proxy(readStoredContrastMode()));
6658
6658
  let textSize = /* @__PURE__ */ state(proxy(readStoredTextSize()));
@@ -8136,739 +8136,6 @@ function createWidgetStyles(config2) {
8136
8136
  }
8137
8137
  `;
8138
8138
  }
8139
- const IDB_NAME = "accessify-alt-text-cache";
8140
- const IDB_STORE = "alt-texts";
8141
- const IDB_VERSION = 2;
8142
- function hashSrc(src) {
8143
- let hash = 5381;
8144
- const n = src.toLowerCase().trim();
8145
- for (let i = 0; i < n.length; i++) {
8146
- hash = (hash << 5) + hash + n.charCodeAt(i);
8147
- hash |= 0;
8148
- }
8149
- return Math.abs(hash).toString(36);
8150
- }
8151
- function normalizeImageUrl(url) {
8152
- try {
8153
- const u = new URL(url);
8154
- u.searchParams.delete("width");
8155
- u.searchParams.delete("height");
8156
- u.searchParams.delete("scale-down-to");
8157
- return u.href;
8158
- } catch {
8159
- return url;
8160
- }
8161
- }
8162
- function getImageSrc(img) {
8163
- return img.currentSrc || img.src;
8164
- }
8165
- function openCache() {
8166
- return new Promise((resolve) => {
8167
- try {
8168
- const req = indexedDB.open(IDB_NAME, IDB_VERSION);
8169
- req.onupgradeneeded = () => {
8170
- const db = req.result;
8171
- if (!db.objectStoreNames.contains(IDB_STORE)) db.createObjectStore(IDB_STORE, { keyPath: "key" });
8172
- if (!db.objectStoreNames.contains("alt-text-reports")) db.createObjectStore("alt-text-reports", { keyPath: "key" });
8173
- };
8174
- req.onsuccess = () => resolve(req.result);
8175
- req.onerror = () => resolve(null);
8176
- } catch {
8177
- resolve(null);
8178
- }
8179
- });
8180
- }
8181
- async function getAllCachedAltTexts() {
8182
- const db = await openCache();
8183
- const map = /* @__PURE__ */ new Map();
8184
- if (!db) return map;
8185
- return new Promise((resolve) => {
8186
- try {
8187
- const tx = db.transaction(IDB_STORE, "readonly");
8188
- const req = tx.objectStore(IDB_STORE).getAll();
8189
- req.onsuccess = () => {
8190
- for (const r of req.result) {
8191
- map.set(r.src, r.altText);
8192
- }
8193
- resolve(map);
8194
- };
8195
- req.onerror = () => resolve(map);
8196
- } catch {
8197
- resolve(map);
8198
- }
8199
- });
8200
- }
8201
- async function getCachedAltText(src) {
8202
- const db = await openCache();
8203
- if (!db) return null;
8204
- return new Promise((resolve) => {
8205
- try {
8206
- const tx = db.transaction(IDB_STORE, "readonly");
8207
- const store = tx.objectStore(IDB_STORE);
8208
- const req1 = store.get(hashSrc(src));
8209
- req1.onsuccess = () => {
8210
- if (req1.result?.altText) {
8211
- resolve(req1.result.altText);
8212
- return;
8213
- }
8214
- const norm = normalizeImageUrl(src);
8215
- if (norm !== src) {
8216
- const req2 = store.get(hashSrc(norm));
8217
- req2.onsuccess = () => resolve(req2.result?.altText || null);
8218
- req2.onerror = () => resolve(null);
8219
- } else {
8220
- resolve(null);
8221
- }
8222
- };
8223
- req1.onerror = () => resolve(null);
8224
- } catch {
8225
- resolve(null);
8226
- }
8227
- });
8228
- }
8229
- async function setCachedAltText(src, altText2, langCode) {
8230
- const db = await openCache();
8231
- if (!db) return;
8232
- return new Promise((resolve) => {
8233
- try {
8234
- const tx = db.transaction(IDB_STORE, "readwrite");
8235
- tx.objectStore(IDB_STORE).put({ key: hashSrc(src), src, altText: altText2, lang: langCode, createdAt: Date.now() });
8236
- tx.oncomplete = () => resolve();
8237
- tx.onerror = () => resolve();
8238
- } catch {
8239
- resolve();
8240
- }
8241
- });
8242
- }
8243
- const DEFAULT_API_BASE = "https://accessify-api.accessify.workers.dev";
8244
- let currentAltSiteMode = "manual";
8245
- async function fetchServerAltTexts(siteKey, proxyUrl, lang) {
8246
- const map = /* @__PURE__ */ new Map();
8247
- try {
8248
- const base = proxyUrl || DEFAULT_API_BASE;
8249
- const pageUrl = window.location.origin + window.location.pathname;
8250
- const res = await fetch(`${base}/v1/manifest?siteKey=${encodeURIComponent(siteKey)}&url=${encodeURIComponent(pageUrl)}&feature=alt_text&variant=${encodeURIComponent(lang)}`, {
8251
- headers: { "Accept": "application/json" },
8252
- cache: "no-cache"
8253
- });
8254
- if (!res.ok) return map;
8255
- const data = await res.json();
8256
- currentAltSiteMode = data.siteMode === "auto" ? "auto" : "manual";
8257
- if (data.blocks) {
8258
- for (const block2 of data.blocks) {
8259
- if (block2.selector && block2.result) map.set(block2.selector, block2.result);
8260
- }
8261
- }
8262
- } catch {
8263
- }
8264
- return map;
8265
- }
8266
- function persistAltTextToServer(siteKey, proxyUrl, imageUrl, altText2, lang) {
8267
- try {
8268
- const base = proxyUrl || DEFAULT_API_BASE;
8269
- const pageUrl = window.location.origin + window.location.pathname;
8270
- fetch(`${base}/v1/cache/persist-alt-text`, {
8271
- method: "POST",
8272
- headers: { "Content-Type": "application/json" },
8273
- body: JSON.stringify({ siteKey, pageUrl, imageUrl, altText: altText2, lang })
8274
- }).catch(() => {
8275
- });
8276
- } catch {
8277
- }
8278
- }
8279
- let autoApplied = false;
8280
- async function autoApplyCachedAltTexts(widgetConfig) {
8281
- if (autoApplied) return 0;
8282
- autoApplied = true;
8283
- const cache = /* @__PURE__ */ new Map();
8284
- const siteKey = widgetConfig?.siteKey;
8285
- const proxyUrl = widgetConfig?.proxyUrl || "";
8286
- const pageLang = widgetConfig?.lang?.split("-")[0] || document.documentElement.lang?.split("-")[0] || "en";
8287
- if (siteKey) {
8288
- const serverCache = await fetchServerAltTexts(siteKey, proxyUrl, pageLang);
8289
- for (const [url, alt] of serverCache) {
8290
- cache.set(url, alt);
8291
- const norm = normalizeImageUrl(url);
8292
- if (norm !== url) cache.set(norm, alt);
8293
- setCachedAltText(url, alt, pageLang).catch(() => {
8294
- });
8295
- }
8296
- }
8297
- const localCache = await getAllCachedAltTexts();
8298
- for (const [url, alt] of localCache) {
8299
- if (!cache.has(url)) cache.set(url, alt);
8300
- }
8301
- if (cache.size === 0) return 0;
8302
- function applyToImg(img) {
8303
- if (img.closest("#accessify-root") || img.closest("accessify-widget")) return false;
8304
- const src = getImageSrc(img);
8305
- const norm = normalizeImageUrl(src);
8306
- const imgSrcNorm = normalizeImageUrl(img.src);
8307
- const cached = cache.get(src) || cache.get(norm) || cache.get(img.src) || cache.get(imgSrcNorm);
8308
- if (!cached) return false;
8309
- const alt = img.getAttribute("alt");
8310
- if (alt === null || alt.trim() === "") {
8311
- img.setAttribute("alt", cached);
8312
- img.setAttribute("data-accessify-alt", "auto");
8313
- }
8314
- img.setAttribute("title", cached);
8315
- return true;
8316
- }
8317
- let applied = 0;
8318
- document.querySelectorAll("img").forEach((img) => {
8319
- if (applyToImg(img)) applied++;
8320
- });
8321
- const observer2 = new MutationObserver((mutations) => {
8322
- for (const m of mutations) {
8323
- for (const node of m.addedNodes) {
8324
- const imgs = node instanceof HTMLImageElement ? [node] : node instanceof HTMLElement ? Array.from(node.querySelectorAll("img")) : [];
8325
- for (const img of imgs) applyToImg(img);
8326
- }
8327
- }
8328
- });
8329
- observer2.observe(document.body, { childList: true, subtree: true });
8330
- setTimeout(() => observer2.disconnect(), 3e4);
8331
- return applied;
8332
- }
8333
- function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8334
- const siteKey = serverConfig?.siteKey || "";
8335
- const proxyUrl = serverConfig?.proxyUrl || "";
8336
- let enabled = false;
8337
- let domObserver = null;
8338
- let autoGenerating = false;
8339
- let missingAltImages = [];
8340
- const processedImages = /* @__PURE__ */ new Map();
8341
- function lang() {
8342
- return getCurrentWidgetLang() || initialLang;
8343
- }
8344
- function isDE() {
8345
- return lang().startsWith("de");
8346
- }
8347
- function isGenericAlt(alt) {
8348
- if (!alt.trim()) return true;
8349
- if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;
8350
- if (/^IMG_\d+/i.test(alt)) return true;
8351
- if (/\.(jpg|jpeg|png|gif|webp|svg|avif)$/i.test(alt)) return true;
8352
- return false;
8353
- }
8354
- function isDecorativeImage(img) {
8355
- const role = img.getAttribute("role");
8356
- if (role === "presentation" || role === "none") return true;
8357
- if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return true;
8358
- return false;
8359
- }
8360
- function isValidImage(img) {
8361
- if (img.closest("#accessify-root") || img.closest("accessify-widget")) return false;
8362
- if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return false;
8363
- const rect = img.getBoundingClientRect();
8364
- if (rect.width < 40 || rect.height < 40) return false;
8365
- const style = getComputedStyle(img);
8366
- if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
8367
- if (img.getAttribute("role") === "presentation" || img.getAttribute("aria-hidden") === "true") return false;
8368
- return true;
8369
- }
8370
- function needsAltText(img) {
8371
- if (!isValidImage(img)) return false;
8372
- const alt = img.getAttribute("alt");
8373
- if (alt === null) return true;
8374
- if (isGenericAlt(alt)) return true;
8375
- if (alt === "" && !isDecorativeImage(img)) return true;
8376
- return false;
8377
- }
8378
- function scanForMissingAlt() {
8379
- const missing = [];
8380
- document.querySelectorAll("img").forEach((img) => {
8381
- if (needsAltText(img)) missing.push(img);
8382
- });
8383
- document.querySelectorAll("picture").forEach((picture) => {
8384
- if (picture.closest("#accessify-root") || picture.closest("accessify-widget")) return;
8385
- const img = picture.querySelector("img");
8386
- if (img && !missing.includes(img) && needsAltText(img)) {
8387
- missing.push(img);
8388
- }
8389
- });
8390
- return missing;
8391
- }
8392
- function gatherImageContext(img) {
8393
- const parts = [];
8394
- try {
8395
- const url = new URL(getImageSrc(img), window.location.href);
8396
- const filename = url.pathname.split("/").pop();
8397
- if (filename) parts.push(`Filename: ${filename}`);
8398
- } catch {
8399
- }
8400
- const figure = img.closest("figure");
8401
- if (figure) {
8402
- const caption = figure.querySelector("figcaption");
8403
- if (caption?.textContent?.trim()) parts.push(`Caption: ${caption.textContent.trim()}`);
8404
- }
8405
- const container = img.parentElement?.parentElement || img.parentElement;
8406
- if (container) {
8407
- const heading = container.querySelector("h1, h2, h3, h4, h5, h6");
8408
- if (heading?.textContent?.trim()) parts.push(`Nearby heading: ${heading.textContent.trim()}`);
8409
- }
8410
- return parts.join(". ");
8411
- }
8412
- function applyAltText(img, altText2) {
8413
- img.setAttribute("alt", altText2);
8414
- img.setAttribute("title", altText2);
8415
- processedImages.set(img, { generatedAlt: altText2 });
8416
- if (enabled) addInfoBadge(img, altText2);
8417
- }
8418
- function applyTitlesToAllImages() {
8419
- document.querySelectorAll("img").forEach((img) => {
8420
- if (!isValidImage(img)) return;
8421
- if (img.getAttribute("title")) return;
8422
- const alt = img.getAttribute("alt");
8423
- if (alt && alt.trim()) {
8424
- img.setAttribute("title", alt);
8425
- img.setAttribute("data-accessify-title", "auto");
8426
- }
8427
- });
8428
- }
8429
- const BADGE_ATTR = "data-accessify-badge";
8430
- const WRAPPER_ATTR = "data-accessify-badge-wrap";
8431
- const OVERLAY_ID = "accessify-badge-overlay";
8432
- const BADGE_STYLE_ID = "accessify-badge-styles";
8433
- let badgePositionRAF = null;
8434
- let trackedBadges = [];
8435
- let outsideClickHandler = null;
8436
- function getOrCreateOverlay() {
8437
- let overlay = document.getElementById(OVERLAY_ID);
8438
- if (!overlay) {
8439
- overlay = document.createElement("div");
8440
- overlay.id = OVERLAY_ID;
8441
- Object.assign(overlay.style, {
8442
- position: "absolute",
8443
- top: "0",
8444
- left: "0",
8445
- width: "0",
8446
- height: "0",
8447
- overflow: "visible",
8448
- pointerEvents: "none",
8449
- zIndex: "10000"
8450
- });
8451
- document.body.appendChild(overlay);
8452
- }
8453
- if (!document.getElementById(BADGE_STYLE_ID)) {
8454
- const style = document.createElement("style");
8455
- style.id = BADGE_STYLE_ID;
8456
- style.textContent = `
8457
- [${BADGE_ATTR}="badge"]:hover + [${BADGE_ATTR}="tooltip"] { display: block !important; }
8458
- [${BADGE_ATTR}="badge"]:hover { background: rgba(0,0,0,0.85) !important; }
8459
- @media (pointer: coarse) {
8460
- [${BADGE_ATTR}="badge"] { width: 36px !important; height: 36px !important; line-height: 36px !important; font-size: 16px !important; }
8461
- }
8462
- `;
8463
- document.head.appendChild(style);
8464
- }
8465
- return overlay;
8466
- }
8467
- function positionBadge(target, badge, tooltip) {
8468
- const rect = target.getBoundingClientRect();
8469
- if (rect.width < 40 || rect.height < 40 || rect.bottom < 0 || rect.top > window.innerHeight + 200 || rect.right < 0 || rect.left > window.innerWidth + 200) {
8470
- badge.style.display = "none";
8471
- tooltip.style.display = "none";
8472
- return;
8473
- }
8474
- const scrollX = window.scrollX;
8475
- const scrollY = window.scrollY;
8476
- const top = rect.top + scrollY + 6;
8477
- const left = rect.left + scrollX + 6;
8478
- badge.style.display = "";
8479
- badge.style.top = `${top}px`;
8480
- badge.style.left = `${left}px`;
8481
- tooltip.style.top = `${top + 26}px`;
8482
- tooltip.style.left = `${left}px`;
8483
- }
8484
- function updateAllBadgePositions() {
8485
- for (const { target, badge, tooltip } of trackedBadges) {
8486
- if (!document.body.contains(target)) continue;
8487
- positionBadge(target, badge, tooltip);
8488
- }
8489
- }
8490
- function startBadgeTracking() {
8491
- if (badgePositionRAF !== null) return;
8492
- const tick = () => {
8493
- updateAllBadgePositions();
8494
- badgePositionRAF = requestAnimationFrame(tick);
8495
- };
8496
- badgePositionRAF = requestAnimationFrame(tick);
8497
- if (!outsideClickHandler) {
8498
- outsideClickHandler = (e) => {
8499
- const target = e.target;
8500
- if (target.getAttribute(BADGE_ATTR) === "badge") return;
8501
- for (const entry of trackedBadges) {
8502
- entry.tooltip.style.display = "none";
8503
- entry.badge.style.background = "rgba(0,0,0,0.6)";
8504
- }
8505
- };
8506
- document.addEventListener("click", outsideClickHandler, { passive: true });
8507
- }
8508
- }
8509
- function stopBadgeTracking() {
8510
- if (badgePositionRAF !== null) {
8511
- cancelAnimationFrame(badgePositionRAF);
8512
- badgePositionRAF = null;
8513
- }
8514
- if (outsideClickHandler) {
8515
- document.removeEventListener("click", outsideClickHandler);
8516
- outsideClickHandler = null;
8517
- }
8518
- }
8519
- function addInfoBadge(target, altText2) {
8520
- if (target.getAttribute(BADGE_ATTR)) return;
8521
- target.setAttribute(BADGE_ATTR, "1");
8522
- const overlay = getOrCreateOverlay();
8523
- const badge = document.createElement("span");
8524
- Object.assign(badge.style, {
8525
- position: "absolute",
8526
- width: "22px",
8527
- height: "22px",
8528
- borderRadius: "50%",
8529
- background: "rgba(0,0,0,0.6)",
8530
- color: "#fff",
8531
- fontFamily: "sans-serif",
8532
- fontWeight: "bold",
8533
- fontSize: "13px",
8534
- lineHeight: "22px",
8535
- textAlign: "center",
8536
- cursor: "default",
8537
- pointerEvents: "auto",
8538
- boxShadow: "0 1px 4px rgba(0,0,0,0.4)",
8539
- transition: "background 0.15s"
8540
- });
8541
- badge.textContent = "i";
8542
- badge.setAttribute("aria-hidden", "true");
8543
- badge.setAttribute("translate", "no");
8544
- badge.classList.add("notranslate");
8545
- badge.setAttribute(BADGE_ATTR, "badge");
8546
- const tooltip = document.createElement("span");
8547
- Object.assign(tooltip.style, {
8548
- display: "none",
8549
- position: "absolute",
8550
- minWidth: "150px",
8551
- maxWidth: "280px",
8552
- padding: "6px 10px",
8553
- background: "rgba(0,0,0,0.88)",
8554
- color: "#fff",
8555
- fontFamily: "sans-serif",
8556
- fontSize: "12px",
8557
- lineHeight: "1.4",
8558
- borderRadius: "6px",
8559
- pointerEvents: "none",
8560
- wordWrap: "break-word",
8561
- boxShadow: "0 2px 8px rgba(0,0,0,0.3)",
8562
- zIndex: "1"
8563
- });
8564
- tooltip.textContent = altText2;
8565
- tooltip.setAttribute("translate", "no");
8566
- tooltip.classList.add("notranslate");
8567
- tooltip.setAttribute(BADGE_ATTR, "tooltip");
8568
- badge.addEventListener("click", () => {
8569
- const isOpen = tooltip.style.display === "block";
8570
- for (const entry of trackedBadges) {
8571
- entry.tooltip.style.display = "none";
8572
- entry.badge.style.background = "rgba(0,0,0,0.6)";
8573
- }
8574
- if (!isOpen) {
8575
- badge.style.background = "rgba(0,0,0,0.85)";
8576
- tooltip.style.display = "block";
8577
- }
8578
- });
8579
- overlay.appendChild(badge);
8580
- overlay.appendChild(tooltip);
8581
- positionBadge(target, badge, tooltip);
8582
- trackedBadges.push({ target, badge, tooltip });
8583
- }
8584
- function removeAllBadges() {
8585
- stopBadgeTracking();
8586
- trackedBadges = [];
8587
- document.getElementById(OVERLAY_ID)?.remove();
8588
- document.getElementById(BADGE_STYLE_ID)?.remove();
8589
- document.querySelectorAll(`[${BADGE_ATTR}]`).forEach((el) => el.removeAttribute(BADGE_ATTR));
8590
- document.querySelectorAll(`[${WRAPPER_ATTR}]`).forEach((wrapper) => {
8591
- const img = wrapper.querySelector("img");
8592
- if (img && wrapper.parentElement) {
8593
- wrapper.parentElement.insertBefore(img, wrapper);
8594
- wrapper.remove();
8595
- }
8596
- });
8597
- }
8598
- function addBadgesToAllImages() {
8599
- document.querySelectorAll("img").forEach((img) => {
8600
- if (!isValidImage(img)) return;
8601
- const alt = img.getAttribute("alt") || img.getAttribute("title");
8602
- if (alt && alt.trim()) {
8603
- addInfoBadge(img, alt.trim());
8604
- }
8605
- });
8606
- document.querySelectorAll("[data-accessify-bg-alt]").forEach((el) => {
8607
- const alt = el.getAttribute("aria-label");
8608
- if (alt && alt.trim()) {
8609
- addInfoBadge(el, alt.trim());
8610
- }
8611
- });
8612
- if (trackedBadges.length > 0) startBadgeTracking();
8613
- }
8614
- function removeTitles() {
8615
- document.querySelectorAll('img[data-accessify-title="auto"]').forEach((img) => {
8616
- img.removeAttribute("title");
8617
- img.removeAttribute("data-accessify-title");
8618
- });
8619
- document.querySelectorAll("[data-accessify-bg-alt]").forEach((el) => {
8620
- el.removeAttribute("role");
8621
- el.removeAttribute("aria-label");
8622
- el.removeAttribute("title");
8623
- el.removeAttribute("data-accessify-bg-alt");
8624
- });
8625
- removeAllBadges();
8626
- }
8627
- function scanForBackgroundImages() {
8628
- const found = [];
8629
- const allElements = document.querySelectorAll("*");
8630
- for (const el of allElements) {
8631
- if (el.closest("#accessify-root") || el.closest("accessify-widget")) continue;
8632
- if (el.getAttribute("data-accessify-bg-alt")) continue;
8633
- if (el.offsetWidth < 200 || el.offsetHeight < 150) continue;
8634
- const style = getComputedStyle(el);
8635
- const bg = style.backgroundImage;
8636
- if (!bg || bg === "none") continue;
8637
- const urlMatch = bg.match(/url\(["']?([^"')]+)["']?\)/);
8638
- if (!urlMatch) continue;
8639
- if (urlMatch[1].startsWith("data:image/svg")) continue;
8640
- if (el.getAttribute("role") === "img" && el.getAttribute("aria-label")) continue;
8641
- found.push(el);
8642
- }
8643
- return found;
8644
- }
8645
- function getBackgroundImageUrl(el) {
8646
- const bg = getComputedStyle(el).backgroundImage;
8647
- const match = bg?.match(/url\(["']?([^"')]+)["']?\)/);
8648
- return match ? match[1] : null;
8649
- }
8650
- function applyBgAlt(el, altText2) {
8651
- el.setAttribute("role", "img");
8652
- el.setAttribute("aria-label", altText2);
8653
- el.setAttribute("title", altText2);
8654
- el.setAttribute("data-accessify-bg-alt", "auto");
8655
- if (enabled) addInfoBadge(el, altText2);
8656
- }
8657
- async function generateBgAlts() {
8658
- if (!aiService || !enabled) return;
8659
- if (currentAltSiteMode !== "auto") {
8660
- if (window.__ACCESSIFY_DEBUG) {
8661
- console.info("[Accessify] alt-text: siteMode=manual — skipping live generation for background images");
8662
- }
8663
- return;
8664
- }
8665
- const bgElements = scanForBackgroundImages();
8666
- for (const el of bgElements) {
8667
- if (!enabled) break;
8668
- const src = getBackgroundImageUrl(el);
8669
- if (!src) continue;
8670
- const cached = await getCachedAltText(src);
8671
- if (cached) {
8672
- applyBgAlt(el, cached);
8673
- continue;
8674
- }
8675
- try {
8676
- const ctx = gatherBgContext(el);
8677
- const alt = await aiService.generateAltText(src, ctx, lang());
8678
- if (alt && enabled) {
8679
- applyBgAlt(el, alt);
8680
- setCachedAltText(src, alt, lang()).catch(() => {
8681
- });
8682
- if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());
8683
- }
8684
- } catch (err) {
8685
- console.warn("[Accessify] Bg alt-text generation failed:", src, err);
8686
- }
8687
- }
8688
- }
8689
- function gatherBgContext(el) {
8690
- const parts = [];
8691
- parts.push(`Element: <${el.tagName.toLowerCase()}>`);
8692
- if (el.className) parts.push(`Class: ${el.className}`);
8693
- const text = el.textContent?.trim().slice(0, 100);
8694
- if (text) parts.push(`Overlay text: ${text}`);
8695
- const heading = el.querySelector("h1, h2, h3");
8696
- if (heading?.textContent?.trim()) parts.push(`Heading: ${heading.textContent.trim()}`);
8697
- return parts.join(". ");
8698
- }
8699
- async function generateAll() {
8700
- if (autoGenerating || !enabled || !aiService) return;
8701
- autoGenerating = true;
8702
- const CONCURRENCY = 3;
8703
- const uncached = [];
8704
- for (const img of missingAltImages) {
8705
- if (processedImages.has(img)) continue;
8706
- const src = getImageSrc(img);
8707
- const cached = await getCachedAltText(src);
8708
- if (cached) {
8709
- applyAltText(img, cached);
8710
- } else {
8711
- uncached.push(img);
8712
- }
8713
- }
8714
- if (!uncached.length) {
8715
- autoGenerating = false;
8716
- return;
8717
- }
8718
- if (currentAltSiteMode !== "auto") {
8719
- if (window.__ACCESSIFY_DEBUG) {
8720
- console.info(
8721
- `[Accessify] alt-text: siteMode=manual — ${uncached.length} image(s) left untouched. Trigger a crawl from the dashboard or enable auto mode.`
8722
- );
8723
- }
8724
- autoGenerating = false;
8725
- return;
8726
- }
8727
- for (let i = 0; i < uncached.length; i += CONCURRENCY) {
8728
- if (!enabled) break;
8729
- const batch = uncached.slice(i, i + CONCURRENCY);
8730
- await Promise.all(batch.map(async (img) => {
8731
- if (!enabled) return;
8732
- try {
8733
- const src = getImageSrc(img);
8734
- const ctx = gatherImageContext(img);
8735
- const alt = await aiService.generateAltText(src, ctx, lang());
8736
- if (alt && enabled) {
8737
- applyAltText(img, alt);
8738
- setCachedAltText(src, alt, lang()).catch(() => {
8739
- });
8740
- if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());
8741
- }
8742
- } catch (err) {
8743
- console.warn("[Accessify] Alt-text generation failed:", getImageSrc(img), err);
8744
- }
8745
- }));
8746
- }
8747
- autoGenerating = false;
8748
- }
8749
- async function generateSingle(img) {
8750
- if (!aiService || !enabled) return;
8751
- const src = getImageSrc(img);
8752
- const cached = await getCachedAltText(src);
8753
- if (cached) {
8754
- applyAltText(img, cached);
8755
- return;
8756
- }
8757
- if (currentAltSiteMode !== "auto") return;
8758
- try {
8759
- const ctx = gatherImageContext(img);
8760
- const alt = await aiService.generateAltText(src, ctx, lang());
8761
- if (alt && enabled) {
8762
- applyAltText(img, alt);
8763
- setCachedAltText(src, alt, lang()).catch(() => {
8764
- });
8765
- if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, alt, lang());
8766
- }
8767
- } catch (err) {
8768
- console.warn("[Accessify] Alt-text generation failed:", src, err);
8769
- }
8770
- }
8771
- function tryRegisterImage(img) {
8772
- if (!enabled) return;
8773
- if (!isValidImage(img)) return;
8774
- if (missingAltImages.includes(img)) return;
8775
- function addIfValid() {
8776
- if (!enabled || missingAltImages.includes(img)) return;
8777
- if (img.naturalWidth < 20 || img.naturalHeight < 20) return;
8778
- if (needsAltText(img)) {
8779
- missingAltImages.push(img);
8780
- generateSingle(img);
8781
- } else {
8782
- const alt = img.getAttribute("alt");
8783
- if (alt && alt.trim()) {
8784
- if (!img.getAttribute("title")) {
8785
- img.setAttribute("title", alt);
8786
- img.setAttribute("data-accessify-title", "auto");
8787
- }
8788
- addInfoBadge(img, alt.trim());
8789
- }
8790
- }
8791
- }
8792
- if (img.complete && img.naturalWidth > 0) addIfValid();
8793
- else img.addEventListener("load", addIfValid, { once: true });
8794
- }
8795
- function activate() {
8796
- if (enabled) return;
8797
- enabled = true;
8798
- document.querySelectorAll('img[data-accessify-alt="auto"]').forEach((img) => {
8799
- if (img.closest("#accessify-root")) return;
8800
- if (!processedImages.has(img)) {
8801
- processedImages.set(img, { generatedAlt: img.getAttribute("alt") || "" });
8802
- missingAltImages.push(img);
8803
- }
8804
- });
8805
- const missing = scanForMissingAlt();
8806
- for (const img of missing) {
8807
- if (!missingAltImages.includes(img)) {
8808
- missingAltImages.push(img);
8809
- }
8810
- }
8811
- generateAll();
8812
- generateBgAlts();
8813
- applyTitlesToAllImages();
8814
- addBadgesToAllImages();
8815
- document.querySelectorAll("img").forEach((img) => {
8816
- if (!img.complete) tryRegisterImage(img);
8817
- });
8818
- for (const delay of [2e3, 5e3, 1e4]) {
8819
- setTimeout(() => {
8820
- if (enabled) {
8821
- document.querySelectorAll("img").forEach(tryRegisterImage);
8822
- applyTitlesToAllImages();
8823
- addBadgesToAllImages();
8824
- }
8825
- }, delay);
8826
- }
8827
- domObserver = new MutationObserver((mutations) => {
8828
- for (const m of mutations) {
8829
- for (const node of m.addedNodes) {
8830
- if (node instanceof HTMLImageElement) tryRegisterImage(node);
8831
- else if (node instanceof HTMLElement) {
8832
- node.querySelectorAll("img").forEach(tryRegisterImage);
8833
- }
8834
- }
8835
- }
8836
- });
8837
- domObserver.observe(document.body, { childList: true, subtree: true });
8838
- }
8839
- function deactivate() {
8840
- enabled = false;
8841
- autoGenerating = false;
8842
- domObserver?.disconnect();
8843
- domObserver = null;
8844
- removeTitles();
8845
- missingAltImages = [];
8846
- }
8847
- autoApplyCachedAltTexts({ siteKey, proxyUrl, lang: initialLang }).catch(() => {
8848
- });
8849
- return {
8850
- id: "alt-text",
8851
- name: () => isDE() ? "Bildbeschreibung" : "Image Description",
8852
- description: isDE() ? "Bildbeschreibungen per Hover anzeigen und fehlende automatisch erzeugen" : "Show image descriptions on hover and auto-generate missing ones",
8853
- icon: "alt-text",
8854
- category: "ai",
8855
- activate,
8856
- deactivate,
8857
- getState: () => ({
8858
- id: "alt-text",
8859
- enabled,
8860
- value: {
8861
- missingCount: missingAltImages.filter((img) => !processedImages.has(img)).length,
8862
- processedCount: processedImages.size
8863
- }
8864
- })
8865
- };
8866
- }
8867
- const altText = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
8868
- __proto__: null,
8869
- autoApplyCachedAltTexts,
8870
- default: createAltTextModule
8871
- }, Symbol.toStringTag, { value: "Module" }));
8872
8139
  const REMOVED_FEATURES = /* @__PURE__ */ new Set([
8873
8140
  "spacing",
8874
8141
  "dyslexia-font",
@@ -9056,7 +8323,7 @@ async function init(userConfig = {}) {
9056
8323
  }
9057
8324
  });
9058
8325
  document.body.appendChild(containerEl);
9059
- autoApplyCachedAltTexts(config).catch(() => {
8326
+ import("./alt-text-CoS2ISqs.js").then((m) => m.autoApplyCachedAltTexts(config)).catch(() => {
9060
8327
  });
9061
8328
  config.onReady?.();
9062
8329
  }
@@ -9099,4 +8366,4 @@ export {
9099
8366
  init as i,
9100
8367
  t
9101
8368
  };
9102
- //# sourceMappingURL=index-DLo9u9kS.js.map
8369
+ //# sourceMappingURL=index-DCvvWewP.js.map