Add Spiellogik in play.html und play.js
This commit is contained in:
parent
66cee7e5e2
commit
d91d42f759
@ -137,9 +137,9 @@ p {
|
||||
border-radius: 6px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#logo-img {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
#logo_img {
|
||||
max-width: 300px;
|
||||
width: 50%;
|
||||
height: auto;
|
||||
}
|
||||
#main-area {
|
||||
|
||||
@ -74,7 +74,7 @@
|
||||
|
||||
<!-- Content -->
|
||||
<main class="container mt-4" id="main-content">
|
||||
<!-- Hier wird play.html geladen -->
|
||||
<!-- Hier werden die pages.html geladen -->
|
||||
</main>
|
||||
|
||||
<!-- Footer: Jetzt INSIDE main-area, damit Flexbox funktioniert -->
|
||||
@ -82,8 +82,8 @@
|
||||
<div class="container">
|
||||
<!-- Oberer Bereich -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-12">
|
||||
<h5 class="text-warning">Made with <span class="text-danger">♥</span> und zu viel Kaffee für das Modul Frontend. Bootstrap 5.3.8 powered.</h5>
|
||||
<div class="col-12">Made with <span class="text-danger">♥</span> für das Modul Frontend
|
||||
<h5 class="text-warning">Made with Bootstrap 5.3.8.</h5>
|
||||
<p class="text-black small mb-0 fst-italic">
|
||||
<em>„Unser Impressum ist länger als der Text, den Sie sich merken müssen.“</em>
|
||||
</p>
|
||||
@ -132,11 +132,8 @@
|
||||
<script src="assets/src/service/score-service.js"></script>
|
||||
<script src="assets/src/service/leaderboard-service.js"></script>
|
||||
<script src="js/login.js"></script>
|
||||
<<<<<<< Updated upstream
|
||||
<script src="js/leaderboard.js"></script>
|
||||
<!--Navigation Script -->
|
||||
=======
|
||||
>>>>>>> Stashed changes
|
||||
<script src="js/play.js"></script>
|
||||
<script src="js/navigation.js"></script>
|
||||
</body>
|
||||
|
||||
27
js/login.js
27
js/login.js
@ -71,7 +71,7 @@
|
||||
logoutButton.disabled = false;
|
||||
deleteAccountButton.disabled = false;
|
||||
currentSessionBox.classList.remove("d-none");
|
||||
authFormsRow.classList.add("d-none");
|
||||
authFormsRow.classList.remove("d-none");
|
||||
} else {
|
||||
sessionText.textContent = "Nicht eingeloggt.";
|
||||
logoutButton.disabled = true;
|
||||
@ -100,6 +100,7 @@
|
||||
|
||||
const usernameInput = document.getElementById("login-username");
|
||||
const passwordInput = document.getElementById("login-password");
|
||||
const submitButton = event.submitter;
|
||||
const username = usernameInput.value.trim();
|
||||
const password = passwordInput.value.trim();
|
||||
|
||||
@ -108,7 +109,29 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await userService.getUser(username, password);
|
||||
if (submitButton) {
|
||||
submitButton.disabled = true;
|
||||
submitButton.textContent = "Einloggen...";
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await userService.getUser(username, password);
|
||||
} catch (error) {
|
||||
console.error("Login fehlgeschlagen:", error);
|
||||
setFeedback("Login fehlgeschlagen: Backend ist nicht erreichbar.", "danger");
|
||||
if (submitButton) {
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = "Einloggen";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (submitButton) {
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = "Einloggen";
|
||||
}
|
||||
|
||||
if (result.ok) {
|
||||
saveAuth(username, password);
|
||||
setFeedback("Login erfolgreich.", "success");
|
||||
|
||||
@ -26,6 +26,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (page === "leaderboard" && typeof window.initLeaderboardPage === "function") {
|
||||
window.initLeaderboardPage();
|
||||
}
|
||||
if (page === "play" && typeof window.initPlayPage === "function") {
|
||||
window.initPlayPage();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Fehler beim Laden von " + page + ":", error);
|
||||
@ -49,4 +52,4 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
|
||||
//Startseite laden
|
||||
loadPage("home", "nav-home");
|
||||
});
|
||||
});
|
||||
|
||||
326
js/play.js
326
js/play.js
@ -1,50 +1,117 @@
|
||||
(function() {
|
||||
// --- Konfiguration ---
|
||||
const GAME_TEXT = "Der schnelle braune Fuchs springt über den faulen Hund. Programmieren ist wie Zaubern, nur mit mehr Kaffee und weniger Magie. Wer rastet, der rostet, aber wer codet, der lebt.";
|
||||
const MEMORIZE_TIME_SECONDS = 15;
|
||||
|
||||
// Bausteine fuer den zufaelligen Rundentext. Alles bleibt lokal, damit das Spiel ohne Backend starten kann.
|
||||
const TEXT_PARTS = {
|
||||
subjects: [
|
||||
"Der flinke Entwickler",
|
||||
"Die neugierige Studentin",
|
||||
"Ein mueder Professor",
|
||||
"Das kleine Frontend",
|
||||
"Der mutige Browser",
|
||||
"Eine schlaue Funktion",
|
||||
"Der vergessliche Server",
|
||||
"Die kreative Gruppe"
|
||||
],
|
||||
actions: [
|
||||
"sortiert leise",
|
||||
"debuggt geduldig",
|
||||
"vergleicht heimlich",
|
||||
"speichert vorsichtig",
|
||||
"rendert ploetzlich",
|
||||
"zaehlt konzentriert",
|
||||
"testet neugierig",
|
||||
"kompiliert langsam"
|
||||
],
|
||||
objects: [
|
||||
"sieben blaue Buttons",
|
||||
"drei lange Variablen",
|
||||
"neun goldene Woerter",
|
||||
"vier kaputte Formulare",
|
||||
"acht schnelle Requests",
|
||||
"zwei leuchtende Karten",
|
||||
"fuenf stille Fehlermeldungen",
|
||||
"sechs winzige Icons"
|
||||
],
|
||||
places: [
|
||||
"im hellen Dashboard",
|
||||
"unter dem dunklen Navbar",
|
||||
"neben dem alten Footer",
|
||||
"zwischen Login und Leaderboard",
|
||||
"vor dem ersten Kaffee",
|
||||
"waehrend der Lernphase",
|
||||
"hinter dem lokalen Server",
|
||||
"mitten im Semesterprojekt"
|
||||
],
|
||||
endings: [
|
||||
"Danach lacht der Code, weil alles endlich funktioniert.",
|
||||
"Am Ende merkt sich niemand die Semikolons, aber alle die Punkte.",
|
||||
"Kurz darauf blinkt die Konsole und behauptet, sie sei unschuldig.",
|
||||
"Spaeter landet der Score im Ranking und wartet auf Applaus.",
|
||||
"Dabei bleibt die Seite ruhig, obwohl der Timer dramatisch tickt.",
|
||||
"Zum Schluss gewinnt, wer die Woerter sauber in Reihenfolge bringt."
|
||||
]
|
||||
};
|
||||
|
||||
let timerInterval;
|
||||
let currentTime = 0;
|
||||
|
||||
// --- DOM Elemente holen ---
|
||||
const phaseStart = document.getElementById('phaseStart');
|
||||
const phaseMemorize = document.getElementById('phaseMemorize');
|
||||
const phaseInput = document.getElementById('phaseInput');
|
||||
const phaseResult = document.getElementById('phaseResult');
|
||||
|
||||
const targetTextDisplay = document.getElementById('targetTextDisplay');
|
||||
const timerDisplay = document.getElementById('timerDisplay');
|
||||
const userTextInput = document.getElementById('userTextInput');
|
||||
const resultScore = document.getElementById('resultScore');
|
||||
const resultOriginal = document.getElementById('resultOriginal');
|
||||
const resultInput = document.getElementById('resultInput');
|
||||
const gameStatus = document.getElementById('gameStatus');
|
||||
// Der aktuell angezeigte Text muss bis zur Auswertung stabil bleiben.
|
||||
let currentGameText = "";
|
||||
let lastGeneratedText = "";
|
||||
|
||||
// Buttons
|
||||
const btnStart = document.getElementById('btnStartGame');
|
||||
const btnSubmit = document.getElementById('btnSubmitScore');
|
||||
const btnRestart = document.getElementById('btnRestart');
|
||||
const btnLeaderboard = document.getElementById('btnLeaderboard');
|
||||
|
||||
// --- Event Listener registrieren ---
|
||||
if (btnStart) btnStart.addEventListener('click', startGame);
|
||||
if (btnSubmit) btnSubmit.addEventListener('click', submitScore);
|
||||
if (btnRestart) btnRestart.addEventListener('click', () => location.reload());
|
||||
if (btnLeaderboard) btnLeaderboard.addEventListener('click', () => {
|
||||
const navLink = document.getElementById('nav-leaderboard');
|
||||
if (navLink) {
|
||||
navLink.click(); // Simuliert Klick auf Sidebar-Link
|
||||
} else {
|
||||
console.warn("Sidebar Link #nav-leaderboard nicht gefunden.");
|
||||
}
|
||||
});
|
||||
// DOM-Referenzen werden erst gesetzt, nachdem pages/play.html dynamisch geladen wurde.
|
||||
let phaseStart;
|
||||
let phaseMemorize;
|
||||
let phaseInput;
|
||||
let phaseResult;
|
||||
let targetTextDisplay;
|
||||
let timerDisplay;
|
||||
let userTextInput;
|
||||
let resultScore;
|
||||
let resultOriginal;
|
||||
let resultInput;
|
||||
let gameStatus;
|
||||
let scoreSaveFeedback;
|
||||
let btnSubmitScore;
|
||||
|
||||
// --- Funktionen ---
|
||||
|
||||
function getRandomItem(items) {
|
||||
return items[Math.floor(Math.random() * items.length)];
|
||||
}
|
||||
|
||||
// Erstellt pro Runde zwei zufaellige Saetze plus Schluss-Satz und vermeidet direkte Wiederholungen.
|
||||
function generateGameText() {
|
||||
let generatedText = "";
|
||||
|
||||
do {
|
||||
const firstSentence = [
|
||||
getRandomItem(TEXT_PARTS.subjects),
|
||||
getRandomItem(TEXT_PARTS.actions),
|
||||
getRandomItem(TEXT_PARTS.objects),
|
||||
getRandomItem(TEXT_PARTS.places)
|
||||
].join(" ") + ".";
|
||||
|
||||
const secondSentence = [
|
||||
getRandomItem(TEXT_PARTS.subjects),
|
||||
getRandomItem(TEXT_PARTS.actions),
|
||||
getRandomItem(TEXT_PARTS.objects),
|
||||
getRandomItem(TEXT_PARTS.places)
|
||||
].join(" ") + ".";
|
||||
|
||||
generatedText = firstSentence + " " + secondSentence + " " + getRandomItem(TEXT_PARTS.endings);
|
||||
} while (generatedText === lastGeneratedText);
|
||||
|
||||
lastGeneratedText = generatedText;
|
||||
return generatedText;
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
if (!phaseStart || !phaseMemorize) return;
|
||||
|
||||
// UI umschalten
|
||||
// Startansicht ausblenden und den neu generierten Text fuer die Lernphase anzeigen.
|
||||
phaseStart.classList.add('d-none');
|
||||
phaseMemorize.classList.remove('d-none');
|
||||
|
||||
@ -55,9 +122,10 @@
|
||||
gameStatus.style.color = "#1b1b2f";
|
||||
}
|
||||
|
||||
if(targetTextDisplay) targetTextDisplay.textContent = GAME_TEXT;
|
||||
currentGameText = generateGameText();
|
||||
if(targetTextDisplay) targetTextDisplay.textContent = currentGameText;
|
||||
|
||||
// Timer starten
|
||||
// Nach Ablauf des Timers wird automatisch zur Eingabe gewechselt.
|
||||
currentTime = MEMORIZE_TIME_SECONDS;
|
||||
if(timerDisplay) timerDisplay.textContent = currentTime;
|
||||
|
||||
@ -76,7 +144,7 @@
|
||||
|
||||
if (!phaseMemorize || !phaseInput) return;
|
||||
|
||||
// UI umschalten
|
||||
// Text verschwindet, Eingabefeld erscheint: ab hier zaehlt nur noch das Gedaechtnis.
|
||||
phaseMemorize.classList.add('d-none');
|
||||
phaseInput.classList.remove('d-none');
|
||||
|
||||
@ -93,12 +161,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Entfernt alles, was beim Vergleichen nicht zaehlen soll.
|
||||
function normalizeWord(word) {
|
||||
return word.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "");
|
||||
}
|
||||
|
||||
// Behält die sichtbaren Woerter separat, damit Satzzeichen in der Ergebnisanzeige erhalten bleiben.
|
||||
function getWords(text) {
|
||||
return text.split(/\s+/).filter(word => word.length > 0);
|
||||
}
|
||||
|
||||
function calculateScore(original, input) {
|
||||
if (!original || !input) return 0;
|
||||
|
||||
// Bereinigung: Kleinbuchstaben, Satzzeichen entfernen, in Arrays aufteilen
|
||||
const cleanOriginal = original.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g,"").split(/\s+/).filter(w => w.length > 0);
|
||||
const cleanInput = input.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g,"").split(/\s+/).filter(w => w.length > 0);
|
||||
// Score-Regel: gleiche Woerter an gleicher Position, Satzzeichen und Grossschreibung ignoriert.
|
||||
const cleanOriginal = getWords(original).map(normalizeWord).filter(word => word.length > 0);
|
||||
const cleanInput = getWords(input).map(normalizeWord).filter(word => word.length > 0);
|
||||
|
||||
let correctWords = 0;
|
||||
const limit = Math.min(cleanOriginal.length, cleanInput.length);
|
||||
@ -112,7 +190,104 @@
|
||||
return correctWords;
|
||||
}
|
||||
|
||||
function submitScore() {
|
||||
// Baut ein einzelnes farbiges Wort-Label fuer den Ergebnisvergleich.
|
||||
function createWordBadge(word, isCorrect) {
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "badge me-1 mb-1 " + (isCorrect ? "text-bg-success" : "text-bg-danger");
|
||||
badge.textContent = word;
|
||||
return badge;
|
||||
}
|
||||
|
||||
// Markiert Original und Eingabe nach derselben Positionslogik wie calculateScore().
|
||||
function renderWordComparison(original, input) {
|
||||
if (!resultOriginal || !resultInput) return;
|
||||
|
||||
const originalWords = getWords(original);
|
||||
const inputWords = getWords(input);
|
||||
|
||||
resultOriginal.innerHTML = "";
|
||||
resultInput.innerHTML = "";
|
||||
|
||||
// Original: rot, wenn das eingegebene Wort an dieser Position fehlt oder falsch ist.
|
||||
originalWords.forEach((word, index) => {
|
||||
const isCorrect = normalizeWord(word) === normalizeWord(inputWords[index] || "");
|
||||
resultOriginal.appendChild(createWordBadge(word, isCorrect));
|
||||
});
|
||||
|
||||
// Eingabe: rot, wenn das Wort nicht zum Originalwort an derselben Position passt.
|
||||
inputWords.forEach((word, index) => {
|
||||
const isCorrect = normalizeWord(word) === normalizeWord(originalWords[index] || "");
|
||||
resultInput.appendChild(createWordBadge(word, isCorrect));
|
||||
});
|
||||
}
|
||||
|
||||
function getAuth() {
|
||||
if (!window.AppAuth || typeof window.AppAuth.getAuth !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return window.AppAuth.getAuth();
|
||||
}
|
||||
|
||||
function getScoreService() {
|
||||
if (!window.config || !window.ScoreService) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new window.ScoreService(window.config);
|
||||
}
|
||||
|
||||
function showScoreSaveFeedback(message, type) {
|
||||
if (!scoreSaveFeedback) return;
|
||||
|
||||
scoreSaveFeedback.className = "alert alert-" + type + " mb-4";
|
||||
scoreSaveFeedback.textContent = message;
|
||||
scoreSaveFeedback.classList.remove("d-none");
|
||||
}
|
||||
|
||||
async function saveScore(scoreData) {
|
||||
const auth = getAuth();
|
||||
if (!auth || !auth.username || !auth.password) {
|
||||
showScoreSaveFeedback(
|
||||
"Score wurde nur lokal berechnet. Bitte einloggen, damit er im Leaderboard gespeichert wird.",
|
||||
"warning"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Auth-Daten kommen aus login.js; der ScoreService setzt daraus die Backend-Header.
|
||||
const scoreService = getScoreService();
|
||||
if (!scoreService) {
|
||||
showScoreSaveFeedback("Score-Service konnte nicht geladen werden.", "danger");
|
||||
return;
|
||||
}
|
||||
|
||||
showScoreSaveFeedback("Score wird gespeichert...", "info");
|
||||
|
||||
const result = await scoreService.postScore(
|
||||
auth.username,
|
||||
auth.password,
|
||||
scoreData.score,
|
||||
scoreData.time,
|
||||
scoreData.text,
|
||||
scoreData.userWrittenText
|
||||
);
|
||||
|
||||
if (result.ok) {
|
||||
const place = result.body && result.body.place ? " Platz " + result.body.place + "." : "";
|
||||
showScoreSaveFeedback("Score erfolgreich gespeichert." + place, "success");
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.status === 401) {
|
||||
showScoreSaveFeedback("Score konnte nicht gespeichert werden: Login ist nicht gültig.", "danger");
|
||||
return;
|
||||
}
|
||||
|
||||
showScoreSaveFeedback("Score konnte nicht gespeichert werden (Status " + result.status + ").", "danger");
|
||||
}
|
||||
|
||||
async function submitScore() {
|
||||
if (!userTextInput) return;
|
||||
|
||||
const userInput = userTextInput.value.trim();
|
||||
@ -121,9 +296,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const score = calculateScore(GAME_TEXT, userInput);
|
||||
if (btnSubmitScore) {
|
||||
btnSubmitScore.disabled = true;
|
||||
btnSubmitScore.textContent = "Wird ausgewertet...";
|
||||
}
|
||||
|
||||
const score = calculateScore(currentGameText, userInput);
|
||||
|
||||
// Ergebnis anzeigen
|
||||
// Ergebnis sofort anzeigen; das Speichern im Backend passiert danach asynchron.
|
||||
if (phaseInput) phaseInput.classList.add('d-none');
|
||||
if (phaseResult) phaseResult.classList.remove('d-none');
|
||||
|
||||
@ -135,23 +315,65 @@
|
||||
}
|
||||
|
||||
if (resultScore) resultScore.textContent = score;
|
||||
if (resultOriginal) resultOriginal.textContent = GAME_TEXT;
|
||||
if (resultInput) resultInput.textContent = userInput;
|
||||
renderWordComparison(currentGameText, userInput);
|
||||
|
||||
// --- API Aufruf vorbereiten ---
|
||||
// Genau dieser Rundentext wird gespeichert, damit Leaderboard/Score-Details nachvollziehbar bleiben.
|
||||
const scoreData = {
|
||||
score: score,
|
||||
time: MEMORIZE_TIME_SECONDS,
|
||||
text: GAME_TEXT,
|
||||
text: currentGameText,
|
||||
userWrittenText: userInput
|
||||
};
|
||||
|
||||
console.log("Score bereit zum Senden:", scoreData);
|
||||
|
||||
// HIER Ihren Service Aufruf einfügen, z.B.:
|
||||
// if (typeof window.ScoreService !== 'undefined') {
|
||||
// window.ScoreService.post(scoreData);
|
||||
// }
|
||||
|
||||
try {
|
||||
await saveScore(scoreData);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Speichern des Scores:", error);
|
||||
showScoreSaveFeedback("Score konnte wegen eines technischen Fehlers nicht gespeichert werden.", "danger");
|
||||
} finally {
|
||||
if (btnSubmitScore) {
|
||||
btnSubmitScore.disabled = false;
|
||||
btnSubmitScore.textContent = "Auswerten & Absenden";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
window.initPlayPage = function initPlayPage() {
|
||||
clearInterval(timerInterval);
|
||||
|
||||
// Die Navigation laedt play.html per fetch; deshalb werden die Elemente erst hier gesucht.
|
||||
phaseStart = document.getElementById('phaseStart');
|
||||
phaseMemorize = document.getElementById('phaseMemorize');
|
||||
phaseInput = document.getElementById('phaseInput');
|
||||
phaseResult = document.getElementById('phaseResult');
|
||||
|
||||
targetTextDisplay = document.getElementById('targetTextDisplay');
|
||||
timerDisplay = document.getElementById('timerDisplay');
|
||||
userTextInput = document.getElementById('userTextInput');
|
||||
resultScore = document.getElementById('resultScore');
|
||||
resultOriginal = document.getElementById('resultOriginal');
|
||||
resultInput = document.getElementById('resultInput');
|
||||
gameStatus = document.getElementById('gameStatus');
|
||||
scoreSaveFeedback = document.getElementById('scoreSaveFeedback');
|
||||
|
||||
const btnStart = document.getElementById('btnStartGame');
|
||||
btnSubmitScore = document.getElementById('btnSubmitScore');
|
||||
const btnRestart = document.getElementById('btnRestart');
|
||||
const btnLeaderboard = document.getElementById('btnLeaderboard');
|
||||
|
||||
if (btnStart) btnStart.addEventListener('click', startGame);
|
||||
if (btnSubmitScore) btnSubmitScore.addEventListener('click', submitScore);
|
||||
if (btnRestart) btnRestart.addEventListener('click', () => window.loadPage("play", "nav-play"));
|
||||
if (btnLeaderboard) btnLeaderboard.addEventListener('click', () => {
|
||||
const navLink = document.getElementById('nav-leaderboard');
|
||||
if (navLink) {
|
||||
navLink.click(); // Nutzt die bestehende Navigation inklusive Active-State.
|
||||
} else {
|
||||
console.warn("Sidebar Link #nav-leaderboard nicht gefunden.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
<h4 class="card-title mb-3">Willkommen beim Lorem Ipsum Game</h2>
|
||||
<p class="card-text text-uted fs-6 mb-4">Teste deine Fähigkeiten im Umgang mit Lorem Ipsum Texten! Je schneller und genauer du bist, desto höher ist dein Score.
|
||||
Viel Spaß beim Spielen!</p>
|
||||
|
||||
<p class="card-text fs-6"> Wähle eine Option aus der Navigation, um zu starten.</p>
|
||||
<img id="logo_img" src="image/Logo_loremIpsum.png" alt="Lorem Ipsum Game" class="img-fluid w-50 mt-3 d-block mx-auto">
|
||||
<img id="logo_img" src="image/Logo_loremIpsum.png" alt="Lorem Ipsum Game"class="img-fluid mt-3 d-block mx-auto">
|
||||
</div>
|
||||
@ -1,10 +1,10 @@
|
||||
<!-- Spiel-Wrapper -->
|
||||
<!-- Spielseite: Die vier Phasen werden per play.js ein- und ausgeblendet. -->
|
||||
<div class="game-container">
|
||||
|
||||
<!-- Header Bereich -->
|
||||
<!-- Status-Badge zeigt die aktuelle Spielphase: Bereit, Lernphase, Eingabe, Abgeschlossen. -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h2 class="fw-bold mb-1">Memorize Challenge</h2>
|
||||
<h2 class="fw-bold mb-0">Lorem Ipsum - Challenge you brain</h2>
|
||||
<p class="text-muted mb-0">Merken Sie sich den Text so gut wie möglich.</p>
|
||||
</div>
|
||||
<div id="gameStatus" class="badge bg-secondary fs-6 px-3 py-2">
|
||||
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 1: Start -->
|
||||
<!-- Phase 1: Startbildschirm vor der Textanzeige. -->
|
||||
<div id="phaseStart" class="card">
|
||||
<div class="card-body text-center py-5">
|
||||
<h3 class="mb-3">Sind Sie bereit?</h3>
|
||||
@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 2: Lernphase -->
|
||||
<!-- Phase 2: Merken. Der zufaellige Rundentext wird in #targetTextDisplay eingesetzt. -->
|
||||
<div id="phaseMemorize" class="d-none">
|
||||
<div class="card border-warning" style="border-left: 5px solid #ffd166; background-color: #fffbf0;">
|
||||
<div class="card-body text-center py-4">
|
||||
@ -43,7 +43,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 3: Eingabe -->
|
||||
<!-- Phase 3: Eingabe aus dem Gedaechtnis. Der Originaltext ist hier bewusst ausgeblendet. -->
|
||||
<div id="phaseInput" class="d-none">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@ -58,13 +58,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 4: Ergebnis -->
|
||||
<!-- Phase 4: Auswertung inklusive Backend-Feedback und Vergleich Original/Eingabe. -->
|
||||
<div id="phaseResult" class="d-none">
|
||||
<div class="card text-center" style="border-top: 5px solid #28a745;">
|
||||
<div class="card-body py-5">
|
||||
<h3 class="text-success mb-2">Ergebnis</h3>
|
||||
<div class="display-1 fw-bold my-4" id="resultScore" style="color: #4a6fa5;">0</div>
|
||||
<p class="text-muted mb-5">Punkte (korrekte Wörter an der richtigen Position)</p>
|
||||
<!-- Wird von saveScore() befuellt: gespeichert, nur lokal berechnet oder Fehler. -->
|
||||
<div id="scoreSaveFeedback" class="alert d-none mb-4" role="alert"></div>
|
||||
|
||||
<div class="row g-4 text-start mb-5">
|
||||
<div class="col-md-6">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user