accessify-widget 0.2.16 → 0.2.17

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.
@@ -6310,16 +6310,16 @@ function FeatureGrid($$anchor, $$props) {
6310
6310
  const FEATURE_LOADERS = {
6311
6311
  contrast: () => import("./contrast-CqsICAkU.js"),
6312
6312
  "text-size": () => import("./text-size-C6OFhCGi.js"),
6313
- "keyboard-nav": () => import("./keyboard-nav-Ckw-aZ93.js"),
6313
+ "keyboard-nav": () => import("./keyboard-nav-CfJ2ocV2.js"),
6314
6314
  "link-highlight": () => import("./link-highlight-DBGm067Y.js"),
6315
6315
  "reading-guide": () => import("./reading-guide-VT8NciIL.js"),
6316
6316
  "reading-mask": () => import("./reading-mask-BABChuCz.js"),
6317
- "animation-stop": () => import("./animation-stop-BG1kaNGZ.js"),
6317
+ "animation-stop": () => import("./animation-stop-CNucTFZ2.js"),
6318
6318
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6319
6319
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6320
- "page-structure": () => import("./page-structure-DfDEgXGb.js"),
6320
+ "page-structure": () => import("./page-structure-DAbGRhYZ.js"),
6321
6321
  tts: () => import("./tts-CjszLRnb.js"),
6322
- "text-simplify": () => import("./text-simplify-B1v6Muvn.js"),
6322
+ "text-simplify": () => import("./text-simplify-Cvhpio7g.js"),
6323
6323
  "alt-text": () => Promise.resolve().then(() => altText)
6324
6324
  };
6325
6325
  let contrastMode = /* @__PURE__ */ state(proxy(readStoredContrastMode()));
@@ -6624,9 +6624,22 @@ function PanelFooter($$anchor, $$props) {
6624
6624
  append($$anchor, div);
6625
6625
  pop();
6626
6626
  }
6627
- let savedNodes = [];
6627
+ let savedTextNodes = [];
6628
+ let savedAttrs = [];
6628
6629
  let currentTranslateLang = null;
6629
6630
  let translating = false;
6631
+ let observer = null;
6632
+ let observerPaused = false;
6633
+ const TRANSLATABLE_ATTRS = [
6634
+ "aria-label",
6635
+ "aria-description",
6636
+ "placeholder",
6637
+ "title",
6638
+ "alt",
6639
+ "aria-placeholder",
6640
+ "aria-roledescription",
6641
+ "aria-valuetext"
6642
+ ];
6630
6643
  const TRANSLATE_URL = "https://translate.googleapis.com/translate_a/single";
6631
6644
  async function translateSingleText(text, sourceLang, targetLang) {
6632
6645
  const params = new URLSearchParams({
@@ -6668,24 +6681,23 @@ async function translateTexts(texts, sourceLang, targetLang) {
6668
6681
  }
6669
6682
  return results;
6670
6683
  }
6671
- function getTranslatableTextNodes() {
6684
+ function getTranslatableTextNodes(root2 = document.body) {
6672
6685
  const walker = document.createTreeWalker(
6673
- document.body,
6686
+ root2,
6674
6687
  NodeFilter.SHOW_TEXT,
6675
6688
  {
6676
6689
  acceptNode(node) {
6677
- if (!node.textContent || !node.textContent.trim()) {
6678
- return NodeFilter.FILTER_REJECT;
6679
- }
6690
+ if (!node.textContent || !node.textContent.trim()) return NodeFilter.FILTER_REJECT;
6680
6691
  const parent = node.parentElement;
6681
6692
  if (!parent) return NodeFilter.FILTER_REJECT;
6682
6693
  const tag2 = parent.tagName;
6683
6694
  if (["SCRIPT", "STYLE", "NOSCRIPT", "CODE", "PRE", "TEXTAREA", "INPUT"].includes(tag2)) {
6684
6695
  return NodeFilter.FILTER_REJECT;
6685
6696
  }
6686
- if (parent.closest("accessify-widget")) {
6697
+ if (parent.closest("accessify-widget") || parent.closest("#accessify-root")) {
6687
6698
  return NodeFilter.FILTER_REJECT;
6688
6699
  }
6700
+ if (parent.classList?.contains("notranslate")) return NodeFilter.FILTER_REJECT;
6689
6701
  return NodeFilter.FILTER_ACCEPT;
6690
6702
  }
6691
6703
  }
@@ -6697,43 +6709,121 @@ function getTranslatableTextNodes() {
6697
6709
  }
6698
6710
  return nodes;
6699
6711
  }
6712
+ function getTranslatableAttributes(root2 = document.body) {
6713
+ const attrs = [];
6714
+ const all = root2.querySelectorAll("*");
6715
+ for (const el of all) {
6716
+ if (el.closest("accessify-widget") || el.closest("#accessify-root")) continue;
6717
+ for (const attr of TRANSLATABLE_ATTRS) {
6718
+ const val = el.getAttribute(attr);
6719
+ if (val?.trim()) {
6720
+ attrs.push({ el, attr, original: val });
6721
+ }
6722
+ }
6723
+ }
6724
+ return attrs;
6725
+ }
6726
+ async function translatePage(targetLang) {
6727
+ const pageLang = document.documentElement.lang?.split("-")[0] || "auto";
6728
+ const textNodes = getTranslatableTextNodes();
6729
+ const attrEntries = getTranslatableAttributes();
6730
+ const existingSaved = new Set(savedTextNodes.map((s) => s.node));
6731
+ for (const node of textNodes) {
6732
+ if (!existingSaved.has(node)) {
6733
+ savedTextNodes.push({ node, original: node.data });
6734
+ }
6735
+ }
6736
+ const existingAttrs = new Set(savedAttrs.map((s) => `${getElId(s.el)}:${s.attr}`));
6737
+ for (const entry of attrEntries) {
6738
+ const key = `${getElId(entry.el)}:${entry.attr}`;
6739
+ if (!existingAttrs.has(key)) {
6740
+ savedAttrs.push(entry);
6741
+ }
6742
+ }
6743
+ const allTexts = [
6744
+ ...textNodes.map((n) => n.data.trim()),
6745
+ ...attrEntries.map((a) => a.original.trim())
6746
+ ].filter(Boolean);
6747
+ const uniqueTexts = [...new Set(allTexts)];
6748
+ if (uniqueTexts.length === 0) return;
6749
+ const translated = await translateTexts(uniqueTexts, pageLang, targetLang);
6750
+ const lookup = /* @__PURE__ */ new Map();
6751
+ uniqueTexts.forEach((text, i) => {
6752
+ if (translated[i] && translated[i] !== text) {
6753
+ lookup.set(text, translated[i]);
6754
+ }
6755
+ });
6756
+ observerPaused = true;
6757
+ for (const node of textNodes) {
6758
+ const trimmed = node.data.trim();
6759
+ const replacement = lookup.get(trimmed);
6760
+ if (replacement) {
6761
+ const leading = node.data.match(/^\s*/)?.[0] || "";
6762
+ const trailing = node.data.match(/\s*$/)?.[0] || "";
6763
+ node.data = leading + replacement + trailing;
6764
+ }
6765
+ }
6766
+ for (const entry of attrEntries) {
6767
+ const replacement = lookup.get(entry.original.trim());
6768
+ if (replacement) {
6769
+ entry.el.setAttribute(entry.attr, replacement);
6770
+ }
6771
+ }
6772
+ observerPaused = false;
6773
+ }
6774
+ function setupObserver(targetLang) {
6775
+ if (observer) observer.disconnect();
6776
+ const debouncedTranslate = debounce(() => {
6777
+ if (!currentTranslateLang || observerPaused) return;
6778
+ translatePage(currentTranslateLang);
6779
+ }, 300);
6780
+ observer = new MutationObserver((mutations) => {
6781
+ if (observerPaused || !currentTranslateLang) return;
6782
+ let hasRelevantChange = false;
6783
+ for (const m of mutations) {
6784
+ if (m.addedNodes.length > 0) {
6785
+ hasRelevantChange = true;
6786
+ break;
6787
+ }
6788
+ if (m.type === "characterData") {
6789
+ hasRelevantChange = true;
6790
+ break;
6791
+ }
6792
+ }
6793
+ if (hasRelevantChange) debouncedTranslate();
6794
+ });
6795
+ observer.observe(document.body, {
6796
+ childList: true,
6797
+ subtree: true,
6798
+ characterData: true
6799
+ });
6800
+ }
6801
+ function teardownObserver() {
6802
+ observer?.disconnect();
6803
+ observer = null;
6804
+ }
6805
+ function getElId(el) {
6806
+ return el.id || el.getAttribute("data-a11y-id") || (el.setAttribute("data-a11y-id", Math.random().toString(36).substr(2, 9)), el.getAttribute("data-a11y-id"));
6807
+ }
6808
+ function debounce(fn, ms) {
6809
+ let timer;
6810
+ return () => {
6811
+ clearTimeout(timer);
6812
+ timer = setTimeout(fn, ms);
6813
+ };
6814
+ }
6700
6815
  function createTextTransformService() {
6701
6816
  return {
6702
6817
  async translate(targetLang) {
6703
6818
  if (translating) return;
6704
6819
  translating = true;
6705
6820
  try {
6706
- if (savedNodes.length > 0) {
6821
+ if (savedTextNodes.length > 0) {
6707
6822
  this.restore();
6708
6823
  }
6709
- const pageLang = document.documentElement.lang?.split("-")[0] || "auto";
6710
- const textNodes = getTranslatableTextNodes();
6711
- if (textNodes.length === 0) {
6712
- translating = false;
6713
- return;
6714
- }
6715
- savedNodes = textNodes.map((node) => ({
6716
- node,
6717
- original: node.textContent
6718
- }));
6719
- const uniqueTexts = [...new Set(savedNodes.map((s) => s.original.trim()).filter(Boolean))];
6720
- const translated = await translateTexts(uniqueTexts, pageLang, targetLang);
6721
- const lookup = /* @__PURE__ */ new Map();
6722
- uniqueTexts.forEach((text, i) => {
6723
- if (translated[i]) {
6724
- lookup.set(text, translated[i]);
6725
- }
6726
- });
6727
- for (const saved of savedNodes) {
6728
- const trimmed = saved.original.trim();
6729
- const replacement = lookup.get(trimmed);
6730
- if (replacement) {
6731
- const leading = saved.original.match(/^\s*/)?.[0] || "";
6732
- const trailing = saved.original.match(/\s*$/)?.[0] || "";
6733
- saved.node.textContent = leading + replacement + trailing;
6734
- }
6735
- }
6824
+ await translatePage(targetLang);
6736
6825
  currentTranslateLang = targetLang;
6826
+ setupObserver(targetLang);
6737
6827
  } finally {
6738
6828
  translating = false;
6739
6829
  }
@@ -6741,11 +6831,25 @@ function createTextTransformService() {
6741
6831
  async simplify(_level, _lang) {
6742
6832
  },
6743
6833
  restore() {
6744
- for (const saved of savedNodes) {
6745
- saved.node.textContent = saved.original;
6834
+ teardownObserver();
6835
+ observerPaused = true;
6836
+ for (const saved of savedTextNodes) {
6837
+ if (saved.node.parentNode) {
6838
+ saved.node.data = saved.original;
6839
+ }
6746
6840
  }
6747
- savedNodes = [];
6841
+ savedTextNodes = [];
6842
+ for (const saved of savedAttrs) {
6843
+ if (saved.el.isConnected) {
6844
+ saved.el.setAttribute(saved.attr, saved.original);
6845
+ }
6846
+ }
6847
+ savedAttrs = [];
6848
+ document.querySelectorAll("[data-a11y-id]").forEach((el) => {
6849
+ el.removeAttribute("data-a11y-id");
6850
+ });
6748
6851
  currentTranslateLang = null;
6852
+ observerPaused = false;
6749
6853
  },
6750
6854
  isTranslated() {
6751
6855
  return currentTranslateLang !== null;
@@ -7641,10 +7745,11 @@ async function autoApplyCachedAltTexts(widgetConfig) {
7641
7745
  let applied = 0;
7642
7746
  const images = document.querySelectorAll("img");
7643
7747
  images.forEach((img) => {
7644
- if (img.closest("#accessify-root")) return;
7748
+ if (img.closest("#accessify-root") || img.closest("accessify-widget")) return;
7645
7749
  const alt = img.getAttribute("alt");
7646
7750
  if (alt !== null && alt.trim() !== "") return;
7647
- const cached = cache.get(img.src);
7751
+ const src = img.currentSrc || img.src;
7752
+ const cached = cache.get(src) || cache.get(img.src);
7648
7753
  if (cached) {
7649
7754
  img.setAttribute("alt", cached);
7650
7755
  img.setAttribute("title", cached);
@@ -7652,15 +7757,16 @@ async function autoApplyCachedAltTexts(widgetConfig) {
7652
7757
  applied++;
7653
7758
  }
7654
7759
  });
7655
- const observer = new MutationObserver((mutations) => {
7760
+ const observer2 = new MutationObserver((mutations) => {
7656
7761
  for (const m of mutations) {
7657
7762
  for (const node of m.addedNodes) {
7658
7763
  const imgs = node instanceof HTMLImageElement ? [node] : node instanceof HTMLElement ? Array.from(node.querySelectorAll("img")) : [];
7659
7764
  for (const img of imgs) {
7660
- if (img.closest("#accessify-root")) continue;
7765
+ if (img.closest("#accessify-root") || img.closest("accessify-widget")) continue;
7661
7766
  const a = img.getAttribute("alt");
7662
7767
  if (a !== null && a.trim() !== "") continue;
7663
- const c = cache.get(img.src);
7768
+ const src = img.currentSrc || img.src;
7769
+ const c = cache.get(src) || cache.get(img.src);
7664
7770
  if (c) {
7665
7771
  img.setAttribute("alt", c);
7666
7772
  img.setAttribute("title", c);
@@ -7670,8 +7776,8 @@ async function autoApplyCachedAltTexts(widgetConfig) {
7670
7776
  }
7671
7777
  }
7672
7778
  });
7673
- observer.observe(document.body, { childList: true, subtree: true });
7674
- setTimeout(() => observer.disconnect(), 3e4);
7779
+ observer2.observe(document.body, { childList: true, subtree: true });
7780
+ setTimeout(() => observer2.disconnect(), 3e4);
7675
7781
  return applied;
7676
7782
  }
7677
7783
  function createAltTextModule(aiService, initialLang = "de", serverConfig) {
@@ -7952,14 +8058,43 @@ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
7952
8058
  reportPanelEl?.remove();
7953
8059
  reportPanelEl = null;
7954
8060
  }
8061
+ function isGenericAlt(alt) {
8062
+ if (!alt.trim()) return true;
8063
+ if (/^(image|img|photo|bild|foto|untitled|placeholder)/i.test(alt)) return true;
8064
+ if (/^IMG_\d+/i.test(alt)) return true;
8065
+ if (/\.(jpg|jpeg|png|gif|webp|svg|avif)$/i.test(alt)) return true;
8066
+ return false;
8067
+ }
7955
8068
  function scanForMissingAlt() {
7956
- const images = document.querySelectorAll("img");
7957
8069
  const missing = [];
7958
- images.forEach((img) => {
7959
- if (img.closest("#accessify-root")) return;
8070
+ document.querySelectorAll("img").forEach((img) => {
8071
+ if (img.closest("#accessify-root") || img.closest("accessify-widget")) return;
7960
8072
  if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 20 || img.naturalHeight < 20)) return;
7961
8073
  const alt = img.getAttribute("alt");
7962
- if (alt === null || alt.trim() === "") missing.push(img);
8074
+ if (alt === "") return;
8075
+ if (alt === null || isGenericAlt(alt)) missing.push(img);
8076
+ });
8077
+ document.querySelectorAll("picture").forEach((picture) => {
8078
+ if (picture.closest("#accessify-root") || picture.closest("accessify-widget")) return;
8079
+ const img = picture.querySelector("img");
8080
+ if (img && !missing.includes(img)) {
8081
+ const alt = img.getAttribute("alt");
8082
+ if (alt === null || isGenericAlt(alt)) {
8083
+ missing.push(img);
8084
+ }
8085
+ }
8086
+ });
8087
+ document.querySelectorAll("*").forEach((el) => {
8088
+ if (el.closest("#accessify-root") || el.closest("accessify-widget")) return;
8089
+ if (el.tagName === "SCRIPT" || el.tagName === "STYLE") return;
8090
+ const bg = window.getComputedStyle(el).backgroundImage;
8091
+ if (!bg || bg === "none" || !bg.startsWith("url(")) return;
8092
+ const src = bg.match(/url\(["']?(.+?)["']?\)/)?.[1];
8093
+ if (!src || src.includes("data:") || src.includes("gradient")) return;
8094
+ if (el.textContent?.trim() || el.getAttribute("aria-label")) return;
8095
+ if (!el.dataset.accessifyBgSrc) {
8096
+ el.dataset.accessifyBgSrc = src;
8097
+ }
7963
8098
  });
7964
8099
  return missing;
7965
8100
  }
@@ -8400,4 +8535,4 @@ export {
8400
8535
  init as i,
8401
8536
  t
8402
8537
  };
8403
- //# sourceMappingURL=index-BRmOW1-V.js.map
8538
+ //# sourceMappingURL=index-a0msSpCc.js.map