📝 listatt Code_Change_Report.mdv4.2 · 2026-09-05

Checkpoint: ListAttBBC v6.9 → v7.0 — PDF "Download instead of viewing" toggle

1. Problem & Resolution

Problem. Andrew wanted PDF rows in a [listatt] box to be openable via Adobe Acrobat, not just the built-in PDF.js viewer. Several UI approaches were discussed and ruled out on the way to this one:

Resolution. A checkbox is the one part of this that's fully within a webpage's control. Added "Download PDFs instead of viewing" next to the existing theme switcher in each listatt box header:

2. Risk Analysis

Risk Assessment
Regression to non-PDF rows None — pdfAttrs/data-pdf-view is only ever set when fileExt() === 'pdf'; listattFileClick() falls through to the original popup behavior for every other row exactly as before.
Regression to PDF viewing when unchecked None by design — listattApplyPdfMode() only swaps href when listattPdfDownloadMode is true; default state (no localStorage key set) evaluates false, so first-time visitors see identical behavior to v6.9.
Multiple listatt boxes on one page (common on volume posts) Handled — the toggle and the mode flag are page-global (window.listattPdfDownloadMode, one shared localStorage key), and both the checkbox sync loop and listattApplyPdfMode() iterate every box's toggle/every PDF link on the page, not just the one clicked.
XSS via filename in new data-pdf-view/data-pdf-dl attributes None — both are passed through htmlspecialchars(..., ENT_QUOTES) before being embedded, same discipline as the existing htmlspecialchars($a['filename']) call two lines below.
Browser compatibility of hasAttribute / querySelectorAll / localStorage None — all three are already used elsewhere in this same file's script block (theme switcher), so no new browser-support surface is introduced.
Popup blockers Unchanged — window.open() is still only called from a real user click handler (listattFileClick), same as v6.9; no new popup call sites were added.
Migration / existing posts None needed — this is a display-time behavior change in the mod itself, not a per-post attribute; the ~4000 already-migrated [listatt] posts pick it up automatically on next render, no bulk edit or re-migration required.

Overall risk: low. Purely additive — new attribute, new checkbox, new JS functions — with the v6.9 code path left completely intact as the default (unchecked) behavior.

3. Code Change

Full unified diff (ListAttBBC.diff, included alongside this report) between v6.9 and v7.0. Summary of the five touch points:

  1. Doc-block@version 7.0, @date 2026-09-09, new v7.0 changelog entry explaining what was tried and why the checkbox is the ceiling of what's achievable.
  2. ConstantsVERSION/BUILD_DATE bumped to match.
  3. CSS — two new small rules, .listatt-pdf-toggle-label and .listatt-pdf-toggle, styled consistently with the existing .listatt-switcher block.
  4. Row markup — PDF rows now also carry data-pdf-view="<pdfjs url>" data-pdf-dl="<raw dlattach url>"; the filename <a>'s inline onclick was refactored out into a single shared listattFileClick(this, event) function (previously identical inline JS was duplicated per row via string concatenation — same logic, no functional change for non-PDF rows).
  5. Script block — three new functions (listattApplyPdfMode, listattSetPdfMode, listattFileClick) plus an extension to the existing page-load IIFE to sync toggle state and apply the saved preference on first paint, matching the theme switcher's own init pattern exactly.

Files changed: ListAttBBC.php only. No changes to listatt.css, listatt_display_patch.xml, CollabCore/*, or any installer script.