"""
BreakPilot Studio - Lerneinheiten/Arbeitsblaetter Modul
Refactored: 2024-12-18
- Kachel-basierte Startansicht
- Sub-Module fuer verschiedene Funktionen
Funktionen (als Kacheln):
- Lerneinheiten erstellen und verwalten
- Dateien hochladen
- Dateien bereinigen (OCR, Neuaufbau)
- Lernflows (Interaktive Uebungen)
- Multiple Choice Tests
- Lueckentexte
- Mindmap Generator
- Uebersetzungen
"""
class WorksheetsModule:
"""Modul fuer Lerneinheiten und Arbeitsblaetter."""
@staticmethod
def get_css() -> str:
"""CSS fuer das Worksheets-Modul."""
return """
/* =============================================
WORKSHEETS MODULE - Lerneinheiten & Arbeitsblaetter
============================================= */
/* Panel Layout */
.panel-worksheets {
display: none;
flex-direction: column;
height: 100%;
background: var(--bp-bg);
overflow: hidden;
}
.panel-worksheets.active {
display: flex;
}
/* Worksheets Header */
.worksheets-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 32px;
border-bottom: 1px solid var(--bp-border);
background: var(--bp-surface);
}
.worksheets-title-section h1 {
font-size: 24px;
font-weight: 700;
color: var(--bp-text);
margin-bottom: 4px;
}
.worksheets-subtitle {
font-size: 14px;
color: var(--bp-text-muted);
}
.worksheets-nav {
display: flex;
gap: 8px;
}
.worksheets-nav-btn {
padding: 8px 16px;
border-radius: 8px;
border: 1px solid var(--bp-border);
background: var(--bp-surface);
color: var(--bp-text-muted);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.worksheets-nav-btn:hover {
background: var(--bp-surface-elevated);
color: var(--bp-text);
}
.worksheets-nav-btn.active {
background: var(--bp-primary);
border-color: var(--bp-primary);
color: white;
}
/* Worksheets Content - Kacheln */
.worksheets-content {
flex: 1;
overflow-y: auto;
padding: 32px;
}
/* Tiles Grid */
.worksheets-tiles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
max-width: 1400px;
margin: 0 auto;
}
/* Section Header */
.tiles-section {
margin-bottom: 32px;
}
.tiles-section-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.tiles-section-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
}
.tiles-section-icon.create { background: rgba(59, 130, 246, 0.15); }
.tiles-section-icon.process { background: rgba(16, 185, 129, 0.15); }
.tiles-section-icon.generate { background: rgba(245, 158, 11, 0.15); }
.tiles-section-icon.translate { background: rgba(139, 92, 246, 0.15); }
.tiles-section-title {
font-size: 16px;
font-weight: 600;
color: var(--bp-text);
}
.tiles-section-desc {
font-size: 13px;
color: var(--bp-text-muted);
}
/* Worksheet Tile */
.worksheet-tile {
background: var(--bp-surface);
border: 1px solid var(--bp-border);
border-radius: 16px;
padding: 24px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.worksheet-tile:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
border-color: var(--bp-primary);
}
.worksheet-tile::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--bp-primary);
opacity: 0;
transition: opacity 0.3s;
}
.worksheet-tile:hover::before {
opacity: 1;
}
.tile-icon-container {
width: 56px;
height: 56px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
margin-bottom: 16px;
}
/* Icon Colors */
.tile-icon-container.blue { background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); }
.tile-icon-container.green { background: linear-gradient(135deg, #10b981 0%, #059669 100%); }
.tile-icon-container.orange { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); }
.tile-icon-container.purple { background: linear-gradient(135deg, #8b5cf6 0%, #6d28d9 100%); }
.tile-icon-container.red { background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); }
.tile-icon-container.cyan { background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%); }
.tile-icon-container.pink { background: linear-gradient(135deg, #ec4899 0%, #be185d 100%); }
.tile-icon-container.teal { background: linear-gradient(135deg, #14b8a6 0%, #0d9488 100%); }
.tile-title {
font-size: 16px;
font-weight: 600;
color: var(--bp-text);
margin-bottom: 8px;
}
.tile-description {
font-size: 13px;
color: var(--bp-text-muted);
line-height: 1.5;
margin-bottom: 16px;
}
.tile-features {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.tile-feature-tag {
padding: 4px 10px;
background: var(--bp-bg);
border-radius: 12px;
font-size: 11px;
color: var(--bp-text-muted);
}
.tile-arrow {
position: absolute;
bottom: 20px;
right: 20px;
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--bp-bg);
display: flex;
align-items: center;
justify-content: center;
color: var(--bp-text-muted);
transition: all 0.3s;
}
.worksheet-tile:hover .tile-arrow {
background: var(--bp-primary);
color: white;
transform: translateX(4px);
}
/* Sub-Panel (hidden by default, shown when tile clicked) */
.worksheets-subpanel {
display: none;
flex-direction: column;
height: 100%;
}
.worksheets-subpanel.active {
display: flex;
}
.subpanel-header {
display: flex;
align-items: center;
gap: 16px;
padding: 16px 24px;
border-bottom: 1px solid var(--bp-border);
background: var(--bp-surface);
}
.subpanel-back {
width: 36px;
height: 36px;
border-radius: 8px;
border: 1px solid var(--bp-border);
background: var(--bp-bg);
color: var(--bp-text);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
transition: all 0.2s;
}
.subpanel-back:hover {
background: var(--bp-surface-elevated);
}
.subpanel-title {
font-size: 18px;
font-weight: 600;
}
.subpanel-content {
flex: 1;
overflow-y: auto;
padding: 24px;
}
/* Status Bar */
.worksheets-status {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 24px;
border-top: 1px solid var(--bp-border);
background: var(--bp-surface);
font-size: 12px;
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: #10b981;
}
.status-indicator.busy {
background: #f59e0b;
animation: statusPulse 1.5s infinite;
}
.status-indicator.error {
background: #ef4444;
}
@keyframes statusPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.status-text {
color: var(--bp-text);
}
.status-detail {
color: var(--bp-text-muted);
}
/* ============================================
SUB-MODULE STYLES: Lerneinheiten Manager
============================================ */
.units-manager {
display: grid;
grid-template-columns: 320px 1fr;
gap: 24px;
height: 100%;
}
.units-sidebar {
background: var(--bp-surface);
border: 1px solid var(--bp-border);
border-radius: 12px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.units-form {
padding: 16px;
border-bottom: 1px solid var(--bp-border);
}
.units-form h3 {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
color: var(--bp-text-muted);
}
.units-form input {
width: 100%;
padding: 10px 12px;
margin-bottom: 8px;
border: 1px solid var(--bp-border);
border-radius: 8px;
background: var(--bp-bg);
color: var(--bp-text);
font-size: 13px;
}
.units-form input:focus {
outline: none;
border-color: var(--bp-primary);
}
.units-form .form-row {
display: flex;
gap: 8px;
}
.units-form .form-row input {
flex: 1;
}
.units-list {
flex: 1;
overflow-y: auto;
padding: 8px;
}
.unit-list-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
margin-bottom: 4px;
}
.unit-list-item:hover {
background: var(--bp-bg);
}
.unit-list-item.selected {
background: var(--bp-primary);
color: white;
}
.unit-info {
flex: 1;
min-width: 0;
}
.unit-name {
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.unit-meta {
font-size: 11px;
opacity: 0.7;
margin-top: 2px;
}
.unit-delete {
opacity: 0;
cursor: pointer;
padding: 4px;
font-size: 12px;
}
.unit-list-item:hover .unit-delete {
opacity: 0.6;
}
.unit-list-item:hover .unit-delete:hover {
opacity: 1;
color: #ef4444;
}
.units-main {
background: var(--bp-surface);
border: 1px solid var(--bp-border);
border-radius: 12px;
padding: 24px;
overflow-y: auto;
}
.units-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
text-align: center;
color: var(--bp-text-muted);
}
.units-empty-icon {
font-size: 48px;
margin-bottom: 16px;
opacity: 0.5;
}
/* ============================================
SUB-MODULE STYLES: File Upload
============================================ */
.upload-container {
max-width: 800px;
margin: 0 auto;
}
.upload-drop-zone {
border: 2px dashed var(--bp-border);
border-radius: 16px;
padding: 48px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background: var(--bp-surface);
}
.upload-drop-zone:hover,
.upload-drop-zone.dragover {
border-color: var(--bp-primary);
background: rgba(59, 130, 246, 0.05);
}
.upload-icon {
font-size: 48px;
margin-bottom: 16px;
}
.upload-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
}
.upload-hint {
font-size: 14px;
color: var(--bp-text-muted);
margin-bottom: 16px;
}
.upload-formats {
font-size: 12px;
color: var(--bp-text-muted);
padding: 8px 16px;
background: var(--bp-bg);
border-radius: 20px;
display: inline-block;
}
.upload-progress {
margin-top: 24px;
padding: 16px;
background: var(--bp-bg);
border-radius: 12px;
}
.upload-file-item {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 0;
}
.upload-file-name {
flex: 1;
font-size: 13px;
}
.upload-file-status {
font-size: 12px;
color: var(--bp-text-muted);
}
/* ============================================
SUB-MODULE STYLES: Generator Tiles
============================================ */
.generator-options {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
margin-top: 24px;
}
.generator-option {
padding: 20px;
background: var(--bp-surface);
border: 1px solid var(--bp-border);
border-radius: 12px;
cursor: pointer;
transition: all 0.2s;
text-align: center;
}
.generator-option:hover {
border-color: var(--bp-primary);
transform: translateY(-2px);
}
.generator-option.selected {
border-color: var(--bp-primary);
background: rgba(59, 130, 246, 0.05);
}
.generator-option-icon {
font-size: 32px;
margin-bottom: 8px;
}
.generator-option-title {
font-weight: 600;
margin-bottom: 4px;
}
.generator-option-desc {
font-size: 12px;
color: var(--bp-text-muted);
}
/* ============================================
Legacy Support: Original 3-Column Layout
============================================ */
/* Linke Spalte - Lerneinheiten */
.worksheets-units-panel {
width: 280px;
border-right: 1px solid var(--bp-border);
display: flex;
flex-direction: column;
background: var(--bp-surface);
}
.units-header {
padding: 16px;
border-bottom: 1px solid var(--bp-border);
}
.units-header h3 {
font-size: 14px;
font-weight: 600;
color: var(--bp-text-muted);
margin-bottom: 12px;
}
/* Mittlere Spalte - Dateiliste */
.worksheets-files-panel {
width: 260px;
border-right: 1px solid var(--bp-border);
display: flex;
flex-direction: column;
background: var(--bp-bg);
}
.files-header {
padding: 12px 16px;
border-bottom: 1px solid var(--bp-border);
display: flex;
justify-content: space-between;
align-items: center;
}
.files-list {
flex: 1;
overflow-y: auto;
padding: 8px;
}
.file-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
margin-bottom: 2px;
border-radius: 6px;
cursor: pointer;
transition: background 0.2s;
}
.file-item:hover {
background: var(--bp-surface);
}
.file-item.active {
background: var(--bp-primary);
color: white;
}
/* Rechte Spalte - Preview */
.worksheets-preview-panel {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Compare Wrapper */
.compare-wrapper {
flex: 1;
display: flex;
gap: 16px;
padding: 16px;
overflow: hidden;
}
.compare-section {
flex: 1;
display: flex;
flex-direction: column;
border-radius: 12px;
overflow: hidden;
background: var(--bp-surface);
border: 1px solid var(--bp-border);
}
.compare-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 16px;
background: var(--bp-bg);
border-bottom: 1px solid var(--bp-border);
font-size: 13px;
font-weight: 500;
}
.compare-body {
flex: 1;
overflow: auto;
padding: 16px;
display: flex;
justify-content: center;
align-items: flex-start;
}
.preview-img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 4px;
cursor: zoom-in;
}
/* Lightbox */
.lightbox {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.9);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10000;
padding: 20px;
}
.lightbox.hidden {
display: none;
}
.lightbox-close {
position: absolute;
top: 20px;
right: 20px;
font-size: 32px;
color: white;
cursor: pointer;
opacity: 0.7;
transition: opacity 0.2s;
}
.lightbox-close:hover {
opacity: 1;
}
.lightbox-img {
max-width: 95%;
max-height: 85%;
object-fit: contain;
}
.lightbox-caption {
margin-top: 16px;
color: rgba(255, 255, 255, 0.7);
font-size: 14px;
}
"""
@staticmethod
def get_html() -> str:
"""HTML fuer das Worksheets-Modul mit Kachel-basierter Startansicht."""
return """
📚
Lerneinheiten
Erstelle und verwalte Lerneinheiten fuer deine Schueler. Ordne Materialien zu und verfolge den Fortschritt.
CRUD
Organisation
→
📤
Dateien hochladen
Lade Arbeitsblaetter, Bilder und PDFs hoch. Unterstuetzt Drag & Drop und Batch-Upload.
PDF
Bilder
Batch
→
🔧
Dateien bereinigen
OCR-Verarbeitung und automatischer Neuaufbau von gescannten Arbeitsblaettern.
OCR
Neuaufbau
AI
→
🎯
Lernflows
Interaktive Lernpfade erstellen. Kombiniere verschiedene Aufgabentypen zu einem Flow.
Interaktiv
Sequenzen
→
✅
Multiple Choice
Generiere Multiple-Choice-Tests aus deinen Lernmaterialien. Inkl. Antwortschluessel.
Tests
AI
Druckbar
→
📝
Lueckentexte
Erstelle Lueckentexte fuer effektives Vokabel- und Faktenlernen.
Uebung
AI
Druckbar
→
🗺
Mindmap
Visualisiere Zusammenhaenge in einer uebersichtlichen Mindmap.
Visualisierung
AI
→
❓
Fragen & Antworten
Generiere Fragenkataloge und Lernkarten aus deinen Materialien.
Lernkarten
AI
→
🗣
Uebersetzungen
Uebersetze Arbeitsblaetter und generierte Inhalte in verschiedene Sprachen.
DE
EN
TR
AR
+10
→
📚
Lerneinheit auswaehlen
Waehle eine Lerneinheit aus der Liste oder erstelle eine neue.
📤
Dateien hochladen
Dateien hierher ziehen oder klicken zum Auswaehlen
PDF, JPG, PNG - max. 50MB pro Datei
Waehle Dateien aus einer Lerneinheit und starte den OCR-Neuaufbau.
Generiere Multiple-Choice-Tests aus deinen Lernmaterialien.
🌟
Einfach
5 Fragen, grundlegend
💪
Mittel
10 Fragen, ausgewogen
🔥
Schwer
15 Fragen, anspruchsvoll
Erstelle Lueckentexte aus deinen Lernmaterialien.
Erstelle eine visuelle Mindmap aus deinen Lernmaterialien.
Generiere Fragen und Antworten fuer Lernkarten.
Erstelle interaktive Lernpfade aus verschiedenen Aufgabentypen.
Uebersetze deine Materialien in verschiedene Sprachen.
Bereit
×
"""
@staticmethod
def get_js() -> str:
"""JavaScript fuer das Worksheets-Modul."""
return """
// =============================================
// WORKSHEETS MODULE - Refactored with Tiles
// =============================================
let worksheetsInitialized = false;
let worksheetsUnits = [];
let worksheetsCurrentUnit = null;
function loadWorksheetsModule() {
if (worksheetsInitialized) {
console.log('Worksheets module already initialized');
return;
}
console.log('Loading Worksheets Module (Tiles)...');
// Initialize upload zone
initWorksheetsUpload();
// Load units
loadWorksheetsUnits();
// Init lightbox
initWorksheetsLightbox();
worksheetsInitialized = true;
console.log('Worksheets Module loaded successfully');
}
// =============================================
// VIEW SWITCHING
// =============================================
function showWorksheetsTiles() {
document.getElementById('worksheets-tiles-view').style.display = 'block';
closeWorksheetsSubpanel();
document.querySelectorAll('.worksheets-nav-btn').forEach(btn => btn.classList.remove('active'));
document.querySelector('.worksheets-nav-btn').classList.add('active');
}
function showWorksheetsManager() {
openWorksheetsSubpanel('units');
document.querySelectorAll('.worksheets-nav-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.worksheets-nav-btn')[1].classList.add('active');
}
// =============================================
// SUBPANEL NAVIGATION
// =============================================
function openWorksheetsSubpanel(panelId) {
// Hide tiles view
document.getElementById('worksheets-tiles-view').style.display = 'none';
// Hide all subpanels
document.querySelectorAll('.worksheets-subpanel').forEach(p => {
p.classList.remove('active');
});
// Show selected subpanel
const panel = document.getElementById('worksheets-subpanel-' + panelId);
if (panel) {
panel.classList.add('active');
}
}
function closeWorksheetsSubpanel() {
document.querySelectorAll('.worksheets-subpanel').forEach(p => {
p.classList.remove('active');
});
document.getElementById('worksheets-tiles-view').style.display = 'block';
// Reset nav buttons
document.querySelectorAll('.worksheets-nav-btn').forEach(btn => btn.classList.remove('active'));
document.querySelector('.worksheets-nav-btn').classList.add('active');
}
// =============================================
// STATUS
// =============================================
function setWorksheetsStatus(text, detail = '', state = 'idle') {
const indicator = document.getElementById('ws-status-indicator');
const textEl = document.getElementById('ws-status-text');
const detailEl = document.getElementById('ws-status-detail');
if (textEl) textEl.textContent = text;
if (detailEl) detailEl.textContent = detail;
if (indicator) {
indicator.classList.remove('busy', 'error');
if (state === 'busy') indicator.classList.add('busy');
else if (state === 'error') indicator.classList.add('error');
}
}
// =============================================
// LERNEINHEITEN
// =============================================
async function loadWorksheetsUnits() {
try {
const resp = await fetch('/api/learning-units/');
if (!resp.ok) {
console.error('Failed to load units');
return;
}
worksheetsUnits = await resp.json();
renderWorksheetsUnits();
} catch (e) {
console.error('Error loading units:', e);
}
}
function renderWorksheetsUnits() {
const container = document.getElementById('units-list-container');
if (!container) return;
if (!worksheetsUnits.length) {
container.innerHTML = 'Keine Lerneinheiten vorhanden
';
return;
}
container.innerHTML = worksheetsUnits.map(unit => `
${unit.label || unit.title || 'Lerneinheit'}
${unit.subject || ''} ${unit.grade || ''} - ${(unit.worksheet_files || []).length} Dateien
🗑
`).join('');
}
function selectWorksheetsUnit(unitId) {
worksheetsCurrentUnit = worksheetsUnits.find(u => u.id === unitId);
renderWorksheetsUnits();
showUnitDetail();
}
function showUnitDetail() {
const container = document.getElementById('units-detail-container');
if (!container || !worksheetsCurrentUnit) return;
const unit = worksheetsCurrentUnit;
const files = unit.worksheet_files || [];
container.innerHTML = `
${unit.label || unit.title}
${unit.student_name ? 'Schueler: ' + unit.student_name + ' | ' : ''}
${unit.subject || ''} ${unit.grade || ''}
Zugeordnete Dateien (${files.length})
${files.length ? `
${files.map(f => `
${f}
✕
`).join('')}
` : 'Keine Dateien zugeordnet
'}
`;
}
async function createNewUnit() {
const student = document.getElementById('new-unit-student')?.value.trim() || '';
const subject = document.getElementById('new-unit-subject')?.value.trim() || '';
const grade = document.getElementById('new-unit-grade')?.value.trim() || '';
const title = document.getElementById('new-unit-title')?.value.trim() || '';
if (!title) {
alert('Bitte einen Titel eingeben');
return;
}
try {
setWorksheetsStatus('Erstelle Lerneinheit...', '', 'busy');
const resp = await fetch('/api/learning-units/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
label: title,
student_name: student,
subject: subject,
grade: grade,
title: title
})
});
if (!resp.ok) {
throw new Error('Failed to create unit');
}
const newUnit = await resp.json();
worksheetsUnits.push(newUnit);
worksheetsCurrentUnit = newUnit;
// Clear form
['new-unit-student', 'new-unit-subject', 'new-unit-grade', 'new-unit-title'].forEach(id => {
const el = document.getElementById(id);
if (el) el.value = '';
});
renderWorksheetsUnits();
showUnitDetail();
setWorksheetsStatus('Lerneinheit erstellt', '');
} catch (e) {
console.error(e);
setWorksheetsStatus('Fehler', String(e), 'error');
}
}
async function deleteWorksheetsUnit(unitId) {
if (!confirm('Lerneinheit wirklich loeschen?')) return;
try {
setWorksheetsStatus('Loesche Lerneinheit...', '', 'busy');
const resp = await fetch(`/api/learning-units/${unitId}`, { method: 'DELETE' });
if (!resp.ok) {
throw new Error('Failed to delete unit');
}
worksheetsUnits = worksheetsUnits.filter(u => u.id !== unitId);
if (worksheetsCurrentUnit?.id === unitId) {
worksheetsCurrentUnit = null;
}
renderWorksheetsUnits();
setWorksheetsStatus('Lerneinheit geloescht', '');
} catch (e) {
console.error(e);
setWorksheetsStatus('Fehler', String(e), 'error');
}
}
// =============================================
// FILE UPLOAD
// =============================================
function initWorksheetsUpload() {
const dropZone = document.getElementById('worksheets-upload-zone');
const fileInput = document.getElementById('worksheets-file-input');
if (!dropZone || !fileInput) return;
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('dragover');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('dragover');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('dragover');
if (e.dataTransfer.files.length) {
uploadWorksheetsFiles(e.dataTransfer.files);
}
});
fileInput.addEventListener('change', () => {
if (fileInput.files.length) {
uploadWorksheetsFiles(fileInput.files);
}
});
}
async function uploadWorksheetsFiles(files) {
const formData = new FormData();
for (const file of files) {
formData.append('files', file);
}
try {
setWorksheetsStatus('Lade hoch...', `${files.length} Datei(en)`, 'busy');
const resp = await fetch('/api/upload', {
method: 'POST',
body: formData
});
if (!resp.ok) {
throw new Error('Upload failed');
}
setWorksheetsStatus('Upload erfolgreich', `${files.length} Datei(en)`);
// If unit selected, offer to add files
if (worksheetsCurrentUnit) {
// Could auto-add here
}
} catch (e) {
console.error(e);
setWorksheetsStatus('Upload fehlgeschlagen', String(e), 'error');
}
}
// =============================================
// GENERATORS - Connected to /api/worksheets/
// =============================================
let generatorDifficulty = 'medium';
let generatorNumQuestions = 10;
let generatedContent = null;
function selectGeneratorOption(el, difficulty) {
document.querySelectorAll('.generator-option').forEach(o => o.classList.remove('selected'));
el.classList.add('selected');
generatorDifficulty = difficulty;
generatorNumQuestions = difficulty === 'easy' ? 5 : difficulty === 'medium' ? 10 : 15;
}
// Get source text from current unit or prompt user
async function getSourceText() {
if (worksheetsCurrentUnit && worksheetsCurrentUnit.worksheet_files?.length > 0) {
// In production: extract text from files via OCR/parser
// For now, prompt user for text input
const text = prompt('Gib den Quelltext ein (min. 50 Zeichen) oder fuege Inhalt aus deiner Lerneinheit ein:');
return text;
}
return prompt('Gib den Quelltext ein (min. 50 Zeichen):');
}
async function generateMC() {
const sourceText = await getSourceText();
if (!sourceText || sourceText.length < 50) {
alert('Bitte einen laengeren Text eingeben (mind. 50 Zeichen).');
return;
}
setWorksheetsStatus('Generiere MC-Test...', '', 'busy');
try {
const resp = await fetch('/api/worksheets/generate/multiple-choice', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
source_text: sourceText,
num_questions: generatorNumQuestions,
difficulty: generatorDifficulty,
topic: worksheetsCurrentUnit?.title || 'Lerneinheit',
subject: worksheetsCurrentUnit?.subject || null
})
});
const result = await resp.json();
if (!result.success) {
throw new Error(result.error || 'Generation failed');
}
generatedContent = result.content;
setWorksheetsStatus('MC-Test generiert', `${result.content.data.questions.length} Fragen`);
showGeneratedMC(result.content);
} catch (e) {
console.error(e);
setWorksheetsStatus('Generation fehlgeschlagen', String(e), 'error');
alert('Fehler bei der MC-Generierung: ' + e.message);
}
}
function showGeneratedMC(content) {
const questions = content.data.questions;
const container = document.querySelector('#worksheets-subpanel-mc .subpanel-content');
let html = `
Generierte Fragen (${questions.length})
`;
questions.forEach((q, i) => {
html += `
Frage ${i + 1}: ${q.question}
${q.options.map(opt => `
-
${opt.text} ${opt.is_correct ? '✓' : ''}
`).join('')}
`;
});
html += `
`;
container.innerHTML = html;
}
async function generateCloze() {
const sourceText = await getSourceText();
if (!sourceText || sourceText.length < 50) {
alert('Bitte einen laengeren Text eingeben (mind. 50 Zeichen).');
return;
}
setWorksheetsStatus('Generiere Lueckentext...', '', 'busy');
try {
const resp = await fetch('/api/worksheets/generate/cloze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
source_text: sourceText,
num_gaps: generatorDifficulty === 'easy' ? 3 : generatorDifficulty === 'medium' ? 5 : 8,
difficulty: generatorDifficulty,
cloze_type: 'fill_in',
topic: worksheetsCurrentUnit?.title || null
})
});
const result = await resp.json();
if (!result.success) {
throw new Error(result.error || 'Generation failed');
}
generatedContent = result.content;
setWorksheetsStatus('Lueckentext generiert', `${result.content.data.gaps.length} Luecken`);
showGeneratedCloze(result.content);
} catch (e) {
console.error(e);
setWorksheetsStatus('Generation fehlgeschlagen', String(e), 'error');
alert('Fehler bei der Lueckentext-Generierung: ' + e.message);
}
}
function showGeneratedCloze(content) {
const container = document.querySelector('#worksheets-subpanel-cloze .subpanel-content');
const clozeData = content.data;
let html = `
Generierter Lueckentext
${clozeData.text_with_gaps}
Loesungen:
${clozeData.gaps.map((g, i) => `
${i + 1}. ${g.answer}
`).join('')}
`;
container.innerHTML = html;
}
async function generateMindmap() {
const sourceText = await getSourceText();
if (!sourceText || sourceText.length < 50) {
alert('Bitte einen laengeren Text eingeben (mind. 50 Zeichen).');
return;
}
setWorksheetsStatus('Generiere Mindmap...', '', 'busy');
try {
const resp = await fetch('/api/worksheets/generate/mindmap', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
source_text: sourceText,
topic: worksheetsCurrentUnit?.title || 'Thema',
max_depth: 3
})
});
const result = await resp.json();
if (!result.success) {
throw new Error(result.error || 'Generation failed');
}
generatedContent = result.content;
setWorksheetsStatus('Mindmap generiert', `${result.content.data.mindmap.total_nodes} Knoten`);
showGeneratedMindmap(result.content);
} catch (e) {
console.error(e);
setWorksheetsStatus('Generation fehlgeschlagen', String(e), 'error');
alert('Fehler bei der Mindmap-Generierung: ' + e.message);
}
}
function showGeneratedMindmap(content) {
const container = document.querySelector('#worksheets-subpanel-mindmap .subpanel-content');
const mindmap = content.data.mindmap;
const mermaid = content.data.mermaid;
let html = `
Generierte Mindmap: ${mindmap.title}
Struktur:
${renderMindmapNode(mindmap.root)}
`;
container.innerHTML = html;
}
function renderMindmapNode(node, indent = 0) {
const padding = indent * 20;
let html = `
${indent > 0 ? '├─ ' : ''}${node.label}
`;
if (node.children) {
node.children.forEach(child => {
html += renderMindmapNode(child, indent + 1);
});
}
return html;
}
function copyMermaidCode() {
if (generatedContent?.data?.mermaid) {
navigator.clipboard.writeText(generatedContent.data.mermaid);
alert('Mermaid-Code in Zwischenablage kopiert!');
}
}
async function generateQA() {
const sourceText = await getSourceText();
if (!sourceText || sourceText.length < 50) {
alert('Bitte einen laengeren Text eingeben (mind. 50 Zeichen).');
return;
}
setWorksheetsStatus('Generiere Quiz...', '', 'busy');
try {
const resp = await fetch('/api/worksheets/generate/quiz', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
source_text: sourceText,
quiz_types: ['true_false', 'matching'],
num_items: generatorDifficulty === 'easy' ? 3 : 5,
difficulty: generatorDifficulty,
topic: worksheetsCurrentUnit?.title || null
})
});
const result = await resp.json();
if (!result.success) {
throw new Error(result.error || 'Generation failed');
}
generatedContent = result.content;
const totalItems = (result.content.data.true_false_questions?.length || 0) +
(result.content.data.matching_pairs?.length || 0);
setWorksheetsStatus('Quiz generiert', `${totalItems} Items`);
showGeneratedQuiz(result.content);
} catch (e) {
console.error(e);
setWorksheetsStatus('Generation fehlgeschlagen', String(e), 'error');
alert('Fehler bei der Quiz-Generierung: ' + e.message);
}
}
function showGeneratedQuiz(content) {
const container = document.querySelector('#worksheets-subpanel-qa .subpanel-content');
const quiz = content.data;
let html = `
Generiertes Quiz
`;
if (quiz.true_false_questions?.length > 0) {
html += `
Richtig/Falsch Fragen:
`;
quiz.true_false_questions.forEach((q, i) => {
html += `
${i + 1}. ${q.statement}
${q.is_true ? '✓ Richtig' : '✗ Falsch'}
`;
});
}
if (quiz.matching_pairs?.length > 0) {
html += `
Zuordnungsaufgaben:
`;
quiz.matching_pairs.forEach((p, i) => {
html += `
${p.left}
↔
${p.right}
`;
});
}
html += `
`;
container.innerHTML = html;
}
// Export functions
async function exportGeneratedContent(format) {
if (!generatedContent) {
alert('Kein generierter Inhalt vorhanden.');
return;
}
if (format === 'h5p' && generatedContent.h5p_format) {
// Download H5P format as JSON (real H5P package would need backend support)
const blob = new Blob([JSON.stringify(generatedContent.h5p_format, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `content_h5p_${generatedContent.id}.json`;
a.click();
URL.revokeObjectURL(url);
} else if (format === 'json') {
const blob = new Blob([JSON.stringify(generatedContent.data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `content_${generatedContent.content_type}_${generatedContent.id}.json`;
a.click();
URL.revokeObjectURL(url);
}
}
function printGeneratedContent() {
window.print();
}
function createLernflow() {
alert('Lernflow-Editor: Kombiniere mehrere Generatoren zu einem interaktiven Lernpfad. Kommt in einer spaeteren Version!');
}
function selectLanguage(lang) {
alert('Uebersetzung nach ' + lang.toUpperCase() + ': Diese Funktion wird mit DeepL/LLM-Integration umgesetzt. Kommt bald!');
}
// =============================================
// LIGHTBOX
// =============================================
function initWorksheetsLightbox() {
const lightbox = document.getElementById('lightbox');
const closeBtn = document.getElementById('lightbox-close');
if (closeBtn) {
closeBtn.addEventListener('click', closeLightbox);
}
if (lightbox) {
lightbox.addEventListener('click', (e) => {
if (e.target === lightbox) closeLightbox();
});
}
}
function openLightbox(src, caption) {
const lightbox = document.getElementById('lightbox');
const img = document.getElementById('lightbox-img');
const captionEl = document.getElementById('lightbox-caption');
if (!lightbox || !src) return;
img.src = src;
captionEl.textContent = caption || '';
lightbox.classList.remove('hidden');
}
function closeLightbox() {
const lightbox = document.getElementById('lightbox');
if (lightbox) lightbox.classList.add('hidden');
}
// =============================================
// SHOW PANEL
// =============================================
function showWorksheetsPanel() {
console.log('showWorksheetsPanel called');
hideAllPanels();
if (typeof hideStudioSubMenu === 'function') hideStudioSubMenu();
const panel = document.getElementById('panel-worksheets');
if (panel) {
panel.style.display = 'flex';
loadWorksheetsModule();
console.log('Worksheets panel shown');
} else {
console.error('panel-worksheets not found');
}
}
// Escape key to close subpanels
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeLightbox();
if (document.querySelector('.worksheets-subpanel.active')) {
closeWorksheetsSubpanel();
}
}
});
"""