Files
mindflux/src/main/resources/static/js/finalflux-test.js
T
AliceDarkest 9022961762 Volle Mindflux-App ins Deploy-Repo übernehmen
Ersetzt das Hello-World-Gerüst durch die vollständige Anwendung
(com.example.mindflux: 64 Klassen, Thymeleaf-Templates, Static-Assets,
Flyway V1–V6). Deploy-Infrastruktur (.gitea, Dockerfile) bleibt erhalten.

- pom: volle Abhängigkeiten (Security, Thymeleaf, JPA, Flyway), Spring Boot 3.4.4 / Java 17
- docker-compose: SPRING_DATASOURCE_* unverändert; App lauscht auf 8080
  (nginx -> mindflux:8080); Uploads-Volume; Admin-Passwörter via Gitea-Secrets
- Workflow: Deploy-Step injiziert MINDFLUX_ADMIN*_PASSWORD aus Secrets
- .dockerignore ergänzt; Hello-World (com.mindflux) und Test-Datei 'main' entfernt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 14:51:30 +02:00

180 lines
5.9 KiB
JavaScript

document.addEventListener('DOMContentLoaded', async () => {
const script = document.querySelector('script[data-questions-src]');
const testRoot = document.querySelector('[data-finalflux-test]');
if (!script || !testRoot) {
return;
}
const elements = {
questionCounter: testRoot.querySelector('[data-question-counter]'),
scoreCounter: testRoot.querySelector('[data-score-counter]'),
categoryTitle: testRoot.querySelector('[data-category-title]'),
categoryHint: testRoot.querySelector('[data-category-hint]'),
questionText: testRoot.querySelector('[data-question-text]'),
answerOptions: testRoot.querySelector('[data-answer-options]'),
answerFeedback: testRoot.querySelector('[data-answer-feedback]'),
checkAnswer: testRoot.querySelector('[data-check-answer]'),
skipQuestion: testRoot.querySelector('[data-skip-question]'),
nextQuestion: testRoot.querySelector('[data-next-question]'),
testResult: document.querySelector('[data-test-result]'),
resultSummary: document.querySelector('[data-result-summary]'),
categorySummary: document.querySelector('[data-category-summary]'),
restartTest: document.querySelector('[data-restart-test]')
};
let questions = [];
let currentIndex = 0;
let score = 0;
let answered = false;
const categoryStats = new Map();
function setError(message) {
elements.questionText.textContent = message;
elements.answerOptions.innerHTML = '';
elements.checkAnswer.disabled = true;
elements.skipQuestion.disabled = true;
elements.nextQuestion.disabled = true;
}
function ensureCategory(category) {
if (!categoryStats.has(category)) {
categoryStats.set(category, { correct: 0, total: 0, skipped: 0 });
}
return categoryStats.get(category);
}
function renderQuestion() {
const question = questions[currentIndex];
answered = false;
elements.questionCounter.textContent = `Frage ${currentIndex + 1} von ${questions.length}`;
elements.scoreCounter.textContent = `${score} richtig`;
elements.categoryTitle.textContent = question.category;
elements.categoryHint.textContent = question.hint || '';
elements.questionText.textContent = question.text;
elements.answerFeedback.textContent = '';
elements.answerFeedback.className = 'fluxcheck-result';
elements.nextQuestion.disabled = true;
elements.checkAnswer.disabled = false;
elements.skipQuestion.disabled = false;
elements.answerOptions.innerHTML = '';
question.answers.forEach((answer, index) => {
const label = document.createElement('label');
const input = document.createElement('input');
const text = document.createElement('span');
input.type = 'radio';
input.name = 'answer';
input.value = String(index);
text.textContent = answer;
label.append(input, text);
elements.answerOptions.append(label);
});
}
function markAnswered(isCorrect, skipped) {
const question = questions[currentIndex];
const stats = ensureCategory(question.category);
stats.total += 1;
if (skipped) {
stats.skipped += 1;
}
if (isCorrect) {
stats.correct += 1;
score += 1;
}
}
function finishIfDone() {
if (currentIndex < questions.length - 1) {
currentIndex += 1;
renderQuestion();
return;
}
testRoot.hidden = true;
elements.testResult.hidden = false;
elements.resultSummary.textContent = `Du hast ${score} von ${questions.length} Fragen richtig beantwortet.`;
elements.categorySummary.innerHTML = '';
Array.from(categoryStats.entries()).forEach(([category, stats]) => {
const skipped = stats.skipped ? `, ${stats.skipped} übersprungen` : '';
const item = document.createElement('li');
const categoryLabel = document.createElement('strong');
categoryLabel.textContent = `${category}:`;
item.append(categoryLabel, ` ${stats.correct} von ${stats.total} richtig${skipped}`);
elements.categorySummary.append(item);
});
}
elements.checkAnswer.addEventListener('click', () => {
if (answered) {
return;
}
const question = questions[currentIndex];
const selected = elements.answerOptions.querySelector('input[type="radio"]:checked');
if (!selected) {
elements.answerFeedback.textContent = 'Wähle zuerst eine Antwort aus oder überspringe die Frage.';
elements.answerFeedback.className = 'fluxcheck-result wrong';
return;
}
const isCorrect = Number(selected.value) === question.correct;
markAnswered(isCorrect, false);
answered = true;
elements.answerFeedback.textContent = (isCorrect ? 'Richtig. ' : 'Noch nicht. ') + question.explanation;
elements.answerFeedback.className = 'fluxcheck-result ' + (isCorrect ? 'correct' : 'wrong');
elements.scoreCounter.textContent = `${score} richtig`;
elements.nextQuestion.disabled = false;
elements.checkAnswer.disabled = true;
elements.skipQuestion.disabled = true;
});
elements.skipQuestion.addEventListener('click', () => {
if (!answered) {
markAnswered(false, true);
}
finishIfDone();
});
elements.nextQuestion.addEventListener('click', finishIfDone);
elements.restartTest.addEventListener('click', () => {
currentIndex = 0;
score = 0;
categoryStats.clear();
testRoot.hidden = false;
elements.testResult.hidden = true;
renderQuestion();
});
try {
const response = await fetch(script.dataset.questionsSrc);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const payload = await response.json();
questions = Array.isArray(payload) ? payload : payload.questions;
if (!Array.isArray(questions) || questions.length === 0) {
setError('Dieser Fragenkatalog enthält noch keine Fragen.');
return;
}
renderQuestion();
} catch (error) {
console.error(error);
setError('Der Fragenkatalog konnte nicht geladen werden.');
}
});