p2/js/quiz.js
2026-06-15 22:42:09 +02:00

224 lines
7 KiB
JavaScript

/* ===== Language detection ===== */
const LANG_OPTIONS = [
{ key: 'nl', label: 'Nederlands', flag: '🇳🇱', data: window.QUESTIONS_NL },
{ key: 'en', label: 'English', flag: '🇬🇧', data: window.QUESTIONS_EN },
].filter(l => l.data && l.data.length > 0);
let ALL_QUESTIONS = [];
/* ===== Quiz state ===== */
let sessionQ = [];
let currentIdx = 0;
let score = 0;
let wrongIds = [];
let selectedCount = 0;
let answered = false;
let timerInterval = null;
let elapsedSeconds = 0;
let answeredCount = 0;
/* ===== Helpers ===== */
function shuffle(arr) {
const a = [...arr];
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function fmtTime(s) {
return Math.floor(s / 60) + ':' + String(s % 60).padStart(2, '0');
}
function startTimer() {
stopTimer();
timerInterval = setInterval(() => { elapsedSeconds++; updateTimerDisplay(); }, 1000);
}
function stopTimer() {
if (timerInterval) { clearInterval(timerInterval); timerInterval = null; }
}
function updateTimerDisplay() {
const avg = answeredCount > 0 ? Math.round(elapsedSeconds / answeredCount) + 's' : '—';
document.getElementById('timer-display').textContent = fmtTime(elapsedSeconds) + ' | gem. ' + avg;
}
function showScreen(id) {
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
document.getElementById(id).classList.add('active');
}
function shuffleQuestion(q) {
const idx = [0, 1, 2, 3];
const si = shuffle(idx);
return {
exam: q.exam, qnum: q.qnum, q: q.q,
opts: si.map(i => q.opts[i]),
correct: si.indexOf(q.correct),
explanation: si.map(i => q.explanation[i]),
};
}
/* ===== Language screen ===== */
function initLangScreen() {
if (LANG_OPTIONS.length === 1) {
ALL_QUESTIONS = LANG_OPTIONS[0].data;
initCountButtons();
showScreen('start');
return;
}
const grid = document.getElementById('lang-grid');
grid.innerHTML = '';
LANG_OPTIONS.forEach(lang => {
const btn = document.createElement('button');
btn.className = 'lang-btn';
btn.innerHTML = '<span>' + lang.flag + '</span><span>' + lang.label + '</span>';
btn.onclick = () => {
ALL_QUESTIONS = lang.data;
initCountButtons();
showScreen('start');
};
grid.appendChild(btn);
});
showScreen('lang');
}
/* ===== Start screen ===== */
function initCountButtons() {
const counts = [5, 10, 20, 60, 9999];
const grid = document.getElementById('count-grid');
grid.innerHTML = '';
const total = ALL_QUESTIONS.length;
counts.forEach(n => {
const btn = document.createElement('button');
btn.className = 'count-btn';
const label = n === 9999 ? 'Alle ' + total : String(n);
btn.textContent = label;
btn.dataset.count = n;
const isDisabled = n !== 9999 && total < n;
btn.disabled = isDisabled;
btn.onclick = () => selectCount(n, btn);
grid.appendChild(btn);
});
document.getElementById('start-btn').disabled = true;
selectedCount = 0;
}
function selectCount(n, btn) {
selectedCount = Math.min(n, ALL_QUESTIONS.length);
document.querySelectorAll('.count-btn').forEach(b => b.classList.remove('selected'));
btn.classList.add('selected');
document.getElementById('start-btn').disabled = false;
}
function startQuiz() {
const pool = shuffle(ALL_QUESTIONS.map(shuffleQuestion));
sessionQ = pool.slice(0, selectedCount);
currentIdx = 0; score = 0; wrongIds = []; answered = false;
elapsedSeconds = 0; answeredCount = 0;
updateTimerDisplay();
showScreen('quiz');
renderQuestion();
}
/* ===== Quiz screen ===== */
function renderQuestion() {
answered = false;
const q = sessionQ[currentIdx];
const total = sessionQ.length;
document.getElementById('progress-fill').style.width = ((currentIdx / total) * 100) + '%';
document.getElementById('q-meta').textContent = 'Vraag ' + (currentIdx + 1) + ' van ' + total;
document.getElementById('q-text').textContent = q.q;
const optDiv = document.getElementById('options');
optDiv.innerHTML = '';
['A', 'B', 'C', 'D'].forEach((ltr, i) => {
const btn = document.createElement('button');
btn.className = 'option-btn';
btn.innerHTML = '<span class="opt-letter">' + ltr + '.</span><span>' + q.opts[i] + '</span>';
btn.onclick = () => handleAnswer(i);
optDiv.appendChild(btn);
});
document.getElementById('explanation').style.display = 'none';
document.getElementById('next-btn').style.display = 'none';
startTimer();
}
function handleAnswer(chosen) {
if (answered) return;
answered = true;
stopTimer();
answeredCount++;
updateTimerDisplay();
const q = sessionQ[currentIdx];
document.querySelectorAll('.option-btn').forEach((btn, i) => {
btn.disabled = true;
if (i === q.correct) btn.classList.add('correct');
else if (i === chosen && chosen !== q.correct) btn.classList.add('wrong');
});
if (chosen === q.correct) score++;
else wrongIds.push(currentIdx);
const expDiv = document.getElementById('explanation');
expDiv.style.display = 'block';
expDiv.innerHTML =
'<div class="explanation-source">Proefexamen ' + q.exam + ', vraag ' + q.qnum + '</div>' +
'<div class="explanation-label">Toelichting</div>' +
q.explanation.map(e => '<p>' + e + '</p>').join('');
const nextBtn = document.getElementById('next-btn');
nextBtn.style.display = 'inline-flex';
nextBtn.textContent = currentIdx === sessionQ.length - 1 ? 'Bekijk resultaat' : 'Volgende vraag →';
}
function nextQuestion() {
currentIdx++;
if (currentIdx >= sessionQ.length) showResult();
else renderQuestion();
}
/* ===== Result screen ===== */
function showResult() {
stopTimer();
showScreen('result');
const total = sessionQ.length;
const pct = Math.round((score / total) * 100);
const circle = document.getElementById('score-circle');
circle.innerHTML = pct + '%<span>' + (pct >= 60 ? 'Geslaagd' : 'Niet geslaagd') + '</span>';
circle.className = 'score-circle ' + (pct >= 60 ? 'score-pass' : 'score-fail');
document.getElementById('result-label').textContent = pct >= 60 ? 'Geslaagd' : 'Niet geslaagd';
document.getElementById('result-sub').textContent = score + ' van de ' + total + ' vragen goed';
document.getElementById('stat-correct').textContent = score;
document.getElementById('stat-wrong').textContent = total - score;
document.getElementById('stat-time').textContent =
answeredCount > 0 ? Math.round(elapsedSeconds / answeredCount) + 's' : '—';
document.getElementById('retry-btn').style.display = wrongIds.length > 0 ? 'inline-flex' : 'none';
}
function goStart() {
stopTimer();
document.querySelectorAll('.count-btn').forEach(b => b.classList.remove('selected'));
document.getElementById('start-btn').disabled = true;
selectedCount = 0;
showScreen('start');
}
function retryWrong() {
sessionQ = shuffle(wrongIds.map(i => shuffleQuestion(sessionQ[i])));
currentIdx = 0; score = 0; wrongIds = []; answered = false;
elapsedSeconds = 0; answeredCount = 0;
updateTimerDisplay();
showScreen('quiz');
renderQuestion();
}
/* ===== Boot ===== */
document.addEventListener('DOMContentLoaded', initLangScreen);