From a1267a546ed19aac8e07dc7b33b0e656eb1adb57 Mon Sep 17 00:00:00 2001 From: Charlotte Wickham Date: Wed, 23 Sep 2026 15:49:35 -0700 Subject: [PATCH] Download table: put the full checksum in the DOM, truncate it with CSS (#2139) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Put the full checksum in the DOM, truncate it with CSS The full SHA-256 lived only in a hover tooltip: keyboard users could not reach it, screen readers never heard it, nobody could copy it easily, and tippy put an invalid aria-expanded on the role-less div (axe aria-allowed-attr, WCAG 4.1.2). The truncated hash also used --bs-primary, which fails WCAG AA contrast for small text. Now the cell's text is the complete hash and only the rendering truncates (CSS ellipsis). The table looks the same as before, but screen readers announce the full value, double-click selects it for copying, and find-in-page matches it — no tooltip, no ARIA, default text color. The SHA-256 column header links to the release's checksums.txt so the full values are also visible at every viewport (WCAG 1.4.10 reflow). Also removes the tippy init for a.checksum, which matched nothing (checksums were divs). * Build the checksum header link with DOM APIs, not an HTML string createHeadingRow was assigning cell.outerHTML from a template literal containing an interpolated URL, the only place in this file that builds markup that way instead of createElement + .href/.innerText. Match the existing pattern so header cells are never built from unescaped strings. Also drops the WCAG 1.4.10 citation for the header link in the code comment - the mapping was shaky; the plain rationale stands on its own. (cherry picked from commit 664eab8f2f62fa6116fa72106c04703c99216df0) --- docs/download/_download.html | 40 ++++++++++++++++++------------------ styles.css | 9 ++++++-- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/docs/download/_download.html b/docs/download/_download.html index 6c6ffd69f8..f007da377d 100644 --- a/docs/download/_download.html +++ b/docs/download/_download.html @@ -74,11 +74,6 @@ } - window.tippy("a.checksum[data-tippy-content]", { - interactive: true, - placement: "top-end", - maxWidth: "none", - }); }) .catch((err) => { console.log(err); @@ -217,7 +212,18 @@ } const table = createTable(); - createHeadingRow(table, ["Platform", "Download", "Size", "SHA-256"]); + // Link the header to the release's checksums.txt so the full values + // stay reachable even where narrow screens truncate the hashes. + const checksumsAsset = assets.find((asset) => + asset.name.endsWith("-checksums.txt") + ); + let shaHeading = "SHA-256"; + if (checksumsAsset) { + shaHeading = window.document.createElement("a"); + shaHeading.href = checksumsAsset.download_url; + shaHeading.innerText = "SHA-256"; + } + createHeadingRow(table, ["Platform", "Download", "Size", shaHeading]); const tbody = table.createTBody(); assets.forEach((asset) => { @@ -228,11 +234,6 @@ } downloadTableContainer.append(table); - window.tippy(".checksum[data-tippy-content]", { - interactive: true, - placement: "top-end", - maxWidth: "none", - }); } function createTable() { @@ -245,12 +246,14 @@ const header = table.createTHead(); var row = header.insertRow(0); row.className = "header"; - let cellCount = 0; headings.forEach((heading) => { - const cell = (row.insertCell( - cellCount - ).outerHTML = `${heading}`); - cellCount = cellCount + 1; + const cell = window.document.createElement("th"); + if (heading instanceof window.Node) { + cell.appendChild(heading); + } else { + cell.innerText = heading; + } + row.appendChild(cell); }); } @@ -287,12 +290,9 @@ const checksumCell = row.insertCell(i++); if (asset.checksum) { - const checkSumSlice = asset.checksum.slice(0, 7); - const checksumEl = window.document.createElement("div"); checksumEl.className = "checksum font-monospace"; - checksumEl.setAttribute("data-tippy-content", asset.checksum); - checksumEl.innerText = checkSumSlice; + checksumEl.innerText = asset.checksum; checksumCell.appendChild(checksumEl); } } diff --git a/styles.css b/styles.css index bd02daf0db..c946f5b0a4 100644 --- a/styles.css +++ b/styles.css @@ -91,11 +91,16 @@ body.quarto-dark #quarto-header { margin-bottom: 0; } +/* The cell holds the full hash; only the rendering truncates (ellipsis). + Screen readers, copying, and find-in-page all see the complete value, + and the header links to checksums.txt for the full values. */ .download-table .checksum { - color: var(--bs-primary); font-size: .775em; - cursor: pointer; padding-top: 4px; + max-width: 9ch; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .download-button {