Skip to content

Frontend polish: CDN-failure resilience, link safety, a11y, UX fixes - #5

Open
LukasWallrich wants to merge 3 commits into
mainfrom
audit/frontend-polish
Open

Frontend polish: CDN-failure resilience, link safety, a11y, UX fixes#5
LukasWallrich wants to merge 3 commits into
mainfrom
audit/frontend-polish

Conversation

@LukasWallrich

Copy link
Copy Markdown
Contributor

Part of a repo audit. Frontend-only changes (no build step; verified with node --check and element-ID cross-checks):

  • CDN-failure resilience: every new Chart / Plotly render entry point is now guarded — if a chart library fails to load (ad-blocker, offline), the affected chart shows an inline "Chart unavailable" message instead of an uncaught error that previously aborted table/FAQ/data-stamp initialization for the whole page.
  • FAQ link scheme allow-list: markdown links from the remote FAQ file only become anchors for http:/https:/mailto:; other schemes (e.g. javascript:) render as plain text.
  • rel="noopener noreferrer" added to all 24 target="_blank" anchors in index.html (JS-generated links already had it).
  • Citation modal keyboard access: Escape closes it; focus moves to the close button on open and returns to the trigger on close.
  • Repo-casing normalized to forrtproject/fred-data (GitHub's canonical full_name) — two URLs used FReD-data while a third used lowercase.
  • Citation Impact loading state: a "Loading…" placeholder shows immediately on init instead of a blank panel until three fetches resolve.
  • Unbiased shuffle: Random Examples now uses Fisher–Yates instead of sort(() => Math.random() - 0.5).
  • Dead schema fields removed: effect_o/effect_r/n_o/n_r/description never exist in flora.csv and could never render.

Deliberately does not touch the Mean Citedness sections of app.js — those are fixed in #4.

🤖 Generated with Claude Code

LukasWallrich and others added 2 commits July 18, 2026 23:52
- Guard every Chart.js / Plotly render entry point (typeof check) so a
  blocked CDN degrades individual charts to an inline message instead of
  throwing an uncaught ReferenceError that aborts the rest of loadData
  (tables, FAQ, data stamps). Adds shared chartLibMissing() helper.
- FAQ markdown links: allow only http/https/mailto schemes (case-insensitive,
  trimmed); other schemes (e.g. javascript:) render as plain text.
- index.html: add rel="noopener noreferrer" to all 24 target="_blank" anchors.
- Citation Impact modal: close on Escape; move focus to the close button on
  open and restore it to the trigger on close.
- Normalize GitHub repo casing to canonical lowercase forrtproject/fred-data
  (REMOTE_CSV_URL, CITATION_URL) to match FAQ_URL.
- Citation Impact: show an immediate "Loading…" state on init, cleared on
  success, consistent with mc-loading/ao-loading.
- Random Examples: replace biased sort(() => Math.random() - 0.5) with an
  unbiased Fisher–Yates shuffle.
- Remove dead schema references (effect_o/effect_r/n_o/n_r/description) not
  present in flora.csv from formatDetailRow and bmSearchableText.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…load

- The FAQ link allow-list now requires the whole trimmed URL to start
  with http:, https:, or mailto:, closing the control-character-prefix
  bypass and excluding protocol-relative/relative URLs.
- Chart guards no longer declare CDN failure while the page is still
  loading: app.js runs before the chart libraries, so a fast cached
  data fetch could hit a guard while Chart.js was mid-download,
  permanently replacing a healthy chart. Before window load, guards now
  defer one retry to the load event; after load, a missing library is a
  real failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@LukasWallrich

Copy link
Copy Markdown
Contributor Author

Codex review (gpt, read-only): REQUEST_CHANGES — two high findings, both addressed in 518cbbf:

  1. High — scheme allow-list bypassable with a leading C0 control character (browsers strip them, exposing javascript:), and protocol-relative/relative URLs slipped through a scheme-only check. ✅ Fixed: the whole trimmed URL must now start with http:, https:, or mailto:; everything else renders as plain text. Unit-tested against the bypass cases.
  2. High — the CDN guard could permanently replace healthy charts: app.js intentionally runs before the chart libraries, and a fast cached data fetch can resolve while Chart.js is still downloading, so a guard could fire during normal load with no re-render afterward (and a later theme re-render would then throw on the removed canvas). ✅ Fixed: before the window load event, guards defer one retry to load instead of declaring failure; after load, a missing library is treated as a genuine CDN failure.

Codex verified the rest cleanly: chartLibMissing global visibility to citation-impact.js, modal Escape/focus logic (no leaks or double registration), loading placeholders replaced on both success and failure paths, all 24 target="_blank" anchors covered, dead-field removal behavior-neutral, and lowercase repo paths valid (GitHub paths are case-insensitive).

Codex re-check: the five trend-chart guards each registered their own
load listener calling renderAllTrends. Retries are now deduped by
function identity, with a shared retryAllTrends for the trend charts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@LukasWallrich

Copy link
Copy Markdown
Contributor Author

Codex re-verified the fix commit: URL validation sound, retry closures and load timing correct. One residual nit — the five trend-chart guards could each queue their own renderAllTrends retry before window load — fixed by deduping retries by function identity. Codex confirmed the rest of the fixes clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant