From 5f5e92e05672c8a985c98a9d062b4a122a714912 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 27 Sep 2026 19:13:03 -0700 Subject: Link previews: the common named entities decode too (an – showed raw in a card). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D --- names/preview.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/names/preview.js b/names/preview.js index 25051d9..b9af975 100644 --- a/names/preview.js +++ b/names/preview.js @@ -45,10 +45,12 @@ async function publicUrl(str) { return u; } +const ENTITIES = { amp: '&', quot: '"', apos: "'", lt: '<', gt: '>', nbsp: ' ', ndash: '–', mdash: '—', hellip: '…', + lsquo: '‘', rsquo: '’', ldquo: '“', rdquo: '”', laquo: '«', raquo: '»', copy: '©', reg: '®', trade: '™', middot: '·', bull: '•', euro: '€', pound: '£' }; const decodeEntities = (s) => String(s || '') - .replace(/&#x([0-9a-f]+);/gi, (_, h) => String.fromCodePoint(parseInt(h, 16))) - .replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(Number(d))) - .replace(/&(amp|quot|apos|lt|gt|nbsp);/g, (_, e) => ({ amp: '&', quot: '"', apos: "'", lt: '<', gt: '>', nbsp: ' ' })[e]); + .replace(/&#x([0-9a-f]+);/gi, (_, h) => { try { return String.fromCodePoint(parseInt(h, 16)); } catch { return ''; } }) + .replace(/&#(\d+);/g, (_, d) => { try { return String.fromCodePoint(Number(d)); } catch { return ''; } }) + .replace(/&([a-z]+);/gi, (m, e) => ENTITIES[e.toLowerCase()] ?? m); const tidy = (s, max) => decodeEntities(s).replace(/\s+/g, ' ').trim().slice(0, max); // Every in the head, whichever way its attributes are ordered. -- cgit v1.2.3