/* share.js — Veröffentlichen: Link/QR/PDF, Teilen */ /* ══════════════════════════════════════════════ SUMMARY CARD ══════════════════════════════════════════════ */ function showSummaryCard(){ document.getElementById('fbCard').style.display='none'; const sc=document.getElementById('sumCard');sc.style.display='block'; sc.style.animation='slideIn 0.4s ease both'; setTimeout(()=>sc.scrollIntoView({behavior:'smooth',block:'start'}),400); const fun=fbAnswers.fun||3;const mg=fbAnswers.minigames||3; const diff=fbAnswers.difficulty;const replay=fbAnswers.replay; document.getElementById('sumText').textContent='Du hast dein Spiel getestet und Feedback gegeben. Hier ist deine Auswertung:'; document.getElementById('sumScores').innerHTML=`
${fun}/5
Spaßfaktor
${mg}/5
Mini-Game Passung
${ST.fieldCount}
Felder
${ST.storyItems.length}
Erzähltexte
`; const notes=[]; if(fun<=2)notes.push({i:'🎯',t:'Der Spaßfaktor ist noch niedrig — überlege, spannendere Mini-Games oder Erzähltexte hinzuzufügen.'}); else if(fun>=4)notes.push({i:'🔥',t:'Super Spaßfaktor! Dein Spiel macht offensichtlich Freude.'}); if(diff===0)notes.push({i:'⚠️',t:'Das Spiel war zu einfach — probiere schwierigere Mini-Games oder weniger Leben.'}); else if(diff===3)notes.push({i:'⚠️',t:'Das Spiel war zu schwer — erhöhe die Lebensanzahl oder wähle einfachere Mini-Games.'}); if(ST.storyItems.length===0)notes.push({i:'📖',t:'Keine Erzähltexte vorhanden — sie machen das Spiel viel lebendiger!'}); if(ST.fields.slice(1,ST.fieldCount-1).filter(Boolean).length<3)notes.push({i:'🕹️',t:'Nur wenige Felder sind belegt — füge mehr Mini-Games hinzu für mehr Abwechslung.'}); if(replay>=2)notes.push({i:'🚀',t:'Das Spiel hat Wiederspielwert — großartig!'}); if(fbAnswers.problems&&fbAnswers.problems.length>5)notes.push({i:'🔧',t:`Problem: "${esc(fbAnswers.problems)}" — geh zurück und überarbeite das.`}); if(notes.length===0)notes.push({i:'✅',t:'Alles sieht gut aus! Dein Spiel ist bereit zum Teilen.'}); document.getElementById('sumNotes').innerHTML=notes.map(n=>`
${n.i}${n.t}
`).join(''); save();localStorage.setItem('testFeedback',JSON.stringify(fbAnswers)); } // ── URL-Sharing System ───────────────────────────────────────────────────── // Komprimiert die Spielkonfiguration und kodiert sie als URL-Hash // JSON → pako.gzip (DEFLATE) → Base64 → URL-Hash function buildShareURL() { // Nur die nötigen Felder exportieren (kein highestStep etc.) const exportCfg = { devName: ST.devName, name: ST.name, desc: ST.desc, figure: ST.figure, figure2: ST.figure2, playerCount: ST.playerCount, background: ST.background, fieldCount: ST.fieldCount, fields: ST.fields, storyItems: ST.storyItems, quizData: ST.quizData, rules: ST.rules, consequences:ST.consequences, mgSettings: ST.mgSettings, worldSeed: ST.worldSeed, worldLocked: ST.worldLocked, }; const json = JSON.stringify(exportCfg); // pako ist über CDN geladen – falls nicht verfügbar: direktes Base64 let encoded; try { const compressed = pako.deflate(json, { level: 9 }); // Uint8Array → binary string → btoa const binary = Array.from(compressed).map(b => String.fromCharCode(b)).join(''); encoded = 'z:' + btoa(binary); } catch(e) { // Fallback ohne Kompression encoded = 'j:' + btoa(unescape(encodeURIComponent(json))); } const base = window.location.href.replace(/\/editor\.html.*$/, '') + '/game.html'; return base + '#' + encoded; } // ── Kurz-Code (6 Zeichen) zum manuellen Eintippen ── const CODE_ALPHA = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // ohne 0,O,1,I,L (Verwechslungsschutz) function genShareCode(){ let s = ''; for(let i=0;i<6;i++) s += CODE_ALPHA[Math.floor(Math.random()*CODE_ALPHA.length)]; return s; } // URL der /play/-Landing-Page (für den zweiten QR) function playPageURL(){ return window.location.href.replace(/\/editor\.html.*$/, '') + '/play/'; } // Spielkonfiguration zum Server hochladen → Kurz-Code reservieren async function uploadCfgForCode(code, cfg){ const res = await fetch('/api/boardgame-play/save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code, cfg }), }); if(!res.ok) throw new Error('Server-Fehler ' + res.status); return res.json(); } function doPublish() { const url = buildShareURL(); // Spiel-Info füllen const bg = BACKGROUNDS.find(b => b.id === ST.background); const fig = FIGURES.find(f => f.id === ST.figure); const infoEl = document.getElementById('shareGameInfo'); infoEl.innerHTML = `
${fig ? fig.e : '🎮'}${bg ? bg.e : ''}
${esc(ST.name || 'Mein Spiel')}
von ${esc(ST.devName || 'Anonym')} · ${ST.fieldCount} Felder · ${ST.fields.filter(Boolean).length} Mini-Games
`; // Link setzen const input = document.getElementById('shareLinkInput'); input.value = url; const lenEl = document.getElementById('shareLinkLen'); lenEl.textContent = `Link-Länge: ${url.length} Zeichen${url.length > 4000 ? ' ⚠️ zu lang für QR-Code!' : ' ✅ QR-Code-tauglich'}`; // Haupt-QR-Code (zum direkten Spiel-Link) const qrEl = document.getElementById('shareQR'); qrEl.innerHTML = ''; try { new QRCode(qrEl, { text: url, width: 180, height: 180, colorDark: '#000000', colorLight: '#ffffff', correctLevel: QRCode.CorrectLevel.M, }); } catch(e) { qrEl.innerHTML = '
QR-Code konnte nicht erstellt werden.
Link zum Kopieren nutzen.
'; } // Overlay zeigen const ov = document.getElementById('shareOverlay'); ov.style.display = 'flex'; document.body.style.overflow = 'hidden'; // ── Kurz-Code-Bereich ── const codeBox = document.getElementById('shareCodeBox'); const codeEl = document.getElementById('shareCodeText'); const playUrlEl= document.getElementById('sharePlayUrl'); const playQrEl = document.getElementById('sharePlayQR'); const codeStatus = document.getElementById('shareCodeStatus'); if(codeBox){ codeBox.style.display = ''; if(codeEl) codeEl.textContent = '······'; if(codeStatus) codeStatus.textContent = 'wird erzeugt …'; if(playUrlEl) playUrlEl.textContent = playPageURL().replace(/^https?:\/\//,''); if(playQrEl){ playQrEl.innerHTML = ''; try{ new QRCode(playQrEl, { text: playPageURL(), width:120, height:120, colorDark:'#000000', colorLight:'#ffffff', correctLevel: QRCode.CorrectLevel.M }); }catch(e){} } } // Code reservieren (re-publish nutzt denselben Code) const exportCfg = { devName: ST.devName, name: ST.name, desc: ST.desc, figure: ST.figure, figure2: ST.figure2, playerCount: ST.playerCount, background: ST.background, fieldCount: ST.fieldCount, fields: ST.fields, storyItems: ST.storyItems, quizData: ST.quizData, rules: ST.rules, consequences: ST.consequences, mgSettings: ST.mgSettings, worldSeed: ST.worldSeed, worldLocked: ST.worldLocked, }; const useCode = ST.shareCode || genShareCode(); uploadCfgForCode(useCode, exportCfg) .then(() => { ST.shareCode = useCode; save(); if(codeEl) codeEl.textContent = useCode; if(codeStatus) codeStatus.textContent = '✓ bereit'; }) .catch(err => { console.warn('Kurz-Code Upload fehlgeschlagen:', err); if(codeEl) codeEl.textContent = '— —'; if(codeStatus) codeStatus.innerHTML = 'offline?'; }); } function closeShare() { document.getElementById('shareOverlay').style.display = 'none'; document.body.style.overflow = ''; } async function printAsPDF() { // Heutiges Datum DD.MM.YYYY (dynamisch — kein Hardcode) const _d = new Date(); const todayStr = String(_d.getDate()).padStart(2,'0') + '.' + String(_d.getMonth()+1).padStart(2,'0') + '.' + _d.getFullYear(); const qrEl = document.getElementById('shareQR'); const canvas = qrEl.querySelector('canvas'); if (!canvas) { appAlert('QR-Code nicht gefunden.'); return; } const qrDataUrl = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' }); const pageW = 210, pageH = 297, margin = 14; await new Promise(resolve => { const img = new Image(); img.onload = () => { const c = document.createElement('canvas'); c.width = img.naturalWidth; c.height = img.naturalHeight; c.getContext('2d').drawImage(img, 0, 0); // Logo klein, zentriert const logoW = 72, logoH = logoW * (img.naturalHeight / img.naturalWidth); doc.addImage(c.toDataURL('image/png'), 'PNG', (pageW - logoW) / 2, margin, logoW, logoH); let y = margin + logoH + 3; // Trennlinie grau doc.setDrawColor(160, 160, 160); doc.setLineWidth(0.3); doc.line(margin, y, pageW - margin, y); y += 4; // Fach-Bezeichnung doc.setFont('helvetica', 'normal'); doc.setFontSize(9); doc.setTextColor(90, 90, 90); doc.text('Fach Informatik & Medien- und Bildungsmanagement', pageW / 2, y, { align: 'center' }); y += 5; // Datum doc.setFont('helvetica', 'bold'); doc.setFontSize(10); doc.setTextColor(40, 40, 40); doc.text(todayStr, pageW / 2, y, { align: 'center' }); y += 6; // Spielname doc.setFont('helvetica', 'bold'); doc.setFontSize(22); doc.setTextColor(10, 10, 10); doc.text(ST.name || 'Mein Spiel', pageW / 2, y, { align: 'center' }); y += 5; // Autor + Info doc.setFont('helvetica', 'normal'); doc.setFontSize(9); doc.setTextColor(110, 110, 110); const miniCount = ST.fields.filter(Boolean).length; doc.text('von ' + (ST.devName || 'Anonym') + ' · ' + ST.fieldCount + ' Felder · ' + miniCount + ' Mini-Games', pageW / 2, y, { align: 'center' }); y += 9; // ── Zwei Spalten: Haupt-QR (Direktstart) links, Kurz-Code-Block rechts ── const colGap = 8; const qrLarge = 70; const colW = (pageW - 2*margin - colGap) / 2; const leftX = margin; const rightX = margin + colW + colGap; // ── LINKE SPALTE: QR direkt ── // Überschrift links doc.setFont('helvetica', 'bold'); doc.setFontSize(9); doc.setTextColor(40,40,40); doc.text('📱 Mit Handy scannen', leftX + colW/2, y, { align: 'center' }); const qrX = leftX + (colW - qrLarge) / 2; const qrY = y + 4; doc.setDrawColor(180,180,180); doc.setLineWidth(0.25); doc.rect(qrX - 1, qrY - 1, qrLarge + 2, qrLarge + 2); doc.addImage(qrDataUrl, 'PNG', qrX, qrY, qrLarge, qrLarge); doc.setFont('helvetica','italic'); doc.setFontSize(7.5); doc.setTextColor(120,120,120); doc.text('Kamera → öffnet Spiel direkt', leftX + colW/2, qrY + qrLarge + 4, { align: 'center' }); // ── RECHTE SPALTE: Kurz-Code + Play-Seite-QR ── const shareCode = (ST.shareCode || '······').toUpperCase(); const playUrl = playPageURL().replace(/^https?:\/\//, ''); doc.setFont('helvetica', 'bold'); doc.setFontSize(9); doc.setTextColor(40,40,40); doc.text('⌨️ Am PC eintippen', rightX + colW/2, y, { align: 'center' }); // Kleiner QR für /play/ Seite const playQrEl = document.getElementById('sharePlayQR'); const playQrCanvas = playQrEl ? playQrEl.querySelector('canvas') : null; const smallQR = 28; if (playQrCanvas) { const playQrDataUrl = playQrCanvas.toDataURL('image/png'); const playQrX = rightX + 2; const playQrY = y + 4; doc.setDrawColor(200,200,200); doc.setLineWidth(0.2); doc.rect(playQrX - 0.5, playQrY - 0.5, smallQR + 1, smallQR + 1); doc.addImage(playQrDataUrl, 'PNG', playQrX, playQrY, smallQR, smallQR); doc.setFont('helvetica','normal'); doc.setFontSize(6); doc.setTextColor(120,120,120); doc.text('zur Seite:', playQrX + smallQR/2, playQrY + smallQR + 3, { align: 'center' }); } // URL-Text + Code const txtX = rightX + smallQR + 8; let codeY = y + 9; doc.setFont('helvetica','normal'); doc.setFontSize(7); doc.setTextColor(80,80,80); doc.text('1. Im Browser öffnen:', txtX, codeY); codeY += 3.5; doc.setFont('helvetica','bold'); doc.setFontSize(8); doc.setTextColor(30,30,30); doc.text(playUrl, txtX, codeY); codeY += 7; doc.setFont('helvetica','normal'); doc.setFontSize(7); doc.setTextColor(80,80,80); doc.text('2. Diesen Code eingeben:', txtX, codeY); codeY += 6; doc.setFont('courier', 'bold'); doc.setFontSize(22); doc.setTextColor(20,20,20); doc.text(shareCode, txtX, codeY); y = qrY + qrLarge + 12; // ---- Schnittlinie ---- const stripW = 43, stripH = 23; const stripX = (pageW - stripW) / 2; const stripY = pageH - margin - stripH; const cutY = stripY - 6; // Schnittlinie doc.setDrawColor(150, 150, 150); doc.setLineWidth(0.25); doc.setLineDashPattern([1.5, 1.5], 0); doc.line(margin, cutY, pageW - margin, cutY); doc.setLineDashPattern([], 0); doc.setFont('helvetica', 'normal'); doc.setFontSize(5.5); doc.setTextColor(170, 170, 170); doc.text('✂ Hier abschneiden', margin + 1, cutY - 1.2); // ---- Ausschneidstreifen 41 × 23 mm (QR 23×23 | Text ~18×23) ---- // Rahmen doc.setDrawColor(100, 100, 100); doc.setLineWidth(0.3); doc.rect(stripX, stripY, stripW, stripH); // Trennlinie bei 23mm (QR-Breite) doc.setLineWidth(0.15); doc.setDrawColor(180,180,180); doc.line(stripX + 23, stripY, stripX + 23, stripY + stripH); // QR links 23×23 doc.addImage(qrDataUrl, 'PNG', stripX, stripY, 23, 23); // Text rechts — linksbündig mit 1.5mm Einzug, vertikal zentriert const tx = stripX + 23 + 1.5; doc.setFont('helvetica', 'bold'); doc.setFontSize(5.5); doc.setTextColor(20, 20, 20); const gameName = (ST.name || 'Mein Spiel').substring(0, 18); doc.text(gameName, tx, stripY + 5); doc.setFont('helvetica', 'normal'); doc.setFontSize(4); doc.setTextColor(110,110,110); doc.text(todayStr + ' · PH Weingarten', tx, stripY + 9); doc.setFont('helvetica', 'normal'); doc.setFontSize(4); doc.setTextColor(120,120,120); doc.text('Code:', tx, stripY + 14); doc.setFont('courier', 'bold'); doc.setFontSize(7); doc.setTextColor(20,20,20); doc.text((ST.shareCode || '······').toUpperCase(), tx, stripY + 18.5); resolve(); }; img.onerror = () => { resolve(); }; img.src = 'phw_logo.png'; }); const filename = (ST.name || 'spiel').replace(/[^a-zA-Z0-9_\-]/g, '_') + '_qr.pdf'; doc.save(filename); } function copyShareLink() { const input = document.getElementById('shareLinkInput'); input.select(); navigator.clipboard.writeText(input.value).then(() => { const btn = document.getElementById('shareCopyBtn'); btn.textContent = '✅ Kopiert!'; setTimeout(() => btn.textContent = '📋 Kopieren', 2000); }).catch(() => { document.execCommand('copy'); showToast('📋 Link kopiert!'); }); } function shareViaEmail() { const url = document.getElementById('shareLinkInput').value; const subject = encodeURIComponent('🎲 Mein Brettspiel: ' + (ST.name || 'Mein Spiel')); const body = encodeURIComponent( 'Hallo!\n\nIch habe ein Brettspiel erstellt und möchte es mit dir teilen:\n\n' + (ST.name || 'Mein Spiel') + '\n' + url + '\n\nViel Spaß beim Spielen!\n' + (ST.devName || '') ); window.open('mailto:?subject=' + subject + '&body=' + body); } function shareViaWhatsApp() { const url = document.getElementById('shareLinkInput').value; const text = encodeURIComponent('🎲 Mein Brettspiel "' + (ST.name || 'Mein Spiel') + '" – einfach anklicken und spielen! ' + url); window.open('https://wa.me/?text=' + text, '_blank', 'noopener,noreferrer'); } function shareNative() { const url = document.getElementById('shareLinkInput').value; if (navigator.share) { navigator.share({ title: ST.name || 'Mein Brettspiel', text: 'Ich habe ein Brettspiel erstellt!', url: url, }).catch(() => {}); } else { copyShareLink(); showToast('📋 Link in die Zwischenablage kopiert!'); } }