diff --git a/frontend/src/ksp-task-grabber.ts b/frontend/src/ksp-task-grabber.ts
index d436bd3..e0824e3 100644
--- a/frontend/src/ksp-task-grabber.ts
+++ b/frontend/src/ksp-task-grabber.ts
@@ -72,12 +72,17 @@ function getLocation(id: string, solution: boolean): TaskLocation {
}
}
+function htmlEncode(text: string): string {
+ const p = document.createElement("p")
+ p.textContent = text
+ return p.innerHTML
+}
+
function parseTask(startElementId: string, doc: HTMLDocument): TaskAssignmentData {
const titleElement = doc.getElementById(startElementId)
if (!titleElement)
throw new Error(`Document does not contain ${startElementId}`)
fixAllLinks(titleElement)
- const elements = []
let e = titleElement
@@ -90,37 +95,52 @@ function parseTask(startElementId: string, doc: HTMLDocument): TaskAssignmentDat
e = e.nextElementSibling as HTMLElement
+ // skip first
while (e.nextElementSibling &&
e.tagName.toLowerCase() == "hr")
e = e.nextElementSibling as HTMLElement
- while (!e.classList.contains("story") &&
- // !e.classList.contains("clearfloat") &&
- e.tagName.toLowerCase() != "h3" &&
- e.textContent!.trim() != "Řešení"
- )
- {
- elements.push(e)
- if (!e.nextElementSibling) break;
- e = e.nextElementSibling as HTMLElement
- }
// hack: remove img tag that shows this task is a practical one. Some tasks have it, some don't, so we remove it for consistency
- const intoImgTag = elements[0]?.firstElementChild
+ const intoImgTag = e.firstElementChild
if (intoImgTag && intoImgTag.tagName.toLowerCase() == "img" && intoImgTag.classList.contains("leftfloat")) {
intoImgTag.remove()
}
let r = ""
- for (const e of elements) {
- // hack: remove the paragraph with the matching text. Occurs in KSP-H, but is useless in this context.
- if (e.textContent!.trim().replace(/\s+/g, " ") == "Toto je praktická open-data úloha. V odevzdávacím systému si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.") {
- continue;
+
+ copyElements: while (!e.classList.contains("story") &&
+ // !e.classList.contains("clearfloat") &&
+ e.tagName.toLowerCase() != "h3" &&
+ e.textContent!.trim() != "Řešení"
+ ) {
+
+ processElement: {
+ // hack: remove the paragraph with the matching text. Occurs in KSP-H, but is useless in this context.
+ if (e.textContent!.trim().replace(/\s+/g, " ") == "Toto je praktická open-data úloha. V odevzdávacím systému si necháte vygenerovat vstupy a odevzdáte příslušné výstupy. Záleží jen na vás, jak výstupy vyrobíte.") {
+ break processElement
+ }
+
+ fixAllLinks(e)
+
+ r += e.outerHTML + "\n"
}
- fixAllLinks(e)
- r += e.outerHTML + "\n"
+ let n = e.nextSibling
+ copyNodes: while(true) {
+ if (!n) {
+ break copyElements
+ }
+ if (n.nodeType == Node.ELEMENT_NODE) {
+ e = n as HTMLElement
+ break copyNodes
+ } else if (n.nodeType == Node.TEXT_NODE && n.textContent!.trim() != "") {
+ r += htmlEncode(n.textContent!)
+ }
+ n = n.nextSibling
+ }
}
+
return {
description: r,
id: id.trim(),
diff --git a/frontend/src/tests/example_assignments/31-3-3.html b/frontend/src/tests/example_assignments/31-3-3.html
index bad1e26..3f676aa 100644
--- a/frontend/src/tests/example_assignments/31-3-3.html
+++ b/frontend/src/tests/example_assignments/31-3-3.html
@@ -48,4 +48,6 @@ ANO
Poznámka:
-BUG
+ Všimněte si, že stejnou černou figurkou (střelcem) můžeme vzít
+dva bílé pěšce. Naopak bílého pěšce vpravo nahoře nemůžeme vzít ani spodní věží
+(v cestě stojí střelec), ani levou věží (v cestě stojí jiné bílé figurky).
diff --git a/frontend/src/tests/grabber.test.ts b/frontend/src/tests/grabber.test.ts
index 663b0c0..8d128fc 100644
--- a/frontend/src/tests/grabber.test.ts
+++ b/frontend/src/tests/grabber.test.ts
@@ -81,7 +81,7 @@ describe('task assignment (exact match)', () => {
const assignmentFiles = readdirSync(assignmentDir)
for (const a of assignmentFiles) {
const [_, id] = /(.*?)\.html/.exec(a)!
- test(id, async () => {
+ test.concurrent(id, async () => {
const assignment = await g.grabAssignment(id)
const expected = readFileSync(resolve(assignmentDir, a)).toString()
try {
@@ -98,7 +98,7 @@ describe('task solution (exact match)', () => {
const assignmentFiles = readdirSync(assignmentDir)
for (const a of assignmentFiles) {
const [_, id] = /(.*?)\.html/.exec(a)!
- test(id, async () => {
+ test.concurrent(id, async () => {
const solution = await g.grabSolution(id)
const expected = readFileSync(resolve(assignmentDir, a)).toString()
try {