Skip to content

Commit a5f2ad8

Browse files
committed
feat: Improve PDF export with Blob URLs and enhanced print styles
Refactor the `exportAsPDF` function to generate PDF content using Blob URLs. This change improves the reliability and security of the export process by avoiding direct `document.write` operations in the new print window. Additionally, this commit introduces specific print media styles directly into the generated HTML. These styles ensure consistent page margins, proper content padding, and basic table formatting, leading to a more professional and readable PDF output. The print window now automatically closes after printing, and Blob URLs are revoked for resource cleanup.
1 parent d0cf4f1 commit a5f2ad8

1 file changed

Lines changed: 49 additions & 12 deletions

File tree

src/export.js

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,29 +79,66 @@ export function exportAsHTML({ bodyHtml, title }) {
7979
}
8080

8181
export function exportAsPDF({ bodyHtml, title }) {
82-
// Open a print-ready window using same origin to allow resource loading
8382
const cssCdn = 'https://cdn.jsdelivr.net/npm/github-markdown-css@5.8.1/github-markdown-light.min.css';
84-
const win = window.open('', '_blank');
85-
if (!win) {
86-
alert('Popup blocked. Please allow popups to export as PDF.');
87-
return;
88-
}
89-
win.document.open();
90-
win.document.write(`<!DOCTYPE html>
83+
const printCss = '/css/style.css'; // Reference the main stylesheet for print media
84+
85+
const htmlContent = `<!DOCTYPE html>
9186
<html>
9287
<head>
9388
<meta charset="UTF-8">
9489
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
9590
<title>${escapeHtml(title)}</title>
9691
<link rel="stylesheet" href="${cssCdn}" />
97-
<link rel="stylesheet" href="/css/style.css" media="print" />
92+
<link rel="stylesheet" href="${printCss}" media="print" />
93+
<style>
94+
/* Additional print-specific styles if needed, or overrides */
95+
@page {
96+
margin: 10mm;
97+
}
98+
html, body {
99+
padding: 10mm !important;
100+
overflow: hidden !important;
101+
}
102+
article.markdown-body {
103+
padding: 0;
104+
}
105+
table {
106+
border-collapse: collapse;
107+
width: 100%;
108+
}
109+
th, td {
110+
border: 1px solid #ddd;
111+
padding: 8px;
112+
text-align: left;
113+
}
114+
th {
115+
background-color: #f2f2f2;
116+
}
117+
</style>
98118
</head>
99119
<body>
100120
<article class="markdown-body">${bodyHtml}</article>
101-
<script>window.addEventListener('load', () => { setTimeout(() => { window.print(); }, 50); });</script>
102121
</body>
103-
</html>`);
104-
win.document.close();
122+
</html>`;
123+
124+
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' });
125+
const url = URL.createObjectURL(blob);
126+
127+
const newWindow = window.open(url, '_blank');
128+
if (!newWindow) {
129+
alert('Popup blocked. Please allow popups to export as PDF.');
130+
URL.revokeObjectURL(url);
131+
return;
132+
}
133+
134+
newWindow.addEventListener('load', () => {
135+
newWindow.print();
136+
URL.revokeObjectURL(url); // Clean up the Blob URL after printing
137+
});
138+
139+
newWindow.addEventListener('afterprint', () => {
140+
newWindow.close(); // Close the window after printing
141+
});
105142
}
106143

107144
function escapeHtml(str) {

0 commit comments

Comments
 (0)