A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
315 lines
8.3 KiB
HTML
315 lines
8.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Fill in the Blanks Player - BreakPilot H5P</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
background: #f5f5f5;
|
|
padding: 20px;
|
|
min-height: 100vh;
|
|
}
|
|
.container {
|
|
background: white;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
padding: 30px;
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
}
|
|
h1 {
|
|
color: #333;
|
|
margin-bottom: 12px;
|
|
font-size: 28px;
|
|
}
|
|
.instructions {
|
|
color: #6b7280;
|
|
margin-bottom: 32px;
|
|
font-size: 16px;
|
|
}
|
|
.text-container {
|
|
font-size: 18px;
|
|
line-height: 2;
|
|
color: #1f2937;
|
|
margin-bottom: 32px;
|
|
}
|
|
.blank-input {
|
|
display: inline-block;
|
|
border: none;
|
|
border-bottom: 2px solid #9ca3af;
|
|
background: #f9fafb;
|
|
padding: 4px 12px;
|
|
font-size: 18px;
|
|
font-family: inherit;
|
|
min-width: 120px;
|
|
text-align: center;
|
|
transition: all 0.2s;
|
|
}
|
|
.blank-input:focus {
|
|
outline: none;
|
|
border-bottom-color: #667eea;
|
|
background: white;
|
|
}
|
|
.blank-input.correct {
|
|
border-bottom-color: #10b981;
|
|
background: #d1fae5;
|
|
color: #065f46;
|
|
}
|
|
.blank-input.incorrect {
|
|
border-bottom-color: #ef4444;
|
|
background: #fee2e2;
|
|
color: #991b1b;
|
|
}
|
|
.blank-input:disabled {
|
|
cursor: not-allowed;
|
|
}
|
|
.btn {
|
|
padding: 12px 24px;
|
|
border: none;
|
|
border-radius: 6px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
transition: all 0.2s;
|
|
}
|
|
.btn-primary {
|
|
background: #667eea;
|
|
color: white;
|
|
}
|
|
.btn-primary:hover {
|
|
background: #5568d3;
|
|
}
|
|
.btn-primary:disabled {
|
|
background: #9ca3af;
|
|
cursor: not-allowed;
|
|
}
|
|
.btn-secondary {
|
|
background: #e5e7eb;
|
|
color: #374151;
|
|
}
|
|
.btn-secondary:hover {
|
|
background: #d1d5db;
|
|
}
|
|
.btn-group {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-top: 24px;
|
|
}
|
|
.results {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
border-radius: 12px;
|
|
padding: 32px;
|
|
text-align: center;
|
|
margin-bottom: 24px;
|
|
display: none;
|
|
}
|
|
.results h2 {
|
|
font-size: 32px;
|
|
margin-bottom: 16px;
|
|
}
|
|
.results .score {
|
|
font-size: 64px;
|
|
font-weight: 700;
|
|
margin: 20px 0;
|
|
}
|
|
.feedback {
|
|
background: #f0f9ff;
|
|
border-left: 4px solid #3b82f6;
|
|
padding: 16px;
|
|
margin-bottom: 24px;
|
|
border-radius: 4px;
|
|
display: none;
|
|
}
|
|
.feedback.show {
|
|
display: block;
|
|
}
|
|
.feedback.correct {
|
|
background: #d1fae5;
|
|
border-color: #10b981;
|
|
color: #065f46;
|
|
}
|
|
.feedback.incorrect {
|
|
background: #fee2e2;
|
|
border-color: #ef4444;
|
|
color: #991b1b;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1 id="title"></h1>
|
|
<p class="instructions" id="instructions"></p>
|
|
|
|
<div class="results" id="results">
|
|
<h2>🎉 Fertig!</h2>
|
|
<div class="score" id="scoreDisplay"></div>
|
|
<p id="resultMessage"></p>
|
|
</div>
|
|
|
|
<div class="feedback" id="feedback"></div>
|
|
|
|
<div class="text-container" id="textContainer"></div>
|
|
|
|
<div class="btn-group">
|
|
<button class="btn btn-primary" id="checkBtn" onclick="checkAnswers()">
|
|
Antworten überprüfen
|
|
</button>
|
|
<button class="btn btn-secondary" id="showBtn" onclick="showSolution()" style="display: none;">
|
|
Lösung anzeigen
|
|
</button>
|
|
<button class="btn btn-secondary" id="retryBtn" onclick="retry()" style="display: none;">
|
|
Nochmal versuchen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let data = null;
|
|
let userAnswers = [];
|
|
let isChecked = false;
|
|
|
|
function loadContent() {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const dataParam = urlParams.get('data');
|
|
|
|
if (dataParam) {
|
|
try {
|
|
data = JSON.parse(decodeURIComponent(dataParam));
|
|
} catch (e) {
|
|
alert('Fehler beim Laden!');
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!data) {
|
|
alert('Keine Daten gefunden!');
|
|
return;
|
|
}
|
|
|
|
document.getElementById('title').textContent = data.title;
|
|
document.getElementById('instructions').textContent = data.instructions || 'Fülle die Lücken aus.';
|
|
|
|
renderText();
|
|
}
|
|
|
|
function renderText() {
|
|
const container = document.getElementById('textContainer');
|
|
let text = data.text;
|
|
let blankIndex = 0;
|
|
|
|
// Replace *word* with input fields
|
|
const html = text.replace(/\*([^*]+)\*/g, (match, word) => {
|
|
const inputId = `blank_${blankIndex}`;
|
|
blankIndex++;
|
|
return `<input type="text" class="blank-input" id="${inputId}" data-answer="${word}" />`;
|
|
});
|
|
|
|
container.innerHTML = html;
|
|
|
|
// Initialize userAnswers array
|
|
userAnswers = new Array(blankIndex).fill('');
|
|
|
|
// Add event listeners
|
|
document.querySelectorAll('.blank-input').forEach((input, index) => {
|
|
input.addEventListener('input', (e) => {
|
|
userAnswers[index] = e.target.value;
|
|
});
|
|
});
|
|
}
|
|
|
|
function checkAnswers() {
|
|
if (isChecked) return;
|
|
isChecked = true;
|
|
|
|
let correct = 0;
|
|
const inputs = document.querySelectorAll('.blank-input');
|
|
|
|
inputs.forEach((input) => {
|
|
const correctAnswer = input.dataset.answer.toLowerCase().trim();
|
|
const userAnswer = input.value.toLowerCase().trim();
|
|
|
|
input.disabled = true;
|
|
|
|
if (userAnswer === correctAnswer) {
|
|
input.classList.add('correct');
|
|
correct++;
|
|
} else {
|
|
input.classList.add('incorrect');
|
|
}
|
|
});
|
|
|
|
const total = inputs.length;
|
|
const percentage = Math.round((correct / total) * 100);
|
|
|
|
// Show feedback
|
|
const feedback = document.getElementById('feedback');
|
|
if (correct === total) {
|
|
feedback.className = 'feedback correct show';
|
|
feedback.textContent = `🎉 Perfekt! Alle ${total} Lücken richtig ausgefüllt!`;
|
|
} else {
|
|
feedback.className = 'feedback incorrect show';
|
|
feedback.textContent = `Du hast ${correct} von ${total} Lücken richtig ausgefüllt (${percentage}%).`;
|
|
}
|
|
|
|
// Update buttons
|
|
document.getElementById('checkBtn').style.display = 'none';
|
|
document.getElementById('showBtn').style.display = 'inline-block';
|
|
document.getElementById('retryBtn').style.display = 'inline-block';
|
|
|
|
// Show results
|
|
if (correct === total) {
|
|
setTimeout(() => {
|
|
showResults(correct, total);
|
|
}, 1500);
|
|
}
|
|
}
|
|
|
|
function showSolution() {
|
|
const inputs = document.querySelectorAll('.blank-input');
|
|
inputs.forEach((input) => {
|
|
input.value = input.dataset.answer;
|
|
input.classList.remove('incorrect');
|
|
input.classList.add('correct');
|
|
});
|
|
|
|
const feedback = document.getElementById('feedback');
|
|
feedback.className = 'feedback show';
|
|
feedback.textContent = '💡 Hier ist die vollständige Lösung.';
|
|
}
|
|
|
|
function retry() {
|
|
isChecked = false;
|
|
userAnswers = [];
|
|
|
|
const inputs = document.querySelectorAll('.blank-input');
|
|
inputs.forEach((input) => {
|
|
input.value = '';
|
|
input.disabled = false;
|
|
input.classList.remove('correct', 'incorrect');
|
|
});
|
|
|
|
document.getElementById('feedback').classList.remove('show');
|
|
document.getElementById('results').style.display = 'none';
|
|
|
|
document.getElementById('checkBtn').style.display = 'inline-block';
|
|
document.getElementById('showBtn').style.display = 'none';
|
|
document.getElementById('retryBtn').style.display = 'none';
|
|
}
|
|
|
|
function showResults(correct, total) {
|
|
const percentage = Math.round((correct / total) * 100);
|
|
|
|
document.getElementById('scoreDisplay').textContent = `${correct} / ${total}`;
|
|
document.getElementById('resultMessage').textContent = `${percentage}% richtig!`;
|
|
document.getElementById('results').style.display = 'block';
|
|
}
|
|
|
|
loadContent();
|
|
</script>
|
|
</body>
|
|
</html>
|