// ===================================================== // Quiz — multiple choice per hovedtema med sub-temaer // ===================================================== let quizData = null; let quizState = { category: 'all', subtopic: 'all', questions: [], current: 0, selected: null, answered: false, correct: 0, wrong: 0, perSubtopic: {}, // subtopic -> {correct, total} finished: false }; async function quizLoad() { if (quizData) return quizData; try { const res = await fetch('data/quiz.json'); quizData = await res.json(); } catch (e) { console.error('Klarte ikke laste quiz:', e); quizData = []; } return quizData; } function quizCategoryLabel(cat) { return { etikk: 'Etikk', baerekraft: 'Bærekraft', samfunn: 'Samfunnsansvar', verktoy: 'Verktøy & implementering', all: 'Alt pensum' }[cat] || cat; } function categoryQuestions(cat) { if (cat === 'all') return quizData; return quizData.filter(q => q.category === cat); } function subtopicsForCategory(cat) { const qs = categoryQuestions(cat); const counts = new Map(); qs.forEach(q => { const sub = q.subtopic || 'Tverrgående'; counts.set(sub, (counts.get(sub) || 0) + 1); }); return [...counts.entries()].sort((a, b) => b[1] - a[1]); } function quizFilter(cat, subtopic) { const base = categoryQuestions(cat); if (!subtopic || subtopic === 'all') return base; return base.filter(q => (q.subtopic || 'Tverrgående') === subtopic); } function quizShuffle(arr) { arr = [...arr]; for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; } return arr; } // ============= Start page (4 main parts) ============= function quizRenderStart() { const stage = document.getElementById('quizStage'); const counts = { all: quizData.length, etikk: categoryQuestions('etikk').length, baerekraft: categoryQuestions('baerekraft').length, samfunn: categoryQuestions('samfunn').length, verktoy: categoryQuestions('verktoy').length }; const cardFor = (cat, label, eyebrow, romanNum, themeClass) => { const subs = subtopicsForCategory(cat); const chips = subs.slice(0, 4).map(([name]) => `${name}`).join(''); const more = subs.length > 4 ? `+${subs.length - 4} til` : ''; return ` `; }; stage.innerHTML = `
Studiemodus

Multiple choice

${counts.all} spørsmål · 4 hovedtemaer · filter på deltema
${cardFor('etikk', 'Etikk', 'Oppgave I', 'I', 'theme-card--etikk')} ${cardFor('baerekraft', 'Bærekraft', 'Oppgave II', 'II', 'theme-card--baerekraft')} ${cardFor('samfunn', 'Samfunnsansvar', 'Oppgave III', 'III', 'theme-card--samfunn')} ${cardFor('verktoy', 'Verktøy & impl.', 'Oppgave IV · Case', 'IV', 'theme-card--verktoy')}
`; stage.querySelectorAll('[data-cat]').forEach(btn => { btn.addEventListener('click', () => { const cat = btn.dataset.cat; if (cat === 'all') { quizBegin(cat, 'all'); } else { quizRenderCategoryHub(cat); } }); }); } // ============= Sub-topic hub for a category ============= function quizRenderCategoryHub(cat) { const stage = document.getElementById('quizStage'); const subs = subtopicsForCategory(cat); const total = categoryQuestions(cat).length; const themeClass = `theme-card--${cat}`; const themeColors = SMF.THEME_COLORS[cat]; stage.innerHTML = `
Multiple choice

${quizCategoryLabel(cat)}

${total} spørsmål totalt ${subs.length} deltemaer

Velg deltema

${subs.map(([name, count]) => ` `).join('')}
`; stage.querySelectorAll('[data-sub]').forEach(btn => { btn.addEventListener('click', () => { quizBegin(cat, btn.dataset.sub); }); }); document.getElementById('quizBack').addEventListener('click', quizRenderStart); } // ============= Begin a quiz ============= function quizBegin(cat, sub) { quizState.category = cat; quizState.subtopic = sub; quizState.questions = quizShuffle(quizFilter(cat, sub)); quizState.current = 0; quizState.selected = null; quizState.answered = false; quizState.correct = 0; quizState.wrong = 0; quizState.perSubtopic = {}; quizState.finished = false; quizRenderCurrent(); } function quizRenderCurrent() { const stage = document.getElementById('quizStage'); if (quizState.finished) return quizRenderResult(); const total = quizState.questions.length; const q = quizState.questions[quizState.current]; if (!q) return; const progress = (quizState.current / total) * 100; const letters = ['A', 'B', 'C', 'D', 'E']; const themeColors = quizState.category === 'all' ? SMF.THEME_COLORS[q.category] : SMF.THEME_COLORS[quizState.category]; const subLabel = q.subtopic || 'Tverrgående'; stage.innerHTML = `
${quizState.current + 1} / ${total} ${quizCategoryLabel(q.category)} · ${subLabel} Riktig: ${quizState.correct}

