// ============================================================= // Schritt-Navigation // ============================================================= let currentStep = 0; const steps = Array.from(document.querySelectorAll('.step')); function showStep(n) { steps.forEach((step, i) => step.classList.toggle('active', i === n)); currentStep = n; } // ============================================================= // Lizenzprüfung und Name anzeigen // ============================================================= let savedLicenseKey = ''; let savedUserName = ''; const licenseForm = document.getElementById('license-form'); if (licenseForm) { licenseForm.addEventListener('submit', function (e) { e.preventDefault(); const key = document.getElementById('license-key').value; fetch('license_check.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'license_key=' + encodeURIComponent(key) }) .then(response => response.json()) .then(result => { if (result.status === 'valid') { savedLicenseKey = key; savedUserName = result.name; document.getElementById('show-license-key').textContent = savedLicenseKey; document.getElementById('show-user-name').textContent = savedUserName; document.getElementById('hidden-license-key').value = savedLicenseKey; showStep(1); // Willkommensseite } else { document.getElementById('license-message').textContent = '❌ Ungültiger Lizenzschlüssel!'; } }) .catch(() => { document.getElementById('license-message').textContent = '⚠️ Fehler bei der Lizenzprüfung.'; }); }); } // ============================================================= // Navigation Buttons // ============================================================= const navLinks = [ ['welcome-next', 2], // 0→1→2 ['back-1', 1], ['next-1', 3], ['back-2', 2], ['next-2', 4], ['back-3', 3], ['next-3', 5], ['back-4', 4], ['next-4', 6], ['back-5', 5], ['next-5', 7], ['back-6', 6], ['next-6', 8], ['back-7', 7], ['next-7', 9], ['back-8', 8], ['next-8', 10], ['back-9', 9], ['next-9', 11], ['back-10', 10], ['next-10', 12], ['back-11', 11], ['next-11', 13], // 👈 Step 11 → Step 12 ]; for (const [id, step] of navLinks) { const el = document.getElementById(id); if (el) el.onclick = () => showStep(step); } // ============================================================= // 🔊 Audio-Recorder Setup (iOS-kompatibel) // ============================================================= function setupRecorder(recordBtnId, stopBtnId, audioElId, dataInputId) { let mediaRecorder, audioChunks = []; const recordBtn = document.getElementById(recordBtnId); const stopBtn = document.getElementById(stopBtnId); const audioEl = document.getElementById(audioElId); const dataInput = document.getElementById(dataInputId); if (!recordBtn || !stopBtn || !audioEl || !dataInput) return; const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent); const preferredMime = isIOS ? 'audio/mp4' : (MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' : 'audio/webm'); recordBtn.addEventListener('click', async function () { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream, { mimeType: preferredMime }); audioChunks = []; mediaRecorder.start(); recordBtn.disabled = true; stopBtn.disabled = false; mediaRecorder.ondataavailable = e => { if (e.data && e.data.size > 0) { audioChunks.push(e.data); } }; mediaRecorder.onstop = async () => { const realMime = mediaRecorder.mimeType || (audioChunks[0] && audioChunks[0].type) || 'audio/wav'; const audioBlob = new Blob(audioChunks, { type: realMime }); const arrayBuffer = await audioBlob.arrayBuffer(); try { const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const decoded = await audioCtx.decodeAudioData(arrayBuffer); const fixedBlob = await encodeWav(decoded); const fixedUrl = URL.createObjectURL(fixedBlob); audioEl.src = fixedUrl; audioEl.classList.remove('hidden'); audioEl.load(); const reader = new FileReader(); reader.onloadend = () => { dataInput.value = reader.result; }; reader.readAsDataURL(fixedBlob); } catch (err) { console.error("Audio-Decoding fehlgeschlagen:", err); const audioUrl = URL.createObjectURL(audioBlob); audioEl.src = audioUrl; audioEl.classList.remove('hidden'); audioEl.load(); } }; } catch (err) { alert("⚠️ Mikrofonzugriff fehlgeschlagen: " + err.message); console.error(err); } }); stopBtn.addEventListener('click', () => { if (mediaRecorder && mediaRecorder.state !== 'inactive') { mediaRecorder.stop(); recordBtn.disabled = false; stopBtn.disabled = true; } }); } // ============================================================= // WAV Encoder Hilfsfunktion (PCM16) // ============================================================= async function encodeWav(decodedBuffer) { const numChannels = decodedBuffer.numberOfChannels; const sampleRate = decodedBuffer.sampleRate; const bitDepth = 16; const format = 1; const samples = decodedBuffer.getChannelData(0); const buffer = new ArrayBuffer(44 + samples.length * 2); const view = new DataView(buffer); const writeString = (offset, string) => { for (let i = 0; i < string.length; i++) view.setUint8(offset + i, string.charCodeAt(i)); }; writeString(0, 'RIFF'); view.setUint32(4, 36 + samples.length * 2, true); writeString(8, 'WAVE'); writeString(12, 'fmt '); view.setUint32(16, 16, true); view.setUint16(20, format, true); view.setUint16(22, numChannels, true); view.setUint32(24, sampleRate, true); view.setUint32(28, sampleRate * numChannels * bitDepth / 8, true); view.setUint16(32, numChannels * bitDepth / 8, true); view.setUint16(34, bitDepth, true); writeString(36, 'data'); view.setUint32(40, samples.length * 2, true); let offset = 44; for (let i = 0; i < samples.length; i++, offset += 2) { let s = Math.max(-1, Math.min(1, samples[i])); view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); } return new Blob([view], { type: 'audio/wav' }); } // ============================================================= // Recorder direkt initialisieren (kein DOMContentLoaded nötig) // ============================================================= setupRecorder('record1-btn', 'stop1-btn', 'audio1', 'audio1-data'); setupRecorder('record1b-btn', 'stop1b-btn', 'audio1b', 'audio1b-data'); setupRecorder('record2-btn', 'stop2-btn', 'audio2', 'audio2-data'); setupRecorder('record3-btn', 'stop3-btn', 'audio3', 'audio3-data'); setupRecorder('record4-btn', 'stop4-btn', 'audio4', 'audio4-data'); setupRecorder('record5-btn', 'stop5-btn', 'audio5', 'audio5-data'); setupRecorder('record6-btn', 'stop6-btn', 'audio6', 'audio6-data'); setupRecorder('record7-btn', 'stop7-btn', 'audio7', 'audio7-data'); // ============================================================= // Formular absenden & Step 13 anzeigen // ============================================================= const submitBtn = document.getElementById("submit-btn"); const form = document.getElementById("quiz-form"); const finalStep = document.getElementById("step-13"); const step12 = document.getElementById("step-12"); // Step 12 referenzieren if (submitBtn && form && finalStep && step12) { submitBtn.addEventListener("click", async (e) => { e.preventDefault(); submitBtn.disabled = true; const formData = new FormData(form); try { const response = await fetch("submit.php", { method: "POST", body: formData }); let result = {}; try { result = await response.json(); } catch (err) { console.error("Antwort war kein gültiges JSON:", err); result = { success: false, message: "Antwort konnte nicht gelesen werden." }; } // Step 12 deaktivieren step12.classList.remove("active"); // Step 13 aktivieren finalStep.classList.add("active"); // Inhalte von Step 13 setzen finalStep.innerHTML = `

${result.success ? "🎉 Erfolgreich gesendet!" : "⚠️ Fehler"}

${(result.message || "").replace(/\n/g, "
")}

`; // Optional: Formular resetten form.reset(); } catch (err) { console.error("Fehler beim Absenden:", err); step12.classList.remove("active"); finalStep.classList.add("active"); finalStep.innerHTML = `

⚠️ Verbindungsfehler

Es gab ein Problem beim Absenden. Bitte versuchen Sie es erneut.

`; } finally { submitBtn.disabled = false; } }); } // ============================================================= // GIFs / Bilder im Modal anzeigen // ============================================================= function openModal(imgElement) { const modal = document.getElementById("imgModal"); const modalImg = document.getElementById("imgModalContent"); const gifSrc = imgElement.dataset.gif; const lastFrameSrc = imgElement.dataset.lastframe; if (gifSrc) { modalImg.src = gifSrc + '?t=' + new Date().getTime(); const gifDuration = 5000; setTimeout(() => { modalImg.src = lastFrameSrc; }, gifDuration); } else { modalImg.src = imgElement.src; } modal.style.display = "block"; } // ============================================================= // Initiale Ansicht: Lizenzabfrage // ============================================================= showStep(0);