accessify-widget 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { d, i } from "./index-C9-1BpqV.js";
1
+ import { d, i } from "./index-DcqLuguC.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -6433,14 +6433,14 @@ function FeatureGrid($$anchor, $$props) {
6433
6433
  const FEATURE_LOADERS = {
6434
6434
  contrast: () => import("./contrast-CqsICAkU.js"),
6435
6435
  "text-size": () => import("./text-size-C6OFhCGi.js"),
6436
- "keyboard-nav": () => import("./keyboard-nav-DF9rgWAV.js"),
6436
+ "keyboard-nav": () => import("./keyboard-nav-BYCst88Y.js"),
6437
6437
  "link-highlight": () => import("./link-highlight-DBGm067Y.js"),
6438
6438
  "reading-guide": () => import("./reading-guide-VT8NciIL.js"),
6439
6439
  "reading-mask": () => import("./reading-mask-BABChuCz.js"),
6440
6440
  "animation-stop": () => import("./animation-stop-C0MwseK0.js"),
6441
6441
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6442
6442
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6443
- "page-structure": () => import("./page-structure-BcyV93JT.js"),
6443
+ "page-structure": () => import("./page-structure-MGMdSnYw.js"),
6444
6444
  tts: () => import("./tts-CjszLRnb.js"),
6445
6445
  "text-simplify": () => import("./text-simplify-Cvhpio7g.js"),
6446
6446
  "alt-text": () => Promise.resolve().then(() => altText)
@@ -7953,16 +7953,16 @@ async function autoApplyCachedAltTexts(widgetConfig) {
7953
7953
  if (cache.size === 0) return 0;
7954
7954
  function applyToImg(img) {
7955
7955
  if (img.closest("#accessify-root") || img.closest("accessify-widget")) return false;
7956
- const alt = img.getAttribute("alt");
7957
- if (alt !== null && alt.trim() !== "") return false;
7958
7956
  const src = getImageSrc(img);
7959
7957
  const cached = cache.get(src) || cache.get(normalizeImageUrl(src)) || cache.get(img.src);
7960
- if (cached) {
7958
+ if (!cached) return false;
7959
+ const alt = img.getAttribute("alt");
7960
+ if (alt === null || alt.trim() === "") {
7961
7961
  img.setAttribute("alt", cached);
7962
7962
  img.setAttribute("data-accessify-alt", "auto");
7963
- return true;
7964
7963
  }
7965
- return false;
7964
+ img.setAttribute("title", cached);
7965
+ return true;
7966
7966
  }
7967
7967
  let applied = 0;
7968
7968
  document.querySelectorAll("img").forEach((img) => {
@@ -7984,257 +7984,16 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
7984
7984
  const siteKey = serverConfig?.siteKey || "";
7985
7985
  const proxyUrl = serverConfig?.proxyUrl || "";
7986
7986
  let enabled = false;
7987
- let styleEl = null;
7988
- let tooltipEl = null;
7989
7987
  let domObserver = null;
7990
7988
  let autoGenerating = false;
7991
7989
  let missingAltImages = [];
7992
7990
  const processedImages = /* @__PURE__ */ new Map();
7993
- let describeClickHandler = null;
7994
- let describeEscHandler = null;
7995
- const describeButtons = /* @__PURE__ */ new Map();
7996
7991
  function lang() {
7997
7992
  return getCurrentWidgetLang() || initialLang;
7998
7993
  }
7999
7994
  function isDE() {
8000
7995
  return lang().startsWith("de");
8001
7996
  }
8002
- const STYLE_ID = "accessify-alt-text-styles";
8003
- function getStyles() {
8004
- return `
8005
- img[data-a11y-describable="true"]:not([data-a11y-is-link="true"]) {
8006
- cursor: help !important;
8007
- }
8008
-
8009
- .accessify-describe-btn {
8010
- position: absolute;
8011
- top: 6px;
8012
- right: 6px;
8013
- z-index: 10;
8014
- width: 26px;
8015
- height: 26px;
8016
- padding: 0;
8017
- border: none;
8018
- border-radius: 50%;
8019
- background: rgba(0, 0, 0, 0.55);
8020
- color: #fff;
8021
- font-family: system-ui, -apple-system, sans-serif;
8022
- font-size: 14px;
8023
- font-weight: 700;
8024
- line-height: 26px;
8025
- text-align: center;
8026
- cursor: help;
8027
- opacity: 0;
8028
- transition: opacity 0.15s ease;
8029
- backdrop-filter: blur(4px);
8030
- }
8031
- img[data-a11y-is-link="true"]:hover ~ .accessify-describe-btn,
8032
- .accessify-describe-btn:hover {
8033
- opacity: 1;
8034
- }
8035
- .accessify-describe-btn:hover {
8036
- background: rgba(0, 0, 0, 0.75);
8037
- }
8038
-
8039
- .accessify-describe-tooltip {
8040
- position: fixed;
8041
- z-index: 2147483647;
8042
- max-width: 320px;
8043
- padding: 10px 14px;
8044
- background: rgba(0, 0, 0, 0.75);
8045
- color: #fff;
8046
- border-radius: 8px;
8047
- backdrop-filter: blur(8px);
8048
- font-family: system-ui, -apple-system, sans-serif;
8049
- font-size: 13px;
8050
- line-height: 1.5;
8051
- word-break: break-word;
8052
- animation: accessify-fade-in 0.12s ease;
8053
- pointer-events: auto;
8054
- }
8055
- .accessify-describe-loading {
8056
- display: flex;
8057
- align-items: center;
8058
- gap: 8px;
8059
- color: #ddd;
8060
- font-style: italic;
8061
- }
8062
- .accessify-describe-loading::before {
8063
- content: '';
8064
- width: 12px;
8065
- height: 12px;
8066
- border: 2px solid rgba(255,255,255,0.3);
8067
- border-top-color: #fff;
8068
- border-radius: 50%;
8069
- animation: accessify-spin 0.8s linear infinite;
8070
- }
8071
- @keyframes accessify-spin {
8072
- to { transform: rotate(360deg); }
8073
- }
8074
- @keyframes accessify-fade-in {
8075
- from { opacity: 0; transform: translateY(4px); }
8076
- to { opacity: 1; transform: translateY(0); }
8077
- }
8078
- `;
8079
- }
8080
- function injectStyles() {
8081
- if (document.getElementById(STYLE_ID)) return;
8082
- styleEl = document.createElement("style");
8083
- styleEl.id = STYLE_ID;
8084
- styleEl.textContent = getStyles();
8085
- document.head.appendChild(styleEl);
8086
- }
8087
- function removeStyles() {
8088
- styleEl?.remove();
8089
- styleEl = null;
8090
- document.getElementById(STYLE_ID)?.remove();
8091
- }
8092
- function showDescribeTooltip(text, rect, loading = false) {
8093
- hideDescribeTooltip();
8094
- const tip = document.createElement("div");
8095
- tip.className = "accessify-describe-tooltip";
8096
- if (loading) {
8097
- const loadingEl = document.createElement("div");
8098
- loadingEl.className = "accessify-describe-loading";
8099
- loadingEl.textContent = isDE() ? "Bild wird analysiert…" : "Analyzing image…";
8100
- tip.appendChild(loadingEl);
8101
- } else {
8102
- const textEl = document.createElement("div");
8103
- textEl.textContent = text;
8104
- tip.appendChild(textEl);
8105
- }
8106
- document.body.appendChild(tip);
8107
- tooltipEl = tip;
8108
- const tipRect = tip.getBoundingClientRect();
8109
- let top = rect.bottom + 8;
8110
- if (top + tipRect.height > window.innerHeight - 8) {
8111
- top = rect.top - tipRect.height - 8;
8112
- }
8113
- if (top < 4) top = 4;
8114
- let left = rect.left + (rect.width - tipRect.width) / 2;
8115
- left = Math.max(8, Math.min(left, window.innerWidth - tipRect.width - 8));
8116
- tip.style.top = `${top}px`;
8117
- tip.style.left = `${left}px`;
8118
- }
8119
- function hideDescribeTooltip() {
8120
- tooltipEl?.remove();
8121
- tooltipEl = null;
8122
- }
8123
- async function handleImageClick(img) {
8124
- const rect = img.getBoundingClientRect();
8125
- const cached = img.dataset.accessifyDescription;
8126
- if (cached) {
8127
- showDescribeTooltip(cached, rect);
8128
- return;
8129
- }
8130
- const existingAlt = img.getAttribute("alt");
8131
- showDescribeTooltip("", rect, true);
8132
- try {
8133
- if (!aiService) {
8134
- showDescribeTooltip(
8135
- existingAlt || (isDE() ? "Kein API-Key konfiguriert" : "No API key configured"),
8136
- rect
8137
- );
8138
- return;
8139
- }
8140
- const src = getImageSrc(img);
8141
- const description = await aiService.describeImage(src, lang());
8142
- if (!enabled) return;
8143
- img.dataset.accessifyDescription = description;
8144
- showDescribeTooltip(description, rect);
8145
- const currentAlt = img.getAttribute("alt");
8146
- if (!currentAlt || !currentAlt.trim()) {
8147
- try {
8148
- const ctx = gatherImageContext(img);
8149
- const altText2 = await aiService.generateAltText(src, ctx, lang());
8150
- if (altText2) {
8151
- img.setAttribute("alt", altText2);
8152
- setCachedAltText(src, altText2, lang()).catch(() => {
8153
- });
8154
- if (siteKey) persistAltTextToServer(siteKey, proxyUrl, src, altText2, lang());
8155
- }
8156
- } catch {
8157
- }
8158
- }
8159
- } catch (err) {
8160
- console.warn("[Accessify] Image description failed:", err);
8161
- showDescribeTooltip(
8162
- existingAlt || (isDE() ? "Beschreibung konnte nicht geladen werden" : "Could not load description"),
8163
- rect
8164
- );
8165
- }
8166
- }
8167
- function isLinkedImage(img) {
8168
- return !!img.closest("a[href]");
8169
- }
8170
- function addDescribeButton(img) {
8171
- if (describeButtons.has(img)) return;
8172
- const parent = img.parentElement;
8173
- if (!parent) return;
8174
- const pos = getComputedStyle(parent).position;
8175
- if (pos === "static") parent.style.position = "relative";
8176
- const btn = document.createElement("button");
8177
- btn.className = "accessify-describe-btn";
8178
- btn.textContent = "i";
8179
- btn.setAttribute("aria-label", isDE() ? "Bildbeschreibung anzeigen" : "Show image description");
8180
- btn.addEventListener("click", (e) => {
8181
- e.preventDefault();
8182
- e.stopPropagation();
8183
- handleImageClick(img);
8184
- });
8185
- img.insertAdjacentElement("afterend", btn);
8186
- describeButtons.set(img, btn);
8187
- }
8188
- function removeDescribeButtons() {
8189
- describeButtons.forEach((btn) => btn.remove());
8190
- describeButtons.clear();
8191
- }
8192
- function markImageDescribable(img) {
8193
- if (img.closest("#accessify-root") || img.closest("accessify-widget")) return;
8194
- if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 20 || img.naturalHeight < 20)) return;
8195
- img.dataset.a11yDescribable = "true";
8196
- if (isLinkedImage(img)) {
8197
- img.dataset.a11yIsLink = "true";
8198
- addDescribeButton(img);
8199
- }
8200
- }
8201
- function enableClickToDescribe() {
8202
- document.querySelectorAll("img").forEach(markImageDescribable);
8203
- describeClickHandler = (e) => {
8204
- if (e.target.closest(".accessify-describe-tooltip")) return;
8205
- if (e.target.closest(".accessify-describe-btn")) return;
8206
- const img = e.target.closest("img[data-a11y-describable]");
8207
- if (!img) {
8208
- if (tooltipEl) hideDescribeTooltip();
8209
- return;
8210
- }
8211
- if (isLinkedImage(img)) return;
8212
- e.preventDefault();
8213
- e.stopPropagation();
8214
- handleImageClick(img);
8215
- };
8216
- document.addEventListener("click", describeClickHandler, true);
8217
- describeEscHandler = (e) => {
8218
- if (e.key === "Escape") hideDescribeTooltip();
8219
- };
8220
- document.addEventListener("keydown", describeEscHandler);
8221
- }
8222
- function disableClickToDescribe() {
8223
- if (describeClickHandler) {
8224
- document.removeEventListener("click", describeClickHandler, true);
8225
- describeClickHandler = null;
8226
- }
8227
- if (describeEscHandler) {
8228
- document.removeEventListener("keydown", describeEscHandler);
8229
- describeEscHandler = null;
8230
- }
8231
- hideDescribeTooltip();
8232
- removeDescribeButtons();
8233
- document.querySelectorAll("img[data-a11y-describable]").forEach((img) => {
8234
- delete img.dataset.a11yDescribable;
8235
- delete img.dataset.a11yIsLink;
8236
- });
8237
- }
8238
7997
  function isGenericAlt(alt) {
8239
7998
  if (!alt.trim()) return true;
8240
7999
  if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;
@@ -8248,9 +8007,13 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8248
8007
  if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 50 || img.naturalHeight < 50)) return true;
8249
8008
  return false;
8250
8009
  }
8251
- function needsAltText(img) {
8010
+ function isValidImage(img) {
8252
8011
  if (img.closest("#accessify-root") || img.closest("accessify-widget")) return false;
8253
8012
  if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 20 || img.naturalHeight < 20)) return false;
8013
+ return true;
8014
+ }
8015
+ function needsAltText(img) {
8016
+ if (!isValidImage(img)) return false;
8254
8017
  const alt = img.getAttribute("alt");
8255
8018
  if (alt === null) return true;
8256
8019
  if (isGenericAlt(alt)) return true;
@@ -8293,8 +8056,26 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8293
8056
  }
