/* 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=`
${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!');
}
}