-
-
- 0 Fehler
-
+
+
+
+
+
+
+
+
Streak: 0
@@ -444,6 +473,30 @@
+
+
+
+
+
+
+
+
Klausur-Simulation (15 Fragen)
+
Kein Sofort-Feedback • Notenskala 1 bis 6
+
+
+
+
+
+
Verbleibende Zeit
+
10:00
+
+
+
+
+
@@ -456,8 +509,14 @@
Welches rhetorische Stilmittel liegt in diesem Zitat vor?
-
- „Die Kunst ist lang, und kurz ist unser Leben.“
+
+
+ „Die Kunst ist lang, und kurz ist unser Leben.“
+
+
+
@@ -466,6 +525,21 @@
+
+
+
+
+
+
+
+
+ Aktives Abrufen trainiert das Langzeitgedächtnis. Tippfehler werden automatisch toleriert!
+
+
+
+
+
+
+
+
+
+ Frage 1 von 15
+
+
+
+
+
+
+
+
+
+
+
+
+ Note: Sehr gut (1)
+
+
Prüfungsauswertung
+
+ Hervorragende Leistung! Du beherrschst die rhetorischen Stilmittel souverän.
+
+
+
+
+
+
+
Richtig gelöst
+
14 / 15
+
+
+
+
+
+
+
+
+
+ Klausur-Korrektur
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1518,12 +1669,17 @@
function updateQuizMistakesBadge() {
const badge = document.getElementById('quizMistakesBadge');
const countEl = document.getElementById('quizMistakesCount');
- if (!badge || !countEl) return;
- if (quizMistakes.length > 0) {
- badge.classList.remove('hidden');
- countEl.innerText = quizMistakes.length;
- } else {
- badge.classList.add('hidden');
+ if (badge && countEl) {
+ if (quizMistakes.length > 0) {
+ badge.classList.remove('hidden');
+ countEl.innerText = quizMistakes.length;
+ } else {
+ badge.classList.add('hidden');
+ }
+ }
+ const weakBtnCount = document.getElementById('quizWeakBtnCount');
+ if (weakBtnCount) {
+ weakBtnCount.innerText = quizMistakes.length;
}
}
@@ -1736,63 +1892,319 @@
}
}, { passive: true });
- // QUIZ ENGINE
+ // ==========================================
+ // AUDIO & WEB SPEECH SYNTHESIS
+ // ==========================================
+ function speakText(text, event) {
+ if (event) event.stopPropagation();
+ if (!('speechSynthesis' in window)) {
+ showToast('Sprachausgabe im Browser nicht verfügbar', 'fa-volume-xmark');
+ return;
+ }
+ try {
+ window.speechSynthesis.cancel();
+ // Remove surrounding quotes and context in brackets for fluid natural speech
+ let clean = text.replace(/„|“|"|'/g, '').replace(/\(.*?\)/g, '').trim();
+ if (!clean) return;
+ const utterance = new SpeechSynthesisUtterance(clean);
+ utterance.lang = 'de-DE';
+ utterance.rate = 0.95;
+ utterance.pitch = 1.0;
+ window.speechSynthesis.speak(utterance);
+ } catch (err) {
+ console.warn('SpeechSynthesis error:', err);
+ }
+ }
+
+ function speakCurrentQuizPhrase(event) {
+ if (currentQuizIndex < quizQuestions.length) {
+ const q = quizQuestions[currentQuizIndex];
+ speakText(q.example, event);
+ }
+ }
+
+ function speakCurrentCard(event) {
+ if (filteredCards.length > 0 && currentCardIndex < filteredCards.length) {
+ const item = filteredCards[currentCardIndex];
+ if (cardFaceMode === 'term' && !cardIsFlipped) {
+ speakText(item.term, event);
+ } else {
+ speakText(item.examples[0], event);
+ }
+ }
+ }
+
+ // ==========================================
+ // FUZZY MATCHER & LEVENSHTEIN DISTANCE
+ // ==========================================
+ function levenshteinDistance(s1, s2) {
+ if (!s1) return s2 ? s2.length : 0;
+ if (!s2) return s1.length;
+ if (s1.length < s2.length) return levenshteinDistance(s2, s1);
+
+ let prevRow = Array.from({ length: s2.length + 1 }, (_, i) => i);
+ for (let i = 0; i < s1.length; i++) {
+ let currRow = [i + 1];
+ for (let j = 0; j < s2.length; j++) {
+ let cost = s1[i] === s2[j] ? 0 : 1;
+ currRow.push(Math.min(
+ currRow[j] + 1, // Insertion
+ prevRow[j + 1] + 1, // Deletion
+ prevRow[j] + cost // Substitution
+ ));
+ }
+ prevRow = currRow;
+ }
+ return prevRow[s2.length];
+ }
+
+ function checkFuzzyMatch(userInput, targetTerm) {
+ if (!userInput) return { isMatch: false, exact: false, dist: 99 };
+ const normUser = userInput.toLowerCase().replace(/[^a-zäöüß0-9]/g, '');
+ const normTarget = targetTerm.toLowerCase().replace(/[^a-zäöüß0-9]/g, '');
+
+ if (normUser === normTarget) {
+ return { isMatch: true, exact: true, dist: 0 };
+ }
+
+ // Special aliases and dual terms
+ if (normTarget.includes('tautologie') || normTarget.includes('pleonasmus')) {
+ if (normUser === 'tautologie' || normUser === 'pleonasmus') {
+ return { isMatch: true, exact: true, dist: 0 };
+ }
+ }
+ if (normTarget.includes('parsprototo')) {
+ if (normUser === 'parsprototo' || normUser === 'synekdoche' || normUser === 'partsprototo') {
+ return { isMatch: true, exact: true, dist: 0 };
+ }
+ }
+
+ const dist = levenshteinDistance(normUser, normTarget);
+ const maxAllowed = normTarget.length > 7 ? 2 : (normTarget.length > 4 ? 1 : 0);
+
+ if (dist <= maxAllowed) {
+ return { isMatch: true, exact: false, dist: dist };
+ }
+ return { isMatch: false, exact: false, dist: dist };
+ }
+
+ // ==========================================
+ // NOTENSCHLÜSSEL & EXAM GRADING
+ // ==========================================
+ function calculateExamGrade(score, total) {
+ const percent = Math.round((score / total) * 100);
+ if (percent >= 90) {
+ return {
+ grade: 1,
+ name: "Sehr gut (1)",
+ points: "15 - 13 Notenpunkte",
+ badgeClass: "bg-emerald-100 text-emerald-900 border-emerald-300",
+ icon: "fa-crown",
+ iconColor: "text-amber-500",
+ feedback: "Ausgezeichnete Leistung! Du beherrschst die rhetorischen Stilmittel absolut souverän und bist bestens für jede Textanalyse gerüstet."
+ };
+ } else if (percent >= 80) {
+ return {
+ grade: 2,
+ name: "Gut (2)",
+ points: "12 - 10 Notenpunkte",
+ badgeClass: "bg-blue-100 text-blue-900 border-blue-300",
+ icon: "fa-star",
+ iconColor: "text-blue-500",
+ feedback: "Sehr gute Textanalyse-Kenntnisse mit nur minimalen Unsicherheiten. Wiederhole kurz die Verwechslungsfallen."
+ };
+ } else if (percent >= 65) {
+ return {
+ grade: 3,
+ name: "Befriedigend (3)",
+ points: "9 - 7 Notenpunkte",
+ badgeClass: "bg-amber-100 text-amber-900 border-amber-300",
+ icon: "fa-thumbs-up",
+ iconColor: "text-amber-600",
+ feedback: "Solides Grundlagenwissen. Ein gezieltes Schwachstellen-Training bringt dich sicher in den Bereich 'Gut'."
+ };
+ } else if (percent >= 50) {
+ return {
+ grade: 4,
+ name: "Ausreichend (4)",
+ points: "6 - 5 Notenpunkte",
+ badgeClass: "bg-orange-100 text-orange-900 border-orange-300",
+ icon: "fa-triangle-exclamation",
+ iconColor: "text-orange-500",
+ feedback: "Bestanden, aber mit spürbaren Lücken. Nutze die Karteikarten und das Glossar, um typische Fallen zu vermeiden."
+ };
+ } else if (percent >= 30) {
+ return {
+ grade: 5,
+ name: "Mangelhaft (5)",
+ points: "4 - 1 Notenpunkte",
+ badgeClass: "bg-rose-100 text-rose-900 border-rose-300",
+ icon: "fa-circle-xmark",
+ iconColor: "text-rose-500",
+ feedback: "Die Grundlagen sitzen noch nicht fest genug. Wiederhole systematisch den Kernstoff mit den Karteikarten."
+ };
+ } else {
+ return {
+ grade: 6,
+ name: "Ungenügend (6)",
+ points: "0 Notenpunkte",
+ badgeClass: "bg-slate-200 text-slate-900 border-slate-300",
+ icon: "fa-skull-crossbones",
+ iconColor: "text-slate-600",
+ feedback: "Nicht bestanden. Keine Panik: Starte am besten im Glossar und arbeite dich durch die 17 Kernstoff-Figuren."
+ };
+ }
+ }
+
+ // ==========================================
+ // QUIZ ENGINE (CHOICE, FREITEXT, EXAM & WEAKSPOTS)
+ // ==========================================
+ let currentQuizInputType = 'choice'; // 'choice' | 'text'
+ let examTimeRemaining = 600; // 10 minutes in seconds
+ let examTimerInterval = null;
+ let examStartTime = null;
+
+ function setQuizInputType(type) {
+ currentQuizInputType = type;
+ const choiceBtn = document.getElementById('quizInputChoiceBtn');
+ const textBtn = document.getElementById('quizInputTextBtn');
+
+ if (type === 'choice') {
+ choiceBtn.className = 'px-2.5 py-1.5 rounded-lg bg-white text-indigo-700 shadow-sm font-bold transition flex items-center gap-1';
+ textBtn.className = 'px-2.5 py-1.5 rounded-lg text-slate-600 hover:text-slate-900 transition font-semibold flex items-center gap-1';
+ } else {
+ textBtn.className = 'px-2.5 py-1.5 rounded-lg bg-white text-indigo-700 shadow-sm font-bold transition flex items-center gap-1';
+ choiceBtn.className = 'px-2.5 py-1.5 rounded-lg text-slate-600 hover:text-slate-900 transition font-semibold flex items-center gap-1';
+ }
+
+ renderQuizQuestion();
+ }
+
function startQuiz(mode = 'highlighted') {
currentQuizMode = mode;
let pool = [];
+ // Clear any running exam timer
+ if (examTimerInterval) {
+ clearInterval(examTimerInterval);
+ examTimerInterval = null;
+ }
+
// Update Quiz Mode buttons UI
const btnMap = {
'highlighted': 'quizModeKernBtn',
'all': 'quizModeAllBtn',
- 'zusatz': 'quizModeZusatzBtn'
+ 'zusatz': 'quizModeZusatzBtn',
+ 'weakspots': 'quizModeWeakBtn',
+ 'exam': 'quizModeExamBtn'
};
- ['quizModeKernBtn', 'quizModeAllBtn', 'quizModeZusatzBtn'].forEach(id => {
+
+ ['quizModeKernBtn', 'quizModeAllBtn', 'quizModeZusatzBtn', 'quizModeWeakBtn', 'quizModeExamBtn'].forEach(id => {
const b = document.getElementById(id);
- if (b) b.className = 'px-2.5 py-1.5 rounded-lg text-slate-600 hover:text-slate-900 transition font-semibold';
+ if (b) {
+ if (id === 'quizModeExamBtn') {
+ b.className = 'px-2.5 sm:px-3 py-1.5 rounded-lg bg-slate-200 text-slate-700 hover:bg-slate-300 transition font-bold flex items-center gap-1';
+ } else {
+ b.className = 'px-2.5 sm:px-3 py-1.5 rounded-lg text-slate-600 hover:text-slate-900 transition font-semibold';
+ }
+ }
});
+
const activeBtn = document.getElementById(btnMap[mode]);
if (activeBtn) {
- activeBtn.className = 'px-2.5 py-1.5 rounded-lg bg-white text-indigo-700 shadow-sm font-bold transition';
+ if (mode === 'exam') {
+ activeBtn.className = 'px-2.5 sm:px-3 py-1.5 rounded-lg bg-gradient-to-r from-amber-500 to-orange-500 text-white shadow font-extrabold transition flex items-center gap-1';
+ } else {
+ activeBtn.className = 'px-2.5 sm:px-3 py-1.5 rounded-lg bg-white text-indigo-700 shadow-sm font-bold transition';
+ }
}
- if (mode === 'weakspots' && quizMistakes.length > 0) {
- pool = STILMITTEL_DATA.filter(item => quizMistakes.includes(item.id));
- document.getElementById('quizModeName').innerText = `Schwachstellen-Training (${pool.length} Begriffe)`;
+ const timerBar = document.getElementById('examTimerBar');
+ const examNavBar = document.getElementById('examNavBar');
+ const scoreStatsContainer = document.getElementById('quizScoreStatsContainer');
+
+ if (mode === 'exam') {
+ pool = [...STILMITTEL_DATA];
+ document.getElementById('quizModeName').innerText = '⏱️ Klausursimulation (15 Fragen unter Zeitdruck)';
+ timerBar.classList.remove('hidden');
+ examNavBar.classList.remove('hidden');
+ scoreStatsContainer.classList.add('hidden');
+
+ // Start 10-minute timer
+ examTimeRemaining = 600;
+ examStartTime = Date.now();
+ updateExamTimerDisplay();
+ examTimerInterval = setInterval(handleExamTimerTick, 1000);
+ } else if (mode === 'weakspots') {
+ if (quizMistakes.length > 0) {
+ pool = STILMITTEL_DATA.filter(item => quizMistakes.includes(item.id));
+ } else {
+ pool = STILMITTEL_DATA.filter(item => (cardLevels[item.id] || 1) <= 2);
+ }
+ document.getElementById('quizModeName').innerText = `⚠️ Schwachstellen-Training (${pool.length} Begriffe)`;
+ timerBar.classList.add('hidden');
+ examNavBar.classList.add('hidden');
+ scoreStatsContainer.classList.remove('hidden');
} else if (mode === 'all') {
pool = [...STILMITTEL_DATA];
document.getElementById('quizModeName').innerText = 'Gesamt-Challenge (Alle 23 Stilmittel)';
+ timerBar.classList.add('hidden');
+ examNavBar.classList.add('hidden');
+ scoreStatsContainer.classList.remove('hidden');
} else if (mode === 'zusatz') {
pool = STILMITTEL_DATA.filter(item => !item.highlighted);
- document.getElementById('quizModeName').innerText = 'Zusatzinfo-Training (6 erweiterte Stilmittel)';
+ document.getElementById('quizModeName').innerText = '🔍 Zusatzinfo-Training (6 erweiterte Stilmittel)';
+ timerBar.classList.add('hidden');
+ examNavBar.classList.add('hidden');
+ scoreStatsContainer.classList.remove('hidden');
} else {
// Default: highlighted / Kernstoff (17)
currentQuizMode = 'highlighted';
pool = STILMITTEL_DATA.filter(item => item.highlighted);
document.getElementById('quizModeName').innerText = '🌟 Kernstoff-Challenge (17 Stilmittel)';
+ timerBar.classList.add('hidden');
+ examNavBar.classList.add('hidden');
+ scoreStatsContainer.classList.remove('hidden');
}
if (pool.length === 0) pool = [...STILMITTEL_DATA];
pool.sort(() => Math.random() - 0.5);
- const questionCount = Math.min(10, pool.length);
+ const questionCount = mode === 'exam' ? 15 : Math.min(10, pool.length);
quizQuestions = [];
for (let i = 0; i < questionCount; i++) {
- const correct = pool[i];
+ const correct = pool[i % pool.length];
const randomExample = correct.examples[Math.floor(Math.random() * correct.examples.length)];
- const distractors = STILMITTEL_DATA
- .filter(x => x.id !== correct.id)
- .sort(() => Math.random() - 0.5)
- .slice(0, 3);
+ // Smart distractors: prioritize confusable term if available
+ let potentialDistractors = STILMITTEL_DATA.filter(x => x.id !== correct.id);
+ let priorityDistractor = null;
+ if (correct.confusion && correct.confusion.trap) {
+ priorityDistractor = potentialDistractors.find(x => correct.confusion.trap.toLowerCase().includes(x.term.toLowerCase()));
+ }
+
+ let distractors = [];
+ if (priorityDistractor) {
+ distractors.push(priorityDistractor);
+ potentialDistractors = potentialDistractors.filter(x => x.id !== priorityDistractor.id);
+ }
+
+ potentialDistractors.sort(() => Math.random() - 0.5);
+ while (distractors.length < 3 && potentialDistractors.length > 0) {
+ distractors.push(potentialDistractors.pop());
+ }
const options = [correct, ...distractors].sort(() => Math.random() - 0.5);
quizQuestions.push({
correctItem: correct,
example: randomExample,
- options: options
+ options: options,
+ userAnswerId: null,
+ userAnswerText: '',
+ isAnswered: false,
+ isCorrect: false
});
}
@@ -1806,6 +2218,7 @@
document.getElementById('quizStreak').innerText = '0';
document.getElementById('quizPlayArea').classList.remove('hidden');
document.getElementById('quizResultScreen').classList.add('hidden');
+ document.getElementById('examResultScreen').classList.add('hidden');
document.getElementById('quizFeedbackBox').classList.add('hidden');
renderQuizQuestion();
@@ -1813,52 +2226,200 @@
function startWeakSpotsQuiz() {
if (quizMistakes.length === 0) {
- showToast('Keine Schwachstellen vorhanden! Starte Kernstoff-Quiz.', 'fa-star');
- startQuiz('highlighted');
- return;
+ const lowCards = STILMITTEL_DATA.filter(item => (cardLevels[item.id] || 1) <= 2);
+ if (lowCards.length === 0) {
+ showToast('Keine Schwachstellen vorhanden! Starte Kernstoff-Quiz.', 'fa-star');
+ startQuiz('highlighted');
+ return;
+ }
}
startQuiz('weakspots');
}
+ function handleExamTimerTick() {
+ examTimeRemaining--;
+ updateExamTimerDisplay();
+ if (examTimeRemaining <= 0) {
+ clearInterval(examTimerInterval);
+ examTimerInterval = null;
+ showToast('Zeit abgelaufen! Prüfung wird ausgewertet...', 'fa-stopwatch');
+ finishExam();
+ }
+ }
+
+ function updateExamTimerDisplay() {
+ const minutes = Math.floor(Math.max(0, examTimeRemaining) / 60);
+ const seconds = Math.max(0, examTimeRemaining) % 60;
+ const displayStr = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
+ const timerEl = document.getElementById('examTimerDisplay');
+ if (timerEl) {
+ timerEl.innerText = displayStr;
+ if (examTimeRemaining <= 30) {
+ timerEl.className = 'font-mono text-2xl font-black text-rose-500 animate-pulse tracking-wider';
+ } else if (examTimeRemaining <= 120) {
+ timerEl.className = 'font-mono text-2xl font-black text-amber-400 tracking-wider';
+ } else {
+ timerEl.className = 'font-mono text-2xl font-black text-emerald-400 tracking-wider';
+ }
+ }
+ }
+
+ function confirmSubmitExamEarly() {
+ const answeredCount = quizQuestions.filter(q => q.isAnswered).length;
+ const confirmMsg = `Du hast ${answeredCount} von ${quizQuestions.length} Fragen beantwortet.\n\nMöchtest du die Prüfung wirklich jetzt abgeben und auswerten lassen?`;
+ if (confirm(confirmMsg)) {
+ finishExam();
+ }
+ }
+
function renderQuizQuestion() {
if (currentQuizIndex >= quizQuestions.length) {
- finishQuiz();
+ if (currentQuizMode === 'exam') {
+ finishExam();
+ } else {
+ finishQuiz();
+ }
return;
}
const q = quizQuestions[currentQuizIndex];
- isQuestionAnswered = false;
+ isQuestionAnswered = q.isAnswered || false;
document.getElementById('quizQuestionNumber').innerText = `Frage ${currentQuizIndex + 1} von ${quizQuestions.length}`;
document.getElementById('quizCategoryTag').innerText = q.correctItem.categoryLabel;
document.getElementById('quizPhraseBox').innerText = `„${q.example}“`;
document.getElementById('quizFeedbackBox').classList.add('hidden');
- const container = document.getElementById('quizOptionsContainer');
- container.innerHTML = '';
+ const isExam = currentQuizMode === 'exam';
- q.options.forEach((opt, idx) => {
- const btn = document.createElement('button');
- btn.id = `quiz-opt-btn-${idx}`;
- btn.className = 'quiz-opt-btn w-full p-4 rounded-2xl bg-white border-2 border-slate-200 hover:border-indigo-500 hover:bg-indigo-50/50 font-bold text-slate-800 text-sm transition shadow-sm text-left flex items-center justify-between group';
- btn.innerHTML = `
-
- ${idx + 1}
- ${opt.term}
-
-
- `;
- btn.onclick = () => answerQuiz(opt.id, btn);
- container.appendChild(btn);
- });
+ // Update Exam Nav Bar
+ const examTracker = document.getElementById('examQuestionTracker');
+ if (examTracker) examTracker.innerText = `Frage ${currentQuizIndex + 1} von ${quizQuestions.length}`;
+ const prevBtn = document.getElementById('examPrevBtn');
+ if (prevBtn) prevBtn.disabled = currentQuizIndex === 0;
+ const nextBtn = document.getElementById('examNextBtn');
+ if (nextBtn) {
+ if (currentQuizIndex === quizQuestions.length - 1) {
+ nextBtn.innerHTML = '
Prüfung abgeben ';
+ nextBtn.className = 'px-5 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-700 text-white font-bold text-xs sm:text-sm shadow transition flex items-center gap-1.5';
+ } else {
+ nextBtn.innerHTML = '
Weiter ';
+ nextBtn.className = 'px-5 py-2.5 rounded-xl bg-slate-900 hover:bg-slate-800 text-white font-bold text-xs sm:text-sm shadow transition flex items-center gap-1.5';
+ }
+ }
+
+ const optionsContainer = document.getElementById('quizOptionsContainer');
+ const freitextContainer = document.getElementById('quizFreitextContainer');
+
+ if (currentQuizInputType === 'text') {
+ optionsContainer.classList.add('hidden');
+ freitextContainer.classList.remove('hidden');
+ const input = document.getElementById('quizFreitextInput');
+ input.value = q.userAnswerText || '';
+ input.disabled = isExam ? false : isQuestionAnswered;
+ setTimeout(() => input.focus(), 50);
+ } else {
+ freitextContainer.classList.add('hidden');
+ optionsContainer.classList.remove('hidden');
+ optionsContainer.innerHTML = '';
+
+ q.options.forEach((opt, idx) => {
+ const btn = document.createElement('button');
+ btn.id = `quiz-opt-btn-${idx}`;
+ const isSelected = q.userAnswerId === opt.id;
+
+ let btnClass = 'quiz-opt-btn w-full p-4 rounded-2xl border-2 font-bold text-sm transition shadow-sm text-left flex items-center justify-between group ';
+ if (isExam) {
+ btnClass += isSelected
+ ? 'bg-indigo-50 border-indigo-600 text-indigo-950 ring-2 ring-indigo-300'
+ : 'bg-white border-slate-200 hover:border-indigo-400 text-slate-800';
+ } else {
+ btnClass += 'bg-white border-slate-200 hover:border-indigo-500 hover:bg-indigo-50/50 text-slate-800';
+ }
+ btn.className = btnClass;
+
+ btn.innerHTML = `
+
+ ${idx + 1}
+ ${opt.term}
+
+
+ `;
+ btn.onclick = () => answerQuiz(opt.id, btn);
+ optionsContainer.appendChild(btn);
+ });
+ }
}
function answerQuiz(selectedId, buttonEl) {
+ const q = quizQuestions[currentQuizIndex];
+ const isExam = currentQuizMode === 'exam';
+
+ if (isExam) {
+ q.userAnswerId = selectedId;
+ const chosenOpt = q.options.find(o => o.id === selectedId);
+ q.userAnswerText = chosenOpt ? chosenOpt.term : '';
+ q.isAnswered = true;
+ q.isCorrect = selectedId === q.correctItem.id;
+ playTone('tap');
+ renderQuizQuestion();
+ return;
+ }
+
if (isQuestionAnswered) return;
isQuestionAnswered = true;
+ q.isAnswered = true;
+ q.userAnswerId = selectedId;
+
+ const isCorrect = selectedId === q.correctItem.id;
+ q.isCorrect = isCorrect;
+
+ handleAnswerEvaluation(isCorrect, buttonEl);
+ }
+
+ function handleFreitextKeydown(e) {
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ submitFreitextAnswer();
+ }
+ }
+
+ function submitFreitextAnswer() {
+ const input = document.getElementById('quizFreitextInput');
+ const val = input.value.trim();
+ if (!val) {
+ input.focus();
+ return;
+ }
const q = quizQuestions[currentQuizIndex];
- const isCorrect = selectedId === q.correctItem.id;
+ const match = checkFuzzyMatch(val, q.correctItem.term);
+ const isExam = currentQuizMode === 'exam';
+
+ q.userAnswerText = val;
+ q.isAnswered = true;
+ q.isCorrect = match.isMatch;
+
+ if (isExam) {
+ playTone('tap');
+ showToast('Antwort gespeichert!', 'fa-check');
+ if (currentQuizIndex < quizQuestions.length - 1) {
+ nextExamQuestion();
+ } else {
+ renderQuizQuestion();
+ }
+ return;
+ }
+
+ if (isQuestionAnswered) return;
+ isQuestionAnswered = true;
+ input.disabled = true;
+
+ handleAnswerEvaluation(match.isMatch, null, match);
+ }
+
+ function handleAnswerEvaluation(isCorrect, buttonEl, fuzzyResult = null) {
+ const q = quizQuestions[currentQuizIndex];
const feedbackBox = document.getElementById('quizFeedbackBox');
const feedbackIcon = document.getElementById('quizFeedbackIcon');
const feedbackTitle = document.getElementById('quizFeedbackTitle');
@@ -1879,12 +2440,19 @@
quizMistakes = quizMistakes.filter(id => id !== q.correctItem.id);
localStorage.setItem('rhetorik_quiz_mistakes', JSON.stringify(quizMistakes));
- buttonEl.className = 'quiz-opt-btn w-full p-4 rounded-2xl bg-emerald-50 border-2 border-emerald-500 font-bold text-emerald-950 text-sm shadow-md text-left flex items-center justify-between';
- buttonEl.innerHTML += `
`;
+ if (buttonEl) {
+ buttonEl.className = 'quiz-opt-btn w-full p-4 rounded-2xl bg-emerald-50 border-2 border-emerald-500 font-bold text-emerald-950 text-sm shadow-md text-left flex items-center justify-between';
+ buttonEl.innerHTML += `
`;
+ }
feedbackBox.className = 'rounded-2xl p-4 sm:p-5 border bg-emerald-50 border-emerald-200 text-emerald-950 block';
feedbackIcon.className = 'fa-solid fa-circle-check text-emerald-600 text-2xl mt-0.5';
- feedbackTitle.innerText = `Exakt richtig! Es ist eine ${q.correctItem.term}.`;
+
+ let title = `Exakt richtig! Es ist eine ${q.correctItem.term}.`;
+ if (fuzzyResult && !fuzzyResult.exact) {
+ title = `Richtig gelöst! (Tippfehler bemerkt: Korrekt schreibt man '${q.correctItem.term}')`;
+ }
+ feedbackTitle.innerText = title;
let correctExtraHtml = `
${q.correctItem.definition} (${q.correctItem.tip || ''})
`;
if (q.correctItem.confusion) {
@@ -1908,8 +2476,10 @@
localStorage.setItem('rhetorik_quiz_mistakes', JSON.stringify(quizMistakes));
}
- buttonEl.className = 'quiz-opt-btn w-full p-4 rounded-2xl bg-rose-50 border-2 border-rose-500 font-bold text-rose-950 text-sm shadow-md text-left flex items-center justify-between';
- buttonEl.innerHTML += `
`;
+ if (buttonEl) {
+ buttonEl.className = 'quiz-opt-btn w-full p-4 rounded-2xl bg-rose-50 border-2 border-rose-500 font-bold text-rose-950 text-sm shadow-md text-left flex items-center justify-between';
+ buttonEl.innerHTML += `
`;
+ }
buttons.forEach((btn, idx) => {
if (q.options[idx].id === q.correctItem.id) {
@@ -1954,6 +2524,124 @@
renderQuizQuestion();
}
+ function prevExamQuestion() {
+ if (currentQuizIndex > 0) {
+ currentQuizIndex--;
+ renderQuizQuestion();
+ }
+ }
+
+ function nextExamQuestion() {
+ if (currentQuizIndex < quizQuestions.length - 1) {
+ currentQuizIndex++;
+ renderQuizQuestion();
+ } else {
+ confirmSubmitExamEarly();
+ }
+ }
+
+ function finishExam() {
+ if (examTimerInterval) {
+ clearInterval(examTimerInterval);
+ examTimerInterval = null;
+ }
+
+ const elapsedSec = Math.round((Date.now() - (examStartTime || Date.now())) / 1000);
+ const minutes = Math.floor(elapsedSec / 60);
+ const seconds = elapsedSec % 60;
+ const timeStr = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')} Min`;
+
+ let correctCount = 0;
+ quizQuestions.forEach(q => {
+ let isRight = false;
+ if (currentQuizInputType === 'text') {
+ isRight = checkFuzzyMatch(q.userAnswerText || '', q.correctItem.term).isMatch;
+ } else {
+ isRight = q.userAnswerId === q.correctItem.id;
+ }
+ q.isCorrect = isRight;
+ if (isRight) correctCount++;
+ else {
+ if (!quizMistakes.includes(q.correctItem.id)) {
+ quizMistakes.push(q.correctItem.id);
+ }
+ }
+ });
+
+ localStorage.setItem('rhetorik_quiz_mistakes', JSON.stringify(quizMistakes));
+ updateQuizMistakesBadge();
+
+ const gradeInfo = calculateExamGrade(correctCount, quizQuestions.length);
+ playTone(gradeInfo.grade <= 3 ? 'win' : 'error');
+
+ // Populate Exam Screen
+ document.getElementById('quizPlayArea').classList.add('hidden');
+ document.getElementById('examTimerBar').classList.add('hidden');
+ document.getElementById('examResultScreen').classList.remove('hidden');
+
+ const badgeContainer = document.getElementById('examGradeBadgeContainer');
+ badgeContainer.className = `inline-flex items-center gap-2 px-6 py-2.5 rounded-2xl border-2 font-black text-xl sm:text-2xl shadow-sm ${gradeInfo.badgeClass}`;
+ document.getElementById('examGradeTitle').innerText = `Note: ${gradeInfo.name}`;
+ const iconEl = document.getElementById('examGradeIcon');
+ iconEl.className = `fa-solid ${gradeInfo.icon} ${gradeInfo.iconColor}`;
+
+ document.getElementById('examPedagogicFeedback').innerText = gradeInfo.feedback;
+ document.getElementById('examScoreDisplay').innerText = `${correctCount} / ${quizQuestions.length}`;
+ document.getElementById('examPercentDisplay').innerText = `${Math.round((correctCount / quizQuestions.length) * 100)}%`;
+ document.getElementById('examTimeDisplay').innerText = timeStr;
+
+ const repeatMistakesBtn = document.getElementById('examRepeatMistakesBtn');
+ if (quizQuestions.some(q => !q.isCorrect)) {
+ repeatMistakesBtn.classList.remove('hidden');
+ } else {
+ repeatMistakesBtn.classList.add('hidden');
+ }
+
+ // Render Itemized Review List
+ const reviewList = document.getElementById('examReviewList');
+ reviewList.innerHTML = '';
+
+ quizQuestions.forEach((q, idx) => {
+ const itemEl = document.createElement('div');
+ itemEl.className = `p-4 rounded-2xl border ${q.isCorrect ? 'bg-emerald-50/60 border-emerald-200' : 'bg-rose-50/60 border-rose-200'} space-y-2`;
+
+ const userAns = q.userAnswerText || (q.userAnswerId ? (q.options.find(o => o.id === q.userAnswerId)?.term || 'Unbekannt') : '
');
+
+ itemEl.innerHTML = `
+
+
+
+
+ ${q.isCorrect ? 'Richtig' : 'Falsch'}
+
+
+
+
+
Deine Antwort: ${userAns}
+
Lösung:
+
+
+ ${q.correctItem.definition}
+
+ ${!q.isCorrect && q.correctItem.confusion ? `
+
+ ⚠️ Verwechslungsgefahr (${q.correctItem.confusion.trap}): ${q.correctItem.confusion.text}
+
+ ` : ''}
+
+ ${!q.isCorrect && q.correctItem.analysisTemplate ? `
+
+ 📝 Klausur-Muster: ${q.correctItem.analysisTemplate}
+
+ ` : ''}
+ `;
+ reviewList.appendChild(itemEl);
+ });
+ }
+
function finishQuiz() {
playTone('win');
document.getElementById('quizPlayArea').classList.add('hidden');
@@ -1972,7 +2660,6 @@
repeatBtn.classList.add('hidden');
}
}
-
// MATCHER GAME
function initMatcherGame() {
matcherSelectedPhrase = null;
diff --git a/www/sw.js b/www/sw.js
index c608cfd..2164e11 100644
--- a/www/sw.js
+++ b/www/sw.js
@@ -1,4 +1,4 @@
-const CACHE_NAME = 'rhetorikmaster-v6';
+const CACHE_NAME = 'rhetorikmaster-v7';
const STATIC_ASSETS = [
'/',
'/index.html',