diff --git a/assets/exam-simulator.js b/assets/exam-simulator.js index cfa677d..e207ccf 100644 --- a/assets/exam-simulator.js +++ b/assets/exam-simulator.js @@ -198,6 +198,7 @@ }); var remainingSeconds = computed(function () { if (!currentPart.value || currentPart.value.status !== "running") return 0; + if (currentPart.value.paused) return currentPart.value.pausedRemainingSeconds; return Math.max(0, Math.ceil((currentPart.value.deadline - now.value) / 1000)); }); var formattedTime = computed(function () { @@ -286,6 +287,8 @@ code: code, status: "pending", deadline: null, + paused: false, + pausedRemainingSeconds: null, score: null, autoSubmitted: false, questions: picked.map(function (question) { @@ -297,9 +300,32 @@ function activatePart(part) { part.status = "running"; part.deadline = Date.now() + PART_DEFINITIONS[part.code].minutes * 60 * 1000; + part.paused = false; + part.pausedRemainingSeconds = null; now.value = Date.now(); } + function toggleTimer() { + var part = currentPart.value; + if (!part || part.status !== "running") return; + if (part.paused) { + part.deadline = Date.now() + part.pausedRemainingSeconds * 1000; + part.pausedRemainingSeconds = null; + part.paused = false; + now.value = Date.now(); + return; + } + + var seconds = remainingSeconds.value; + if (seconds <= 0) { + submitPart(true); + return; + } + part.pausedRemainingSeconds = seconds; + part.paused = true; + part.deadline = null; + } + function startExam(choice) { try { var parts = choice.parts.map(createPart); @@ -320,7 +346,7 @@ } function selectAnswer(questionIndex, answerIndex) { - if (currentPart.value.status !== "running") return; + if (currentPart.value.status !== "running" || currentPart.value.paused) return; var question = currentPart.value.questions[questionIndex]; if (question.selected === answerIndex) return; var firstAnswer = question.selected === null; @@ -372,6 +398,8 @@ currentPart.value.score = score; currentPart.value.status = "evaluated"; currentPart.value.deadline = null; + currentPart.value.paused = false; + currentPart.value.pausedRemainingSeconds = null; currentPart.value.autoSubmitted = Boolean(autoSubmitted); renderMathSoon(Vue); window.scrollTo({ top: 0, behavior: "smooth" }); @@ -494,9 +522,14 @@ clearStoredSession(); return; } + stored.session.parts.forEach(function (part) { + part.paused = Boolean(part.paused); + if (!part.paused) part.pausedRemainingSeconds = null; + }); session.value = stored.session; view.value = stored.view === "summary" ? "summary" : "exam"; if (session.value.parts[session.value.currentPart].status === "running" && + !session.value.parts[session.value.currentPart].paused && session.value.parts[session.value.currentPart].deadline <= Date.now()) { submitPart(true); } @@ -521,7 +554,8 @@ }); watch(remainingSeconds, function (seconds) { - if (session.value && currentPart.value && currentPart.value.status === "running" && seconds <= 0) submitPart(true); + if (session.value && currentPart.value && currentPart.value.status === "running" && + !currentPart.value.paused && seconds <= 0) submitPart(true); }); function loadCatalog() { @@ -595,6 +629,7 @@ answerLabels: ANSWER_LABELS, remainingSeconds: remainingSeconds, formattedTime: formattedTime, + toggleTimer: toggleTimer, answeredCount: answeredCount, hasNextPart: hasNextPart, isReviewing: isReviewing, diff --git a/src/build.py b/src/build.py index 0635a50..cbfba3a 100644 --- a/src/build.py +++ b/src/build.py @@ -160,7 +160,7 @@ class Build: page = self.__build_page( content, page_stylesheets=["assets/exam-simulator.css?ts=20260804"], - page_scripts=["assets/vue.global.prod.js", "assets/exam-simulator.js?ts=20260804"], + page_scripts=["assets/vue.global.prod.js", "assets/exam-simulator.js?ts=20260805"], ) with (self.config.p_build / "simulation.html").open("w", encoding="utf-8") as file: file.write(page) diff --git a/templates/html/exam-simulator.html b/templates/html/exam-simulator.html index 48f7e92..1d1f0f7 100644 --- a/templates/html/exam-simulator.html +++ b/templates/html/exam-simulator.html @@ -104,10 +104,16 @@ - - - + Abgegeben @@ -142,7 +148,8 @@