@bobfrankston/rmfmail 1.2.185 → 1.2.187

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.
@@ -1440,9 +1440,26 @@ function showPreviewBodyMenu(absX, absY, selectedText, sourceWindow, linkUrl, li
1440
1440
  function toggleFullscreenPreview() {
1441
1441
  const body = document.body;
1442
1442
  const on = !body.classList.contains("fullscreen-preview");
1443
+ if (on && !currentMessage)
1444
+ return;
1443
1445
  body.classList.toggle("fullscreen-preview", on);
1446
+ try {
1447
+ window.mailxapi?.logClientEvent?.(`[fullscreen] preview ${on ? "ON" : "OFF"}`);
1448
+ } catch {
1449
+ }
1444
1450
  let exit = document.getElementById("mv-exit-fullscreen");
1445
1451
  if (on) {
1452
+ if (!document.getElementById("mv-fullscreen-hint")) {
1453
+ const hint = document.createElement("div");
1454
+ hint.id = "mv-fullscreen-hint";
1455
+ hint.textContent = "Fullscreen reading \u2014 press Esc or double-click to exit";
1456
+ hint.style.cssText = "position:fixed;top:16px;left:50%;transform:translateX(-50%);z-index:6000;background:rgba(0,0,0,0.7);color:#fff;padding:8px 16px;border-radius:16px;font-size:13px;pointer-events:none;opacity:1;transition:opacity 0.5s;";
1457
+ document.body.appendChild(hint);
1458
+ setTimeout(() => {
1459
+ hint.style.opacity = "0";
1460
+ }, 2500);
1461
+ setTimeout(() => hint.remove(), 3100);
1462
+ }
1446
1463
  if (!exit) {
1447
1464
  exit = document.createElement("button");
1448
1465
  exit.id = "mv-exit-fullscreen";
@@ -1464,6 +1481,7 @@ function toggleFullscreenPreview() {
1464
1481
  }
1465
1482
  } else {
1466
1483
  exit?.remove();
1484
+ document.getElementById("mv-fullscreen-hint")?.remove();
1467
1485
  }
1468
1486
  }
1469
1487
  function initViewer() {
@@ -2635,6 +2653,26 @@ ${csp}
2635
2653
  window.parent.postMessage({ type: "linkClick", url: url }, "*");
2636
2654
  }
2637
2655
  document.addEventListener("click", handleLinkTap, true);
2656
+ // Remote-image failure diagnostic. Bob 2026-07-28: an allowlisted
2657
+ // Nextdoor digest rendered every https image as a broken icon while the
2658
+ // same URLs fetched fine from curl \u2014 untraceable after the fact because
2659
+ // image load failures are silent. Report failures to the parent, which
2660
+ // logs them to the daemon log with the first failing URL.
2661
+ window.addEventListener("load", function () {
2662
+ setTimeout(function () {
2663
+ try {
2664
+ var bad = [];
2665
+ var imgs = document.images || [];
2666
+ for (var i = 0; i < imgs.length; i++) {
2667
+ var im = imgs[i];
2668
+ if (im.complete && im.naturalWidth === 0 && /^https?:/.test(im.src)) bad.push(im.src);
2669
+ }
2670
+ if (bad.length) {
2671
+ window.parent.postMessage({ type: "imgLoadFail", count: bad.length, total: imgs.length, first: String(bad[0]).slice(0, 160) }, "*");
2672
+ }
2673
+ } catch (e3) { /* diagnostic only */ }
2674
+ }, 3000);
2675
+ });
2638
2676
  // Android WebView fallback: some builds drop the synthetic click after
2639
2677
  // touchend, so treat a stationary touchstart\u2192touchend on the same link
2640
2678
  // as a tap. Anything that moves more than TAP_SLOP pixels is a scroll
@@ -10046,6 +10084,17 @@ window.addEventListener("message", (e) => {
10046
10084
  if (api?.openExternal) api.openExternal(url);
10047
10085
  else window.open(url, "_blank", "noopener,noreferrer");
10048
10086
  }
10087
+ if (e.data?.type === "imgLoadFail") {
10088
+ try {
10089
+ logClientEvent("[viewer] remote images failed to load", {
10090
+ failed: e.data.count,
10091
+ total: e.data.total,
10092
+ first: e.data.first
10093
+ });
10094
+ } catch {
10095
+ }
10096
+ return;
10097
+ }
10049
10098
  if (e.data?.type === "previewToggleFullscreen") {
10050
10099
  toggleFullscreenPreview();
10051
10100
  return;