Skip to content

Commit 45972da

Browse files
refactor: extract result page JS
1 parent 7257448 commit 45972da

3 files changed

Lines changed: 200 additions & 176 deletions

File tree

website/result-page.js

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
function normalizeModuleSlug(text) {
2+
return text
3+
.replaceAll(" ", "-")
4+
.replaceAll("&", "")
5+
.replaceAll("/", "");
6+
}
7+
8+
function parseModuleHeadingText(line) {
9+
const linkedHeadingMatch = line.match(
10+
/^###\s+\[([^\]]+)\]\([^)]*\)\s*$/u
11+
);
12+
if (linkedHeadingMatch) {
13+
return linkedHeadingMatch[1];
14+
}
15+
16+
const plainHeadingMatch = line.match(/^###\s+(.+)$/u);
17+
return plainHeadingMatch ? plainHeadingMatch[1].trim() : "";
18+
}
19+
20+
function extractGeneralNotesMarkdown(lines) {
21+
const startIndex = lines.findIndex(
22+
line => line.trim() === "## General notes"
23+
);
24+
if (startIndex === -1) {
25+
return [];
26+
}
27+
28+
const notes = [];
29+
for (let lineIndex = startIndex + 1; lineIndex < lines.length; lineIndex += 1) {
30+
if (/^##\s+/u.test(lines[lineIndex])) {
31+
break;
32+
}
33+
notes.push(lines[lineIndex]);
34+
}
35+
36+
return notes;
37+
}
38+
39+
function extractModuleSectionMarkdown(lines, moduleSlug) {
40+
let startIndex = -1;
41+
42+
for (const [lineIndex, line] of lines.entries()) {
43+
if (line.startsWith("### ")) {
44+
const headingText = parseModuleHeadingText(line);
45+
if (normalizeModuleSlug(headingText) === moduleSlug) {
46+
startIndex = lineIndex;
47+
break;
48+
}
49+
}
50+
}
51+
52+
if (startIndex === -1) {
53+
return null;
54+
}
55+
56+
let endIndex = lines.length;
57+
for (let lineIndex = startIndex + 1; lineIndex < lines.length; lineIndex += 1) {
58+
if (lines[lineIndex].startsWith("### ")) {
59+
endIndex = lineIndex;
60+
break;
61+
}
62+
}
63+
64+
return {
65+
bodyLines: lines.slice(startIndex + 1, endIndex),
66+
headingLine: lines[startIndex],
67+
title: parseModuleHeadingText(lines[startIndex])
68+
};
69+
}
70+
71+
function buildFilteredModuleMarkdown(markdownText, moduleSlug) {
72+
const lines = markdownText.split("\n");
73+
const moduleSection = extractModuleSectionMarkdown(lines, moduleSlug);
74+
if (!moduleSection) {
75+
return null;
76+
}
77+
78+
const generalNotes = extractGeneralNotesMarkdown(lines);
79+
const moduleHeadingLine = moduleSection.headingLine.replace(/^###\s+/u, "## ");
80+
const outputLines = [moduleHeadingLine, ""];
81+
82+
if (generalNotes.length > 0) {
83+
outputLines.push("### General notes", "", ...generalNotes, "");
84+
}
85+
86+
outputLines.push("### Findings", "", ...moduleSection.bodyLines);
87+
88+
return {
89+
markdown: outputLines.join("\n").trim(),
90+
title: moduleSection.title
91+
};
92+
}
93+
94+
function setPageTitle(title) {
95+
document.title = `${title} · Module hints`;
96+
}
97+
98+
async function loadAndDisplayMarkdown() {
99+
const markdownContainer = document.getElementById("markdown-container");
100+
const markdownFile = "result.md";
101+
const moduleSlug = new URLSearchParams(window.location.search).get(
102+
"module"
103+
);
104+
const fullResultsLink = document.getElementById("full-results-link");
105+
const markedParser = window.marked?.parse;
106+
107+
if (typeof markedParser !== "function") {
108+
throw new Error("Marked parser is not available");
109+
}
110+
111+
if (!moduleSlug) {
112+
fullResultsLink.remove();
113+
}
114+
115+
try {
116+
const response = await fetch(markdownFile);
117+
if (!response.ok) {
118+
throw new Error(
119+
`Error fetching the markdown file: ${response.statusText}`
120+
);
121+
}
122+
const markdownText = await response.text();
123+
124+
if (moduleSlug) {
125+
const filtered = buildFilteredModuleMarkdown(
126+
markdownText,
127+
moduleSlug
128+
);
129+
if (filtered) {
130+
markdownContainer.innerHTML = markedParser(filtered.markdown);
131+
setPageTitle(filtered.title);
132+
fullResultsLink.href = "result.html";
133+
fullResultsLink.textContent = "Full hints list";
134+
}
135+
else {
136+
markdownContainer.innerHTML
137+
= "<p>No hints found for this module.</p>";
138+
setPageTitle("Module hints");
139+
fullResultsLink.href = "result.html";
140+
fullResultsLink.textContent = "Full hints list";
141+
}
142+
}
143+
else {
144+
markdownContainer.innerHTML = markedParser(markdownText);
145+
}
146+
147+
addHeadingAnchors();
148+
}
149+
catch (error) {
150+
console.error("Error loading markdown:", error);
151+
markdownContainer.innerHTML
152+
= "<p>Error loading markdown content.</p>";
153+
}
154+
}
155+
156+
function addHeadingAnchors() {
157+
const markdownContainer = document.getElementById("markdown-container");
158+
const headings = markdownContainer.querySelectorAll("h1, h2, h3, h4");
159+
headings.forEach((heading) => {
160+
const anchorId = normalizeModuleSlug(heading.textContent);
161+
const anchor = document.createElement("a");
162+
anchor.id = anchorId;
163+
anchor.href = `#${anchorId}`;
164+
anchor.classList.add("heading-anchor");
165+
anchor.textContent = "#";
166+
heading.appendChild(anchor);
167+
});
168+
169+
const hash = window.location.hash;
170+
if (hash) {
171+
const decodedHash = decodeURIComponent(hash);
172+
const targetId = decodedHash.startsWith("#")
173+
? decodedHash.slice(1)
174+
: decodedHash;
175+
const target = document.getElementById(targetId);
176+
if (target) {
177+
target.scrollIntoView();
178+
}
179+
}
180+
}
181+
182+
window.onload = loadAndDisplayMarkdown;

website/result.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,23 @@ h3 > a {
103103
color: var(--color-link);
104104
}
105105

106+
h2 {
107+
margin: 1.2rem 0 0.4rem;
108+
font-size: 1.85rem;
109+
line-height: 1.2;
110+
}
111+
112+
h3 {
113+
margin: 1rem 0 0.35rem;
114+
font-size: 1.25rem;
115+
line-height: 1.25;
116+
}
117+
118+
h2 > a,
119+
h3 > a {
120+
color: var(--color-link);
121+
}
122+
106123
a:hover {
107124
text-decoration: underline;
108125
}

website/result.html

Lines changed: 1 addition & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -30,181 +30,6 @@
3030
<main id="page-content">
3131
<div id="markdown-container"></div>
3232
</main>
33-
<script>
34-
function normalizeModuleSlug(text) {
35-
return text
36-
.replaceAll(" ", "-")
37-
.replaceAll("&", "")
38-
.replaceAll("/", "");
39-
}
40-
41-
function parseModuleHeadingText(line) {
42-
const linkedHeadingMatch = line.match(
43-
/^###\s+\[([^\]]+)\]\([^)]*\)\s*$/u
44-
);
45-
if (linkedHeadingMatch) {
46-
return linkedHeadingMatch[1];
47-
}
48-
49-
const plainHeadingMatch = line.match(/^###\s+(.+)$/u);
50-
return plainHeadingMatch ? plainHeadingMatch[1].trim() : "";
51-
}
52-
53-
function extractGeneralNotesMarkdown(lines) {
54-
const startIndex = lines.findIndex(
55-
(line) => line.trim() === "## General notes"
56-
);
57-
if (startIndex === -1) {
58-
return [];
59-
}
60-
61-
const notes = [];
62-
for (let i = startIndex + 1; i < lines.length; i++) {
63-
if (/^##\s+/u.test(lines[i])) {
64-
break;
65-
}
66-
notes.push(lines[i]);
67-
}
68-
69-
return notes;
70-
}
71-
72-
function extractModuleSectionMarkdown(lines, moduleSlug) {
73-
let startIndex = -1;
74-
75-
for (let i = 0; i < lines.length; i++) {
76-
if (!lines[i].startsWith("### ")) {
77-
continue;
78-
}
79-
80-
const headingText = parseModuleHeadingText(lines[i]);
81-
if (normalizeModuleSlug(headingText) === moduleSlug) {
82-
startIndex = i;
83-
break;
84-
}
85-
}
86-
87-
if (startIndex === -1) {
88-
return null;
89-
}
90-
91-
let endIndex = lines.length;
92-
for (let i = startIndex + 1; i < lines.length; i++) {
93-
if (lines[i].startsWith("### ")) {
94-
endIndex = i;
95-
break;
96-
}
97-
}
98-
99-
return {
100-
bodyLines: lines.slice(startIndex + 1, endIndex),
101-
title: parseModuleHeadingText(lines[startIndex])
102-
};
103-
}
104-
105-
function buildFilteredModuleMarkdown(markdownText, moduleSlug) {
106-
const lines = markdownText.split("\n");
107-
const moduleSection = extractModuleSectionMarkdown(lines, moduleSlug);
108-
if (!moduleSection) {
109-
return null;
110-
}
111-
112-
const generalNotes = extractGeneralNotesMarkdown(lines);
113-
const outputLines = [];
114-
115-
if (generalNotes.length > 0) {
116-
outputLines.push("## General notes", "", ...generalNotes, "");
117-
}
118-
119-
outputLines.push("## Findings", "", ...moduleSection.bodyLines);
120-
121-
return {
122-
markdown: outputLines.join("\n").trim(),
123-
title: moduleSection.title
124-
};
125-
}
126-
127-
function setPageTitle(title) {
128-
document.title = `${title} · Module hints`;
129-
}
130-
131-
async function loadAndDisplayMarkdown() {
132-
const markdownContainer = document.getElementById("markdown-container");
133-
const markdownFile = "result.md";
134-
const moduleSlug = new URLSearchParams(window.location.search).get(
135-
"module"
136-
);
137-
const fullResultsLink = document.getElementById("full-results-link");
138-
139-
if (!moduleSlug) {
140-
fullResultsLink.remove();
141-
}
142-
143-
try {
144-
const response = await fetch(markdownFile);
145-
if (!response.ok) {
146-
throw new Error(
147-
`Error fetching the markdown file: ${response.statusText}`
148-
);
149-
}
150-
const markdownText = await response.text();
151-
152-
if (moduleSlug) {
153-
const filtered = buildFilteredModuleMarkdown(
154-
markdownText,
155-
moduleSlug
156-
);
157-
if (!filtered) {
158-
markdownContainer.innerHTML =
159-
"<p>No hints found for this module.</p>";
160-
setPageTitle("Module hints");
161-
fullResultsLink.href = "result.html";
162-
fullResultsLink.textContent = "Full hints list";
163-
} else {
164-
markdownContainer.innerHTML = marked.parse(filtered.markdown);
165-
setPageTitle(filtered.title);
166-
fullResultsLink.href = "result.html";
167-
fullResultsLink.textContent = "Full hints list";
168-
}
169-
} else {
170-
markdownContainer.innerHTML = marked.parse(markdownText);
171-
}
172-
173-
addHeadingAnchors();
174-
} catch (error) {
175-
console.error("Error loading markdown:", error);
176-
markdownContainer.innerHTML =
177-
"<p>Error loading markdown content.</p>";
178-
}
179-
}
180-
181-
function addHeadingAnchors() {
182-
const markdownContainer = document.getElementById("markdown-container");
183-
const headings = markdownContainer.querySelectorAll("h1, h2, h3, h4");
184-
headings.forEach((heading) => {
185-
const anchorId = normalizeModuleSlug(heading.textContent);
186-
const anchor = document.createElement("a");
187-
anchor.id = anchorId;
188-
anchor.href = `#${anchorId}`;
189-
anchor.classList.add("heading-anchor");
190-
anchor.textContent = "#";
191-
heading.appendChild(anchor);
192-
});
193-
194-
const hash = window.location.hash;
195-
if (hash) {
196-
const decodedHash = decodeURIComponent(hash);
197-
const targetId = decodedHash.startsWith("#")
198-
? decodedHash.slice(1)
199-
: decodedHash;
200-
const target = document.getElementById(targetId);
201-
if (target) {
202-
target.scrollIntoView();
203-
}
204-
}
205-
}
206-
207-
window.onload = loadAndDisplayMarkdown;
208-
</script>
33+
<script src="result-page.js?v=__ASSET_VERSION__"></script>
20934
</body>
21035
</html>

0 commit comments

Comments
 (0)