[Story] Reading list page #11
+3
-1
@@ -64,9 +64,11 @@ function renderEntry(entry) {
|
||||
const note = entry.note
|
||||
? `<p class="reading-note">${escapeHtml(entry.note)}</p>`
|
||||
: "";
|
||||
// Every reading link points at an external http(s) URL (isValidUrl), so it
|
||||
// carries rel="noopener noreferrer" as a hardening best practice.
|
||||
return (
|
||||
`<li class="reading-entry">` +
|
||||
`<a class="reading-link" href="${escapeHtml(entry.url)}">${escapeHtml(entry.title)}</a>` +
|
||||
`<a class="reading-link" href="${escapeHtml(entry.url)}" rel="noopener noreferrer">${escapeHtml(entry.title)}</a>` +
|
||||
note +
|
||||
`</li>`
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ const indexHtml = readFileSync(join(root, "index.html"), "utf8");
|
||||
const contactHtml = readFileSync(join(root, "contact.html"), "utf8");
|
||||
const rendererSource = readFileSync(join(root, "js/reading-list.js"), "utf8");
|
||||
|
||||
const ANCHOR_RE = /<a class="reading-link" href="([^"]*)">([^<]*)<\/a>/g;
|
||||
const ANCHOR_RE = /<a class="reading-link" href="([^"]*)"[^>]*>([^<]*)<\/a>/g;
|
||||
const ENTRY_LI_RE = /<li class="reading-entry">/g;
|
||||
const SECTION_RE = /<section class="reading-category"/g;
|
||||
|
||||
@@ -152,6 +152,14 @@ test("each rendered link has a valid href and shows its title, with the note sho
|
||||
);
|
||||
}
|
||||
|
||||
// All reading links point at external sites, so each carries the
|
||||
// rel="noopener noreferrer" hardening attribute.
|
||||
assert.equal(
|
||||
(html.match(/rel="noopener noreferrer"/g) || []).length,
|
||||
anchors.length,
|
||||
"every rendered link carries rel=\"noopener noreferrer\""
|
||||
);
|
||||
|
||||
assert.ok(html.includes("One line of context."), "note is rendered when present");
|
||||
assert.equal(
|
||||
(html.match(/<p class="reading-note">/g) || []).length,
|
||||
|
||||
Reference in New Issue
Block a user