/** * Main application logic for Scenar Creator SPA. */ window.currentDocument = null; let typeCounter = 1; let scheduleCounter = 1; /* --- Tab switching --- */ function switchTab(event, tabId) { document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); event.target.classList.add('active'); document.getElementById(tabId).classList.add('active'); } /* --- Status messages --- */ function showStatus(message, type) { const el = document.getElementById('statusMessage'); el.textContent = message; el.className = 'status-message ' + type; el.style.display = 'block'; setTimeout(() => { el.style.display = 'none'; }, 5000); } /* --- Type management --- */ function addTypeRow() { const container = document.getElementById('typesContainer'); const idx = typeCounter++; const div = document.createElement('div'); div.className = 'type-row'; div.setAttribute('data-index', idx); div.innerHTML = ` `; container.appendChild(div); updateTypeDatalist(); } function removeTypeRow(idx) { const row = document.querySelector(`.type-row[data-index="${idx}"]`); if (row) row.remove(); updateTypeDatalist(); } function updateTypeDatalist() { const datalist = document.getElementById('availableTypes'); datalist.innerHTML = ''; document.querySelectorAll('#typesContainer .type-row').forEach(row => { const nameInput = row.querySelector('input[name^="type_name_"]'); if (nameInput && nameInput.value.trim()) { const opt = document.createElement('option'); opt.value = nameInput.value.trim(); datalist.appendChild(opt); } }); } // Update datalist on type name changes document.getElementById('typesContainer').addEventListener('input', function (e) { if (e.target.name && e.target.name.startsWith('type_name_')) { updateTypeDatalist(); } }); /* --- Schedule management --- */ function addScheduleRow() { const tbody = document.getElementById('scheduleBody'); const idx = scheduleCounter++; const tr = document.createElement('tr'); tr.setAttribute('data-index', idx); tr.innerHTML = ` `; tbody.appendChild(tr); } function removeScheduleRow(idx) { const row = document.querySelector(`#scheduleBody tr[data-index="${idx}"]`); if (row) row.remove(); } /* --- Build ScenarioDocument from builder form --- */ function buildDocumentFromForm() { const title = document.getElementById('builderTitle').value.trim(); const detail = document.getElementById('builderDetail').value.trim(); if (!title || !detail) { throw new Error('Název akce a detail jsou povinné'); } // Collect types const programTypes = []; document.querySelectorAll('#typesContainer .type-row').forEach(row => { const code = row.querySelector('input[name^="type_name_"]').value.trim(); const desc = row.querySelector('input[name^="type_desc_"]').value.trim(); const color = row.querySelector('input[name^="type_color_"]').value; if (code) { programTypes.push({ code, description: desc, color }); } }); // Collect blocks const blocks = []; document.querySelectorAll('#scheduleBody tr').forEach(tr => { const inputs = tr.querySelectorAll('input'); const datum = inputs[0].value; const zacatek = inputs[1].value; const konec = inputs[2].value; const program = inputs[3].value.trim(); const typ = inputs[4].value.trim(); const garant = inputs[5].value.trim() || null; const poznamka = inputs[6].value.trim() || null; if (datum && zacatek && konec && program && typ) { blocks.push({ datum, zacatek, konec, program, typ, garant, poznamka }); } }); if (blocks.length === 0) { throw new Error('Přidejte alespoň jeden blok'); } return { version: "1.0", event: { title, detail }, program_types: programTypes, blocks }; } /* --- Handle builder form submit (Excel) --- */ async function handleBuild(event) { event.preventDefault(); try { const doc = buildDocumentFromForm(); const blob = await API.postBlob('/api/generate-excel', doc); API.downloadBlob(blob, 'scenar_timetable.xlsx'); showStatus('Excel vygenerován', 'success'); } catch (err) { showStatus('Chyba: ' + err.message, 'error'); } return false; } /* --- Handle builder PDF --- */ async function handleBuildPdf() { try { const doc = buildDocumentFromForm(); const blob = await API.postBlob('/api/generate-pdf', doc); API.downloadBlob(blob, 'scenar_timetable.pdf'); showStatus('PDF vygenerován', 'success'); } catch (err) { showStatus('Chyba: ' + err.message, 'error'); } } /* --- Handle Excel import --- */ async function handleImport(event) { event.preventDefault(); const form = document.getElementById('importForm'); const formData = new FormData(form); try { const result = await API.postFormData('/api/import-excel', formData); if (result.success && result.document) { window.currentDocument = result.document; showImportedDocument(result.document); if (result.warnings && result.warnings.length > 0) { showStatus('Import OK, warnings: ' + result.warnings.join('; '), 'success'); } else { showStatus('Excel importován', 'success'); } } else { showStatus('Import failed: ' + (result.errors || []).join('; '), 'error'); } } catch (err) { showStatus('Chyba importu: ' + err.message, 'error'); } return false; } /* --- Show imported document in editor --- */ function showImportedDocument(doc) { const area = document.getElementById('editorArea'); area.style.display = 'block'; // Info document.getElementById('importedInfo').innerHTML = `${doc.event.title} — ${doc.event.detail}`; // Types const typesHtml = doc.program_types.map((pt, i) => `
`).join(''); document.getElementById('importedTypesContainer').innerHTML = typesHtml; // Blocks const blocksHtml = doc.blocks.map(b => `
${b.datum} ${b.zacatek}–${b.konec} | ${b.program} [${b.typ}] ${b.garant || ''}
` ).join(''); document.getElementById('importedBlocksContainer').innerHTML = blocksHtml; } /* --- Get current document (with any edits from import editor) --- */ function getCurrentDocument() { if (!window.currentDocument) { throw new Error('No document loaded'); } // Update types from editor const typeRows = document.querySelectorAll('#importedTypesContainer .imported-type-row'); if (typeRows.length > 0) { window.currentDocument.program_types = Array.from(typeRows).map(row => ({ code: row.querySelector('[data-field="code"]').value.trim(), description: row.querySelector('[data-field="description"]').value.trim(), color: row.querySelector('[data-field="color"]').value, })); } return window.currentDocument; } /* --- Generate Excel from imported data --- */ async function generateExcelFromImport() { try { const doc = getCurrentDocument(); const blob = await API.postBlob('/api/generate-excel', doc); API.downloadBlob(blob, 'scenar_timetable.xlsx'); showStatus('Excel vygenerován', 'success'); } catch (err) { showStatus('Chyba: ' + err.message, 'error'); } } /* --- Generate PDF from imported data --- */ async function generatePdfFromImport() { try { const doc = getCurrentDocument(); const blob = await API.postBlob('/api/generate-pdf', doc); API.downloadBlob(blob, 'scenar_timetable.pdf'); showStatus('PDF vygenerován', 'success'); } catch (err) { showStatus('Chyba: ' + err.message, 'error'); } }