224 lines
7 KiB
JavaScript
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);
|