diff --git a/public/index.html b/public/index.html
index 7546621..192e688 100644
--- a/public/index.html
+++ b/public/index.html
@@ -498,8 +498,17 @@ function closeAiModal(){
}
async function downloadPdf(){
+ const fallbackWin = window.open('', '_blank');
+ const openPrintFallback = (msg='') => {
+ if (msg) alert(msg);
+ if (!fallbackWin) return;
+ fallbackWin.document.write(`
Coachingcards PDF${app.innerHTML}`);
+ fallbackWin.document.close();
+ fallbackWin.onload = () => setTimeout(() => fallbackWin.print(), 200);
+ };
+
if (!window.html2canvas || !window.jspdf?.jsPDF) {
- alert('PDF-Export-Bibliothek nicht geladen.');
+ openPrintFallback('PDF-Bibliotheken fehlen – Druckdialog als Fallback.');
return;
}
@@ -511,18 +520,12 @@ async function downloadPdf(){
root.style.background = '#fff';
root.innerHTML = app.innerHTML;
root.querySelectorAll('.card-actions,.card-action-btn,button,[data-edit-all]').forEach(el => el.remove());
- root.querySelectorAll('.card-size').forEach(el => {
- el.style.boxShadow = 'none';
- el.style.margin = '0 0 12px 0';
- });
+ root.querySelectorAll('.card-size').forEach(el => { el.style.boxShadow = 'none'; el.style.margin = '0 0 12px 0'; });
document.body.appendChild(root);
try {
const cards = [...root.querySelectorAll('.card-size')];
- if (!cards.length) {
- alert('Keine Karten für den Export sichtbar.');
- return;
- }
+ if (!cards.length) throw new Error('Keine Karten sichtbar');
const { jsPDF } = window.jspdf;
const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
@@ -533,31 +536,31 @@ async function downloadPdf(){
const usableH = pageH - margin * 2;
for (let i = 0; i < cards.length; i++) {
- const canvas = await window.html2canvas(cards[i], {
- scale: 2,
- useCORS: true,
- backgroundColor: '#ffffff',
- logging: false
- });
+ const canvas = await Promise.race([
+ window.html2canvas(cards[i], { scale: 2, useCORS: true, backgroundColor: '#ffffff', logging: false }),
+ new Promise((_, rej) => setTimeout(() => rej(new Error('Render timeout')), 15000))
+ ]);
const img = canvas.toDataURL('image/jpeg', 0.98);
- const imgW = canvas.width;
- const imgH = canvas.height;
- const ratio = Math.min(usableW / imgW, usableH / imgH);
- const drawW = imgW * ratio;
- const drawH = imgH * ratio;
+ const ratio = Math.min(usableW / canvas.width, usableH / canvas.height);
+ const drawW = canvas.width * ratio;
+ const drawH = canvas.height * ratio;
const x = margin + (usableW - drawW) / 2;
const y = margin + (usableH - drawH) / 2;
-
if (i > 0) pdf.addPage();
pdf.addImage(img, 'JPEG', x, y, drawW, drawH, undefined, 'FAST');
}
pdf.save(`coachingcards-${new Date().toISOString().slice(0,10)}.pdf`);
+ if (fallbackWin && !fallbackWin.closed) fallbackWin.close();
+ } catch (e) {
+ console.error('PDF export failed', e);
+ openPrintFallback('PDF-Download fehlgeschlagen – nutze Druckdialog als Fallback.');
} finally {
root.remove();
}
}
+
async function syncActiveJob(){
const r = await fetch('/api/generate/active');
const j = await r.json();