Feature: 40 bilingual questions, random 10 game run, difficulty levels, and full i18n support

This commit is contained in:
kobold-ai
2026-09-21 12:33:34 +02:00
parent eafa1f833e
commit cf89cd31c7
15 changed files with 1369 additions and 138 deletions
+127
View File
@@ -83,6 +83,41 @@ body {
gap: 10px;
}
.lang-switch-group {
display: inline-flex;
background: rgba(20, 22, 40, 0.85);
border: 1px solid var(--border-gold);
border-radius: 20px;
padding: 2px;
overflow: hidden;
}
.lang-btn {
background: transparent;
border: none;
color: var(--text-muted);
font-size: 0.8rem;
font-weight: 600;
padding: 4px 9px;
border-radius: 16px;
cursor: pointer;
transition: all 0.2s ease;
min-height: 28px;
display: flex;
align-items: center;
gap: 4px;
}
.lang-btn:hover {
color: var(--gold);
}
.lang-btn.active {
background: var(--gold);
color: #0b0b16;
box-shadow: 0 0 8px rgba(201, 168, 106, 0.4);
}
.audio-btn {
background: rgba(201, 168, 106, 0.15);
border: 1px solid var(--gold);
@@ -302,6 +337,57 @@ body {
color: var(--text-muted);
}
.difficulty-selection {
margin: 18px 0 22px;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.difficulty-label {
font-size: 0.95rem;
color: var(--gold-soft);
font-weight: 600;
}
.difficulty-chips {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
}
.diff-chip {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-gold);
color: var(--text-muted);
border-radius: 20px;
padding: 8px 16px;
font-size: 0.88rem;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 6px;
transition: all 0.2s ease;
font-family: inherit;
}
.diff-chip:hover {
border-color: var(--gold);
color: var(--text-main);
transform: translateY(-1px);
background: rgba(201, 168, 106, 0.12);
}
.diff-chip.active {
background: rgba(201, 168, 106, 0.25);
border-color: var(--gold);
color: var(--gold-bright);
box-shadow: 0 0 10px rgba(201, 168, 106, 0.35);
font-weight: bold;
}
/* =========================================
BUTTONS
========================================= */
@@ -446,6 +532,13 @@ body {
gap: 8px;
}
.meta-left {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.badge {
padding: 4px 10px;
border-radius: 12px;
@@ -457,6 +550,30 @@ body {
white-space: nowrap;
}
.badge-diff {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.2);
color: var(--text-main);
}
.badge-diff-easy {
background: rgba(46, 204, 113, 0.15);
border-color: #2ecc71;
color: #2ecc71;
}
.badge-diff-medium {
background: rgba(243, 156, 18, 0.15);
border-color: #f39c12;
color: #f39c12;
}
.badge-diff-hard {
background: rgba(231, 76, 60, 0.15);
border-color: #e74c3c;
color: #e74c3c;
}
.badge-warning {
background: rgba(243, 156, 18, 0.2);
border-color: var(--warning);
@@ -1055,4 +1172,14 @@ body {
.admin-top-actions {
justify-content: center;
}
.lang-btn {
padding: 4px 6px;
font-size: 0.75rem;
}
.diff-chip {
padding: 6px 10px;
font-size: 0.8rem;
}
}
+166 -22
View File
@@ -1,9 +1,72 @@
let currentSessionId = null;
let currentQuestionNumber = 1;
let totalQuestions = 15;
let totalQuestions = 10;
let currentScore = 0;
let attemptsUsed = 0;
const maxAttempts = 3;
let selectedDifficulty = "all";
let lastQuestionData = null;
const UI_TEXT = {
de: {
pageTitle: "✨ Magisches Hogwarts-Escape-Quiz ✨",
pageSubtitle: "10 knifflige Rätsel aus der Zauberwelt warten auf dich",
envelopeLetter: "Hogwarts-Schule für Hexerei und Zauberei",
introDesc: "Ein verzauberter Brief aus Hogwarts schwebt vor dir in der Luft.<br>Bist du bereit, die Prüfungen abzulegen und deine Hauspunkte zu sichern?",
diffLabel: "Schwierigkeitsgrad wählen:",
diffAll: "Alle gemischt",
diffEasy: "Leicht",
diffMed: "Mittel",
diffHard: "Schwer",
startBtn: "📜 Siegel brechen & Brief öffnen",
startBtnCasting: "✨ Zauber wird gewirkt...",
pointsLabel: "🏆 Hauspunkte",
questionLabel: "Frage",
ofLabel: "von",
attemptLabel: "Versuch",
checkBtn: "✨ Zauber prüfen",
hintBtn: "💡 Zaubertipp",
hintHeading: "📜 Notiz aus der verbotenen Abteilung:",
placeholder: "Deine Antwort hier eingeben...",
noHint: "Kein Tipp vorhanden.",
hintFailed: "Tipp konnte nicht geladen werden.",
correctFeedback: "✨ Richtig! 1 Hauspunkt für dein Haus! ✨",
wrongFeedback: "Leider falsch! Noch {attempts} Versuch(e).",
exhaustedWrong: "Leider nicht richtig (3 Fehlversuche).",
solutionLabel: "Richtige Lösung:",
startError: "Fehler beim Starten des Quiz: ",
networkError: "Netzwerkfehler: "
},
en: {
pageTitle: "✨ Magical Hogwarts Escape Quiz ✨",
pageSubtitle: "10 tricky wizarding world puzzles await you",
envelopeLetter: "Hogwarts School of Witchcraft and Wizardry",
introDesc: "An enchanted letter from Hogwarts is floating in the air before you.<br>Are you ready to take the exams and secure House Points?",
diffLabel: "Choose difficulty level:",
diffAll: "All mixed",
diffEasy: "Easy",
diffMed: "Medium",
diffHard: "Hard",
startBtn: "📜 Break Seal & Open Letter",
startBtnCasting: "✨ Casting spell...",
pointsLabel: "🏆 House Points",
questionLabel: "Question",
ofLabel: "of",
attemptLabel: "Attempt",
checkBtn: "✨ Check Spell",
hintBtn: "💡 Magic Hint",
hintHeading: "📜 Note from the Restricted Section:",
placeholder: "Type your answer here...",
noHint: "No hint available.",
hintFailed: "Could not load hint.",
correctFeedback: "✨ Correct! 1 House Point for your House! ✨",
wrongFeedback: "Incorrect! {attempts} attempt(s) remaining.",
exhaustedWrong: "Unfortunately incorrect (3 failed attempts).",
solutionLabel: "Correct solution:",
startError: "Error starting quiz: ",
networkError: "Network error: "
}
};
// Web Audio API Sound Generator for magic chimes and buzzers
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
@@ -43,12 +106,63 @@ function playSound(type) {
}
}
function selectDifficulty(diff) {
selectedDifficulty = diff;
document.querySelectorAll(".diff-chip").forEach(chip => {
chip.classList.toggle("active", chip.getAttribute("data-diff") === diff);
});
}
function onLanguageChange(lang) {
applyQuizTranslations(lang);
}
function applyQuizTranslations(lang) {
const t = UI_TEXT[lang] || UI_TEXT.de;
const pageTitle = document.getElementById("pageTitle");
const pageSubtitle = document.getElementById("pageSubtitle");
const envelopeLetter = document.getElementById("envelopeLetter");
const introDesc = document.getElementById("introDesc");
const diffLabel = document.getElementById("diffLabel");
const diffAllText = document.getElementById("diffAllText");
const diffEasyText = document.getElementById("diffEasyText");
const diffMedText = document.getElementById("diffMedText");
const diffHardText = document.getElementById("diffHardText");
const startBtn = document.getElementById("startBtn");
const checkBtn = document.getElementById("checkBtn");
const hintBtn = document.getElementById("hintBtn");
const hintBtnMC = document.getElementById("hintBtnMC");
const hintHeading = document.getElementById("hintHeading");
const answerInput = document.getElementById("answerInput");
if (pageTitle) pageTitle.innerText = t.pageTitle;
if (pageSubtitle) pageSubtitle.innerText = t.pageSubtitle;
if (envelopeLetter) envelopeLetter.innerText = t.envelopeLetter;
if (introDesc) introDesc.innerHTML = t.introDesc;
if (diffLabel) diffLabel.innerText = t.diffLabel;
if (diffAllText) diffAllText.innerText = t.diffAll;
if (diffEasyText) diffEasyText.innerText = t.diffEasy;
if (diffMedText) diffMedText.innerText = t.diffMed;
if (diffHardText) diffHardText.innerText = t.diffHard;
if (startBtn && !startBtn.disabled) startBtn.innerText = t.startBtn;
if (checkBtn) checkBtn.innerText = t.checkBtn;
if (hintBtn) hintBtn.innerText = t.hintBtn;
if (hintBtnMC) hintBtnMC.innerText = t.hintBtn;
if (hintHeading) hintHeading.innerText = t.hintHeading;
if (answerInput) answerInput.placeholder = t.placeholder;
if (lastQuestionData) {
renderQuestion(lastQuestionData);
}
}
async function startGame() {
const envelope = document.getElementById("envelope");
const startBtn = document.getElementById("startBtn");
const t = UI_TEXT[currentLang] || UI_TEXT.de;
startBtn.disabled = true;
startBtn.innerText = "✨ Zauber wird gewirkt...";
startBtn.innerText = t.startBtnCasting;
envelope.classList.add("envelope-opened");
// Start background music if enabled or first click
@@ -59,7 +173,7 @@ async function startGame() {
const text = document.getElementById("audioText");
if (icon && text) {
icon.innerText = "🔊";
text.innerText = "Musik: An";
text.innerText = (currentLang === "de") ? "Musik: An" : "Music: On";
}
localStorage.setItem("bgm_enabled", "true");
}).catch(() => {});
@@ -68,11 +182,15 @@ async function startGame() {
try {
const res = await fetch("/api/game/start", {
method: "POST",
headers: { "Content-Type": "application/json" }
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
lang: currentLang,
difficulty: selectedDifficulty
})
});
if (!res.ok) {
throw new Error("Konnte Spiel nicht starten.");
throw new Error(currentLang === "en" ? "Could not start game session." : "Konnte Spiel nicht starten.");
}
const data = await res.json();
@@ -89,18 +207,39 @@ async function startGame() {
}, 1100);
} catch (err) {
alert("Fehler beim Starten des Quiz: " + err.message);
alert(t.startError + err.message);
startBtn.disabled = false;
startBtn.innerText = "📜 Siegel brechen & Brief öffnen";
startBtn.innerText = t.startBtn;
envelope.classList.remove("envelope-opened");
}
}
function renderQuestion(qData) {
document.getElementById("questionCounter").innerText = `Frage ${qData.question_number} von ${totalQuestions}`;
document.getElementById("pointsCounter").innerText = `🏆 Hauspunkte: ${currentScore}`;
lastQuestionData = qData;
const t = UI_TEXT[currentLang] || UI_TEXT.de;
document.getElementById("questionCounter").innerText = `${t.questionLabel} ${qData.question_number} ${t.ofLabel} ${totalQuestions}`;
document.getElementById("pointsCounter").innerText = `${t.pointsLabel}: ${currentScore}`;
document.getElementById("badgeCategory").innerText = `⚡ ${qData.category.replace("_", " ").toUpperCase()}`;
document.getElementById("attemptBadge").innerText = `Versuch ${attemptsUsed + 1} von ${maxAttempts}`;
// Difficulty badge
const badgeDiff = document.getElementById("badgeDifficulty");
if (badgeDiff) {
const diff = qData.difficulty || "medium";
badgeDiff.className = `badge badge-diff badge-diff-${diff}`;
let diffText = t.diffMed;
let diffIcon = "🟡";
if (diff === "easy") {
diffText = t.diffEasy;
diffIcon = "🟢";
} else if (diff === "hard") {
diffText = t.diffHard;
diffIcon = "🔴";
}
badgeDiff.innerText = `${diffIcon} ${diffText}`;
}
document.getElementById("attemptBadge").innerText = `${t.attemptLabel} ${attemptsUsed + 1} ${t.ofLabel} ${maxAttempts}`;
document.getElementById("frageText").innerText = qData.question;
const textGroup = document.getElementById("textAnswerGroup");
@@ -129,6 +268,7 @@ function renderQuestion(qData) {
choiceGroup.classList.add("hidden");
textGroup.classList.remove("hidden");
input.value = "";
input.placeholder = t.placeholder;
input.disabled = false;
document.getElementById("checkBtn").disabled = false;
input.focus();
@@ -160,6 +300,8 @@ function checkAnswer() {
async function submitAnswer(answer, clickedBtn = null) {
const checkBtn = document.getElementById("checkBtn");
const input = document.getElementById("answerInput");
const t = UI_TEXT[currentLang] || UI_TEXT.de;
if (checkBtn) checkBtn.disabled = true;
if (input) input.disabled = true;
@@ -181,12 +323,12 @@ async function submitAnswer(answer, clickedBtn = null) {
});
if (!res.ok) {
throw new Error("Fehler bei der Antwortprüfung.");
throw new Error(currentLang === "en" ? "Answer check failed." : "Fehler bei der Antwortprüfung.");
}
const result = await res.json();
currentScore = result.score;
document.getElementById("pointsCounter").innerText = `🏆 Hauspunkte: ${currentScore}`;
document.getElementById("pointsCounter").innerText = `${t.pointsLabel}: ${currentScore}`;
const frageBox = document.getElementById("frageBox");
const feedbackBox = document.getElementById("feedbackBox");
@@ -199,7 +341,7 @@ async function submitAnswer(answer, clickedBtn = null) {
clickedBtn.classList.add("choice-correct");
}
frageBox.classList.add("sparkle-effect");
feedbackBox.innerHTML = `<span class="feedback-correct">✨ Richtig! 1 Hauspunkt für dein Haus! ✨</span>`;
feedbackBox.innerHTML = `<span class="feedback-correct">${t.correctFeedback}</span>`;
setTimeout(() => {
frageBox.classList.remove("sparkle-effect");
@@ -223,13 +365,13 @@ async function submitAnswer(answer, clickedBtn = null) {
setTimeout(() => frageBox.classList.remove("shake-effect"), 500);
attemptsUsed = result.attempts_used;
document.getElementById("attemptBadge").innerText = `Versuch ${Math.min(attemptsUsed + 1, maxAttempts)} von ${maxAttempts}`;
document.getElementById("attemptBadge").innerText = `${t.attemptLabel} ${Math.min(attemptsUsed + 1, maxAttempts)} ${t.ofLabel} ${maxAttempts}`;
if (result.attempts_left === 0) {
// Exhausted all attempts
feedbackBox.innerHTML = `
<div class="feedback-wrong">Leider nicht richtig (3 Fehlversuche).</div>
<div class="feedback-revealed">Richtige Lösung: <strong>${result.revealed_answer}</strong></div>
<div class="feedback-wrong">${t.exhaustedWrong}</div>
<div class="feedback-revealed">${t.solutionLabel} <strong>${result.revealed_answer}</strong></div>
`;
setTimeout(() => {
@@ -244,7 +386,8 @@ async function submitAnswer(answer, clickedBtn = null) {
} else {
// Still attempts remaining
feedbackBox.innerHTML = `<span class="feedback-wrong">Leider falsch! Noch ${result.attempts_left} Versuch(e).</span>`;
const msg = t.wrongFeedback.replace("{attempts}", result.attempts_left);
feedbackBox.innerHTML = `<span class="feedback-wrong">${msg}</span>`;
if (checkBtn) checkBtn.disabled = false;
if (input) {
input.disabled = false;
@@ -256,7 +399,7 @@ async function submitAnswer(answer, clickedBtn = null) {
}
} catch (err) {
alert("Netzwerkfehler: " + err.message);
alert(t.networkError + err.message);
if (checkBtn) checkBtn.disabled = false;
if (input) input.disabled = false;
choiceBtns.forEach(b => b.disabled = false);
@@ -267,22 +410,22 @@ async function requestHint() {
if (!currentSessionId) return;
const hintBox = document.getElementById("hintBox");
const hintText = document.getElementById("hintText");
const t = UI_TEXT[currentLang] || UI_TEXT.de;
try {
const res = await fetch(`/api/game/hint?session_id=${encodeURIComponent(currentSessionId)}`);
const data = await res.json();
hintText.innerText = data.hint || "Kein Tipp vorhanden.";
hintText.innerText = data.hint || t.noHint;
hintBox.classList.remove("hidden");
} catch (err) {
hintText.innerText = "Tipp konnte nicht geladen werden.";
hintText.innerText = t.hintFailed;
hintBox.classList.remove("hidden");
}
}
function finishGame() {
// 100% progress
document.getElementById("progressBar").style.width = "100%";
window.location.href = `/finale?score=${currentScore}&total=${totalQuestions}`;
window.location.href = `/finale?score=${currentScore}&total=${totalQuestions}&lang=${currentLang}`;
}
// Enter key to submit
@@ -296,4 +439,5 @@ document.addEventListener("DOMContentLoaded", () => {
}
});
}
applyQuizTranslations(currentLang);
});
+119 -9
View File
@@ -1,32 +1,136 @@
const SUGGESTION_TEXT = {
de: {
title: "✨ Neue Frage für das Quiz vorschlagen ✨",
subtitle: "Bereichere das magische Quiz mit kniffligen Harry-Potter- oder Escape-Rätseln!",
alert: "ℹ️ <strong>Hinweis zur Moderation:</strong> Eingereichte Fragen werden nicht sofort öffentlich sichtbar, sondern erhalten automatisch den Status <em>„Prüfung ausstehend“</em>. Unser Zaubereiministerium prüft und testet die Antwort, bevor die Frage freigeschaltet wird.",
nameLabel: "Dein Name / Zauberer-Alias (optional):",
namePlaceholder: "z. B. Hermine Granger",
frageLabel: "Deine Frage: *",
fragePlaceholder: "z. B. Wie heißt der Schulleiter von Hogwarts?",
diffLabel: "Schwierigkeitsgrad:",
typeLabel: "Art der Frage:",
optText: "🔤 Freitext-Antwort (Tippen mit Fehlertoleranz)",
optMC: "🔘 Multiple Choice (Auswahl aus 4 Antwortmöglichkeiten)",
antwortLabelText: "Richtige Antwort:",
antwortLabelMC: "Richtige Antwort (die korrekte Option):",
antwortHelpText: "Unser System gleicht Tippfehler und Groß-/Kleinschreibung automatisch ab.",
antwortHelpMC: "Diese Antwort wird zusammen mit den falschen Optionen zufällig für den Spieler angeordnet.",
wrongLabel: "Falsche Antwortmöglichkeiten (zur Auswahl für die Spieler):",
wrongPlaceholder1: "Falsche Option 1 (z. B. Severus Snape)",
wrongPlaceholder2: "Falsche Option 2 (z. B. Minerva McGonagall)",
wrongPlaceholder3: "Falsche Option 3 (z. B. Rubeus Hagrid)",
tippLabel: "Tipp / Hinweis (optional):",
tippPlaceholder: "z. B. Er trägt eine Halbmondbrille.",
submitBtn: "📜 Vorschlag an das Ministerium senden",
submitBtnCasting: "✨ Vorschlag wird übertragen...",
alertFillRequired: "Bitte gib mindestens die Frage und die richtige Antwort ein.",
alertMCRequired: "Bitte gib bei Multiple-Choice mindestens eine falsche Antwortmöglichkeit an.",
successHeader: "✨ Vorschlag erfolgreich übermittelt! ✨"
},
en: {
title: "✨ Suggest a New Quiz Question ✨",
subtitle: "Enrich the magical quiz with tricky Harry Potter or escape puzzles!",
alert: "ℹ️ <strong>Moderation Note:</strong> Submitted questions are not immediately public; they automatically receive the status <em>'Pending Review'</em>. The Ministry of Magic tests and verifies the answer before approval.",
nameLabel: "Your Name / Wizard Alias (optional):",
namePlaceholder: "e.g. Hermione Granger",
frageLabel: "Your Question: *",
fragePlaceholder: "e.g. Who is the Headmaster of Hogwarts?",
diffLabel: "Difficulty Level:",
typeLabel: "Question Type:",
optText: "🔤 Free-Text Input (with typo tolerance)",
optMC: "🔘 Multiple Choice (Selection of 4 options)",
antwortLabelText: "Correct Answer:",
antwortLabelMC: "Correct Answer (the winning option):",
antwortHelpText: "Our system automatically matches minor typos and casing.",
antwortHelpMC: "This option will be shuffled together with the false choices.",
wrongLabel: "Wrong Answer Options (for player to choose from):",
wrongPlaceholder1: "Wrong Option 1 (e.g. Severus Snape)",
wrongPlaceholder2: "Wrong Option 2 (e.g. Minerva McGonagall)",
wrongPlaceholder3: "Wrong Option 3 (e.g. Rubeus Hagrid)",
tippLabel: "Hint / Clue (optional):",
tippPlaceholder: "e.g. He wears half-moon spectacles.",
submitBtn: "📜 Submit Proposal to the Ministry",
submitBtnCasting: "✨ Transmitting proposal...",
alertFillRequired: "Please enter at least the question and the correct answer.",
alertMCRequired: "For Multiple Choice, please provide at least one incorrect option.",
successHeader: "✨ Question successfully submitted! ✨"
}
};
function onLanguageChange(lang) {
const t = SUGGESTION_TEXT[lang] || SUGGESTION_TEXT.de;
const title = document.getElementById("suggTitle");
const subtitle = document.getElementById("suggSubtitle");
const alertBox = document.getElementById("suggAlert");
const nameLabel = document.getElementById("suggNameLabel");
const nameInput = document.getElementById("name");
const frageLabel = document.getElementById("suggFrageLabel");
const frageInput = document.getElementById("frage");
const diffLabel = document.getElementById("suggDiffLabel");
const typeLabel = document.getElementById("suggTypeLabel");
const optText = document.getElementById("optText");
const optMC = document.getElementById("optMC");
const mcWrongLabel = document.getElementById("mcWrongLabel");
const tippLabel = document.getElementById("suggTippLabel");
const tippInput = document.getElementById("tipp");
const submitBtn = document.getElementById("submitBtn");
if (title) title.innerText = t.title;
if (subtitle) subtitle.innerText = t.subtitle;
if (alertBox) alertBox.innerHTML = t.alert;
if (nameLabel) nameLabel.innerText = t.nameLabel;
if (nameInput) nameInput.placeholder = t.namePlaceholder;
if (frageLabel) frageLabel.innerText = t.frageLabel;
if (frageInput) frageInput.placeholder = t.fragePlaceholder;
if (diffLabel) diffLabel.innerText = t.diffLabel;
if (typeLabel) typeLabel.innerText = t.typeLabel;
if (optText) optText.innerText = t.optText;
if (optMC) optMC.innerText = t.optMC;
if (mcWrongLabel) mcWrongLabel.innerText = t.wrongLabel;
if (tippLabel) tippLabel.innerText = t.tippLabel;
if (tippInput) tippInput.placeholder = t.tippPlaceholder;
if (submitBtn && !submitBtn.disabled) submitBtn.innerText = t.submitBtn;
const qType = document.getElementById("q_type");
if (qType) toggleVorschlagType(qType.value);
}
function toggleVorschlagType(type) {
const lang = (typeof currentLang !== "undefined") ? currentLang : (localStorage.getItem("quiz_lang") || "de");
const t = SUGGESTION_TEXT[lang] || SUGGESTION_TEXT.de;
const mcGroup = document.getElementById("mcOptionsGroup");
const antwortLabel = document.getElementById("antwortLabel");
const antwortHelp = document.getElementById("antwortHelp");
if (type === "multiple_choice") {
mcGroup.classList.remove("hidden");
antwortLabel.innerText = "Richtige Antwort (die korrekte Option):";
antwortHelp.innerText = "Diese Antwort wird zusammen mit den falschen Optionen zufällig für den Spieler angeordnet.";
antwortLabel.innerText = t.antwortLabelMC;
antwortHelp.innerText = t.antwortHelpMC;
} else {
mcGroup.classList.add("hidden");
antwortLabel.innerText = "Richtige Antwort:";
antwortHelp.innerText = "Unser System gleicht Tippfehler und Groß-/Kleinschreibung automatisch ab.";
antwortLabel.innerText = t.antwortLabelText;
antwortHelp.innerText = t.antwortHelpText;
}
}
async function submitSuggestion(event) {
event.preventDefault();
const lang = (typeof currentLang !== "undefined") ? currentLang : (localStorage.getItem("quiz_lang") || "de");
const t = SUGGESTION_TEXT[lang] || SUGGESTION_TEXT.de;
const name = document.getElementById("name").value.trim();
const frage = document.getElementById("frage").value.trim();
const antwort = document.getElementById("antwort").value.trim();
const tipp = document.getElementById("tipp").value.trim();
const qType = document.getElementById("q_type").value;
const diff = document.getElementById("diff_select") ? document.getElementById("diff_select").value : "medium";
const submitBtn = document.getElementById("submitBtn");
const resultBox = document.getElementById("resultMessage");
if (!frage || !antwort) {
alert("Bitte gib mindestens die Frage und die richtige Antwort ein.");
alert(t.alertFillRequired);
return;
}
@@ -38,13 +142,13 @@ async function submitSuggestion(event) {
falscheAntworten = [w1, w2, w3].filter(x => x.length > 0);
if (falscheAntworten.length === 0) {
alert("Bitte gib bei Multiple-Choice mindestens eine falsche Antwortmöglichkeit an.");
alert(t.alertMCRequired);
return;
}
}
submitBtn.disabled = true;
submitBtn.innerText = "✨ Vorschlag wird übertragen...";
submitBtn.innerText = t.submitBtnCasting;
try {
const payload = {
@@ -53,6 +157,7 @@ async function submitSuggestion(event) {
antwort: antwort,
tipp: tipp || null,
question_type: qType,
difficulty: diff,
falsche_antworten: falscheAntworten
};
@@ -67,7 +172,7 @@ async function submitSuggestion(event) {
if (res.ok && data.success) {
resultBox.innerHTML = `
<div style="background: rgba(46, 204, 113, 0.2); border: 1px solid #2ecc71; color: #55efc4; padding: 15px; border-radius: 8px;">
<h3>✨ Vorschlag erfolgreich übermittelt! ✨</h3>
<h3>${t.successHeader}</h3>
<p>${data.message}</p>
</div>
`;
@@ -91,6 +196,11 @@ async function submitSuggestion(event) {
resultBox.classList.remove("hidden");
} finally {
submitBtn.disabled = false;
submitBtn.innerText = "📜 Vorschlag an das Ministerium senden";
submitBtn.innerText = t.submitBtn;
}
}
document.addEventListener("DOMContentLoaded", () => {
const lang = (typeof currentLang !== "undefined") ? currentLang : (localStorage.getItem("quiz_lang") || "de");
onLanguageChange(lang);
});