From b7f3f47c610952426a901237180e35d1a3901b9b Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Thu, 29 Jan 2026 07:46:19 +0000 Subject: [PATCH] fix(dees-pdf-viewer): use in-memory PDF data for download and print; add robust print wrapper, cleanup and error handling --- changelog.md | 8 ++ ts_web/00_commitinfo_data.ts | 2 +- .../dees-pdf-viewer/component.ts | 116 ++++++++++++++---- 3 files changed, 101 insertions(+), 25 deletions(-) diff --git a/changelog.md b/changelog.md index 31d20e7..f3429e5 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2026-01-29 - 3.41.3 - fix(dees-pdf-viewer) +use in-memory PDF data for download and print; add robust print wrapper, cleanup and error handling + +- Download and Print now use pdfDocument.getData() to create Blob URLs so in-memory PDFs (pdf.js) can be saved/printed. +- Print flow now opens an HTML wrapper with an iframe to allow onafterprint handling, auto-close, popup-fallback and timed cleanup of Blob URLs. +- Added try/catch logging, URL.revokeObjectURL calls and safety timeouts to avoid resource leaks. +- Removed context menu items that relied on the raw PDF URL (Open in New Tab, Copy PDF URL); Download/Print actions now await the async handlers. + ## 2026-01-28 - 3.41.2 - fix(dees-pdf-viewer) account for devicePixelRatio when setting canvas dimensions and scale 2D context to render crisp PDF pages and thumbnails on high-DPI displays diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 550e219..1905409 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@design.estate/dees-catalog', - version: '3.41.2', + version: '3.41.3', description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' } diff --git a/ts_web/elements/00group-media/dees-pdf-viewer/component.ts b/ts_web/elements/00group-media/dees-pdf-viewer/component.ts index 4587ac8..23becde 100644 --- a/ts_web/elements/00group-media/dees-pdf-viewer/component.ts +++ b/ts_web/elements/00group-media/dees-pdf-viewer/component.ts @@ -935,15 +935,98 @@ export class DeesPdfViewer extends DeesElement { }); } - private downloadPdf() { - const link = document.createElement('a'); - link.href = this.pdfUrl; - link.download = this.pdfUrl.split('/').pop() || 'document.pdf'; - link.click(); + private async downloadPdf() { + if (!this.pdfDocument) return; + + try { + // Get raw PDF data from the loaded document + const data = await this.pdfDocument.getData(); + const blob = new Blob([data.buffer], { type: 'application/pdf' }); + const blobUrl = URL.createObjectURL(blob); + + const link = document.createElement('a'); + link.href = blobUrl; + link.download = this.pdfUrl ? this.pdfUrl.split('/').pop() || 'document.pdf' : 'document.pdf'; + link.click(); + + // Clean up blob URL after short delay + setTimeout(() => URL.revokeObjectURL(blobUrl), 1000); + } catch (error) { + console.error('Error downloading PDF:', error); + } } - private printPdf() { - window.open(this.pdfUrl, '_blank')?.print(); + private async printPdf() { + if (!this.pdfDocument) return; + + try { + // Get raw PDF data from the loaded document + const data = await this.pdfDocument.getData(); + const blob = new Blob([data.buffer], { type: 'application/pdf' }); + const pdfUrl = URL.createObjectURL(blob); + + // Create an HTML wrapper page that embeds the PDF and handles print/close + // This gives us control over the afterprint event (direct PDF URLs don't support it) + const htmlContent = ` + + + + Print PDF + + + + + + + + `; + const htmlBlob = new Blob([htmlContent], { type: 'text/html' }); + const htmlUrl = URL.createObjectURL(htmlBlob); + + const printWindow = window.open(htmlUrl, '_blank', 'width=800,height=600'); + if (printWindow) { + // Cleanup blob URLs when window closes + const checkClosed = setInterval(() => { + if (printWindow.closed) { + clearInterval(checkClosed); + URL.revokeObjectURL(pdfUrl); + URL.revokeObjectURL(htmlUrl); + } + }, 500); + // Safety cleanup after 2 minutes + setTimeout(() => { + clearInterval(checkClosed); + URL.revokeObjectURL(pdfUrl); + URL.revokeObjectURL(htmlUrl); + }, 120000); + } else { + // Popup blocked - fall back to direct navigation + window.open(pdfUrl, '_blank'); + setTimeout(() => URL.revokeObjectURL(pdfUrl), 60000); + URL.revokeObjectURL(htmlUrl); + } + } catch (error) { + console.error('Error printing PDF:', error); + } } /** @@ -967,33 +1050,18 @@ export class DeesPdfViewer extends DeesElement { } items.push( - { - name: 'Open PDF in New Tab', - iconName: 'lucide:ExternalLink', - action: async () => { - window.open(this.pdfUrl, '_blank'); - } - }, - { divider: true }, - { - name: 'Copy PDF URL', - iconName: 'lucide:Link', - action: async () => { - await navigator.clipboard.writeText(this.pdfUrl); - } - }, { name: 'Download PDF', iconName: 'lucide:Download', action: async () => { - this.downloadPdf(); + await this.downloadPdf(); } }, { name: 'Print PDF', iconName: 'lucide:Printer', action: async () => { - this.printPdf(); + await this.printPdf(); } } );