Browse Source

Fix grabber bug when task contained text not inside of an element

mj-deploy
Standa Lukeš 4 years ago
parent
commit
fd971c528f
  1. 48
      frontend/src/ksp-task-grabber.ts
  2. 4
      frontend/src/tests/example_assignments/31-3-3.html
  3. 4
      frontend/src/tests/grabber.test.ts

48
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 <hr>
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) {
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.") {
continue;
break processElement
}
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(),

4
frontend/src/tests/example_assignments/31-3-3.html

@ -48,4 +48,6 @@ ANO
</div>
<div class="clearfloat"></div>
<i>Poznámka:</i>
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&nbsp;cestě stojí střelec), ani levou věží (v&nbsp;cestě stojí jiné bílé figurky).

4
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 {