8294
8057
  function applyAltText(img, altText2) {
8295
8058
  img.setAttribute("alt", altText2);
8059
+ img.setAttribute("title", altText2);
8296
8060
  processedImages.set(img, { generatedAlt: altText2 });
8297
8061
  }
8062
+ function applyTitlesToAllImages() {
8063
+ document.querySelectorAll("img").forEach((img) => {
8064
+ if (!isValidImage(img)) return;
8065
+ if (img.getAttribute("title")) return;
8066
+ const alt = img.getAttribute("alt");
8067
+ if (alt && alt.trim()) {
8068
+ img.setAttribute("title", alt);
8069
+ img.setAttribute("data-accessify-title", "auto");
8070
+ }
8071
+ });
8072
+ }
8073
+ function removeTitles() {
8074
+ document.querySelectorAll('img[data-accessify-title="auto"]').forEach((img) => {
8075
+ img.removeAttribute("title");
8076
+ img.removeAttribute("data-accessify-title");
8077
+ });
8078
+ }
8298
8079
  async function generateAll() {
8299
8080
  if (autoGenerating || !enabled || !aiService) return;
8300
8081
  autoGenerating = true;
@@ -8342,7 +8123,6 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8342
8123
  const cached = await getCachedAltText(src);
8343
8124
  if (cached) {
8344
8125
  applyAltText(img, cached);
8345
- updateBadge();
8346
8126
  return;
8347
8127
  }
8348
8128
  try {
@@ -8360,15 +8140,20 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8360
8140
  }
8361
8141
  function tryRegisterImage(img) {
8362
8142
  if (!enabled) return;
8363
- if (img.closest("#accessify-root")) return;
8143
+ if (!isValidImage(img)) return;
8364
8144
  if (missingAltImages.includes(img)) return;
8365
8145
  function addIfValid() {
8366
8146
  if (!enabled || missingAltImages.includes(img)) return;
8367
8147
  if (img.naturalWidth < 20 || img.naturalHeight < 20) return;
8368
- markImageDescribable(img);
8369
8148
  if (needsAltText(img)) {
8370
8149
  missingAltImages.push(img);
8371
8150
  generateSingle(img);
8151
+ } else {
8152
+ const alt = img.getAttribute("alt");
8153
+ if (alt && alt.trim() && !img.getAttribute("title")) {
8154
+ img.setAttribute("title", alt);
8155
+ img.setAttribute("data-accessify-title", "auto");
8156
+ }
8372
8157
  }
8373
8158
  }
8374
8159
  if (img.complete && img.naturalWidth > 0) addIfValid();
@@ -8377,9 +8162,7 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8377
8162
  function activate() {
8378
8163
  if (enabled) return;
8379
8164
  enabled = true;
8380
- injectStyles();
8381
- const alreadyApplied = document.querySelectorAll('img[data-accessify-alt="auto"]');
8382
- alreadyApplied.forEach((img) => {
8165
+ document.querySelectorAll('img[data-accessify-alt="auto"]').forEach((img) => {
8383
8166
  if (img.closest("#accessify-root")) return;
8384
8167
  if (!processedImages.has(img)) {
8385
8168
  processedImages.set(img, { generatedAlt: img.getAttribute("alt") || "" });
@@ -8393,13 +8176,14 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8393
8176
  }
8394
8177
  }
8395
8178
  generateAll();
8396
- enableClickToDescribe();
8179
+ applyTitlesToAllImages();
8397
8180
  document.querySelectorAll("img").forEach((img) => {
8398
8181
  if (!img.complete) tryRegisterImage(img);
8399
8182
  });
8400
8183
  setTimeout(() => {
8401
8184
  if (enabled) {
8402
8185
  document.querySelectorAll("img").forEach(tryRegisterImage);
8186
+ applyTitlesToAllImages();
8403
8187
  }
8404
8188
  }, 2e3);
8405
8189
  domObserver = new MutationObserver((mutations) => {
@@ -8408,11 +8192,6 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8408
8192
  if (node instanceof HTMLImageElement) tryRegisterImage(node);
8409
8193
  else if (node instanceof HTMLElement) {
8410
8194
  node.querySelectorAll("img").forEach(tryRegisterImage);
8411
- node.querySelectorAll("img").forEach((img) => {
8412
- if (!img.closest("#accessify-root") && !img.closest("accessify-widget")) {
8413
- img.dataset.a11yDescribable = "true";
8414
- }
8415
- });
8416
8195
  }
8417
8196
  }
8418
8197
  }
@@ -8424,9 +8203,8 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
8424
8203
  autoGenerating = false;
8425
8204
  domObserver?.disconnect();
8426
8205
  domObserver = null;
8427
- disableClickToDescribe();
8206
+ removeTitles();
8428
8207
  missingAltImages = [];
8429
- removeStyles();
8430
8208
  }
8431
8209
  autoApplyCachedAltTexts({ siteKey, proxyUrl, lang: initialLang }).catch(() => {
8432
8210
  });
@@ -8639,4 +8417,4 @@ export {
8639
8417
  init as i,
8640
8418
  t
8641
8419
  };
8642
- //# sourceMappingURL=index-C9-1BpqV.js.map
8420
+ //# sourceMappingURL=index-DcqLuguC.js.map