fix: guarantee PDF action with immediate fallback window
This commit is contained in:
@@ -498,8 +498,17 @@ function closeAiModal(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function downloadPdf(){
|
async function downloadPdf(){
|
||||||
|
const fallbackWin = window.open('', '_blank');
|
||||||
|
const openPrintFallback = (msg='') => {
|
||||||
|
if (msg) alert(msg);
|
||||||
|
if (!fallbackWin) return;
|
||||||
|
fallbackWin.document.write(`<!doctype html><html><head><meta charset="utf-8"><title>Coachingcards PDF</title></head><body>${app.innerHTML}</body></html>`);
|
||||||
|
fallbackWin.document.close();
|
||||||
|
fallbackWin.onload = () => setTimeout(() => fallbackWin.print(), 200);
|
||||||
|
};
|
||||||
|
|
||||||
if (!window.html2canvas || !window.jspdf?.jsPDF) {
|
if (!window.html2canvas || !window.jspdf?.jsPDF) {
|
||||||
alert('PDF-Export-Bibliothek nicht geladen.');
|
openPrintFallback('PDF-Bibliotheken fehlen – Druckdialog als Fallback.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,18 +520,12 @@ async function downloadPdf(){
|
|||||||
root.style.background = '#fff';
|
root.style.background = '#fff';
|
||||||
root.innerHTML = app.innerHTML;
|
root.innerHTML = app.innerHTML;
|
||||||
root.querySelectorAll('.card-actions,.card-action-btn,button,[data-edit-all]').forEach(el => el.remove());
|
root.querySelectorAll('.card-actions,.card-action-btn,button,[data-edit-all]').forEach(el => el.remove());
|
||||||
root.querySelectorAll('.card-size').forEach(el => {
|
root.querySelectorAll('.card-size').forEach(el => { el.style.boxShadow = 'none'; el.style.margin = '0 0 12px 0'; });
|
||||||
el.style.boxShadow = 'none';
|
|
||||||
el.style.margin = '0 0 12px 0';
|
|
||||||
});
|
|
||||||
document.body.appendChild(root);
|
document.body.appendChild(root);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cards = [...root.querySelectorAll('.card-size')];
|
const cards = [...root.querySelectorAll('.card-size')];
|
||||||
if (!cards.length) {
|
if (!cards.length) throw new Error('Keine Karten sichtbar');
|
||||||
alert('Keine Karten für den Export sichtbar.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { jsPDF } = window.jspdf;
|
const { jsPDF } = window.jspdf;
|
||||||
const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
|
const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
|
||||||
@@ -533,31 +536,31 @@ async function downloadPdf(){
|
|||||||
const usableH = pageH - margin * 2;
|
const usableH = pageH - margin * 2;
|
||||||
|
|
||||||
for (let i = 0; i < cards.length; i++) {
|
for (let i = 0; i < cards.length; i++) {
|
||||||
const canvas = await window.html2canvas(cards[i], {
|
const canvas = await Promise.race([
|
||||||
scale: 2,
|
window.html2canvas(cards[i], { scale: 2, useCORS: true, backgroundColor: '#ffffff', logging: false }),
|
||||||
useCORS: true,
|
new Promise((_, rej) => setTimeout(() => rej(new Error('Render timeout')), 15000))
|
||||||
backgroundColor: '#ffffff',
|
]);
|
||||||
logging: false
|
|
||||||
});
|
|
||||||
const img = canvas.toDataURL('image/jpeg', 0.98);
|
const img = canvas.toDataURL('image/jpeg', 0.98);
|
||||||
const imgW = canvas.width;
|
const ratio = Math.min(usableW / canvas.width, usableH / canvas.height);
|
||||||
const imgH = canvas.height;
|
const drawW = canvas.width * ratio;
|
||||||
const ratio = Math.min(usableW / imgW, usableH / imgH);
|
const drawH = canvas.height * ratio;
|
||||||
const drawW = imgW * ratio;
|
|
||||||
const drawH = imgH * ratio;
|
|
||||||
const x = margin + (usableW - drawW) / 2;
|
const x = margin + (usableW - drawW) / 2;
|
||||||
const y = margin + (usableH - drawH) / 2;
|
const y = margin + (usableH - drawH) / 2;
|
||||||
|
|
||||||
if (i > 0) pdf.addPage();
|
if (i > 0) pdf.addPage();
|
||||||
pdf.addImage(img, 'JPEG', x, y, drawW, drawH, undefined, 'FAST');
|
pdf.addImage(img, 'JPEG', x, y, drawW, drawH, undefined, 'FAST');
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf.save(`coachingcards-${new Date().toISOString().slice(0,10)}.pdf`);
|
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 {
|
} finally {
|
||||||
root.remove();
|
root.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function syncActiveJob(){
|
async function syncActiveJob(){
|
||||||
const r = await fetch('/api/generate/active');
|
const r = await fetch('/api/generate/active');
|
||||||
const j = await r.json();
|
const j = await r.json();
|
||||||
|
|||||||
Reference in New Issue
Block a user