${q.question}

${q.options.map((opt, i) => ` `).join('')}
`; stage.querySelectorAll('.quiz-option').forEach(opt => { opt.addEventListener('click', () => { if (quizState.answered) return; quizSelect(parseInt(opt.dataset.i, 10)); }); }); document.getElementById('quizNext').addEventListener('click', quizAdvance); document.getElementById('quizCancel').addEventListener('click', () => { if (confirm('Avslutte testen?')) quizRenderStart(); }); } function quizSelect(i) { const q = quizState.questions[quizState.current]; quizState.selected = i; quizState.answered = true; const opts = document.querySelectorAll('.quiz-option'); opts.forEach((opt, idx) => { opt.classList.add('quiz-option--disabled'); if (idx === q.correct) opt.classList.add('quiz-option--correct'); if (idx === i && i !== q.correct) opt.classList.add('quiz-option--wrong'); if (idx === i) opt.classList.add('quiz-option--selected'); }); const sub = q.subtopic || 'Tverrgående'; if (!quizState.perSubtopic[sub]) quizState.perSubtopic[sub] = { correct: 0, total: 0 }; quizState.perSubtopic[sub].total++; if (i === q.correct) { quizState.correct++; quizState.perSubtopic[sub].correct++; } else { quizState.wrong++; } const exp = document.getElementById('quizExplanation'); exp.innerHTML = `
${i === q.correct ? 'Riktig — ' : 'Forklaring — '}
${q.explanation}
`; document.getElementById('quizNext').disabled = false; } function quizAdvance() { quizState.current++; quizState.selected = null; quizState.answered = false; if (quizState.current >= quizState.questions.length) { quizState.finished = true; } quizRenderCurrent(); } function quizRenderResult() { const stage = document.getElementById('quizStage'); const total = quizState.questions.length; const pct = total ? Math.round((quizState.correct / total) * 100) : 0; let verdict, vColor; if (pct >= 90) { verdict = 'Fremragende.'; vColor = 'var(--theme-baerekraft)'; } else if (pct >= 80) { verdict = 'Meget god.'; vColor = 'var(--theme-baerekraft)'; } else if (pct >= 65) { verdict = 'Solid forståelse.'; vColor = 'var(--theme-samfunn)'; } else if (pct >= 50) { verdict = 'Greit, men trener videre.'; vColor = 'var(--theme-samfunn)'; } else { verdict = 'Repeter mer av dette temaet.'; vColor = 'var(--theme-etikk)'; } // Per-subtopic breakdown const subRows = Object.entries(quizState.perSubtopic) .sort((a, b) => b[1].total - a[1].total) .map(([name, { correct, total }]) => { const p = total ? Math.round((correct / total) * 100) : 0; const barColor = p >= 70 ? 'var(--theme-baerekraft)' : p >= 50 ? 'var(--theme-samfunn)' : 'var(--theme-etikk)'; return `
${name}
${correct}/${total}
`; }).join(''); stage.innerHTML = `
${quizState.correct}/${total}
${pct} % riktig
${verdict}
${subRows ? `
Fordelt på deltema
${subRows}
` : ''}
`; document.getElementById('quizRestart').addEventListener('click', () => quizBegin(quizState.category, quizState.subtopic)); document.getElementById('quizMore').addEventListener('click', () => quizRenderStart()); } function quizKeyboard(e) { if (location.hash !== '#/quiz') { document.removeEventListener('keydown', quizKeyboard); return; } const tag = document.activeElement?.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA') return; // 1-4 to select option, Enter to advance, Esc to cancel if (!quizState.finished && quizState.questions.length > 0) { if (e.key === '1' || e.key === '2' || e.key === '3' || e.key === '4') { const idx = parseInt(e.key, 10) - 1; if (!quizState.answered) { const q = quizState.questions[quizState.current]; if (q && idx < q.options.length) { e.preventDefault(); quizSelect(idx); } } } else if ((e.key === 'Enter' || e.key === ' ') && quizState.answered) { e.preventDefault(); quizAdvance(); } } } async function quizInit() { await quizLoad(); quizRenderStart(); document.removeEventListener('keydown', quizKeyboard); document.addEventListener('keydown', quizKeyboard); } SMF.quizInit = quizInit;