Fix PDF export to always include the full book
The previous export printed the CodeMirror editor, which only keeps a virtualized window of lines in the DOM; on larger books the PDF could come out truncated (only what was rendered around the viewport). Replace the print path with a dedicated #printBook container: the renderer renders each chapter of the assembled manuscript to plain HTML with markdown-it, and the print stylesheet hides the entire app and shows that container instead. Plain HTML paginates reliably regardless of editor viewport or scroll position, every chapter after the first still starts on its own page, and output is a properly formatted manuscript instead of raw markdown. Keep the screen-only chapter-break separator in the Full Book editor. Extend the e2e selftest to assert #printBook holds every chapter, is hidden on screen, and that a 1500-line chapter reaches the print DOM and exported PDF in full.
This commit is contained in:
parent
778b480ea2
commit
d2118f080f
4 changed files with 151 additions and 58 deletions
|
|
@ -270,7 +270,7 @@ const BOOK2_DIR = __BOOKDIR2_VALUE__;
|
|||
const rawCss = await (await fetch("./index.css")).text();
|
||||
out.printBreakRule = /break-before\s*:\s*page/.test(rawCss);
|
||||
out.printBreakFallback = /page-break-before\s*:\s*always/.test(rawCss);
|
||||
out.printBreakScoped = /#fullBookHost\s+\.cm-line\.chapter-break/.test(rawCss);
|
||||
out.printBreakScoped = /\.print-chapter\s*{[^}]*break-before\s*:\s*page/.test(rawCss);
|
||||
|
||||
document.getElementById("copyAllBtn").click();
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
|
|
@ -435,6 +435,55 @@ const BOOK2_DIR = __BOOKDIR2_VALUE__;
|
|||
pdfRes.bytes > 500 &&
|
||||
pdfRes.pdfOk === true;
|
||||
|
||||
// The printed book comes from the plain-HTML #printBook container (the
|
||||
// print stylesheet hides the whole app and shows #printBook instead), so
|
||||
// the PDF can never be limited to the CodeMirror viewport. Verify the
|
||||
// container is hidden on screen and carries every chapter.
|
||||
const printBookEl = document.getElementById("printBook");
|
||||
out.printBookHiddenOnScreen = getComputedStyle(printBookEl).display === "none";
|
||||
const printChapters = () =>
|
||||
Array.from(document.querySelectorAll("#printBook .print-chapter"));
|
||||
const pcsAtSmallBook = printChapters();
|
||||
out.printBookChapterCount = pcsAtSmallBook.length;
|
||||
out.printBookHasAllChapters =
|
||||
pcsAtSmallBook.length === 3 &&
|
||||
pcsAtSmallBook.some((s) => s.textContent.includes("Gamma text")) &&
|
||||
pcsAtSmallBook.some((s) => s.textContent.includes("Beta body without heading")) &&
|
||||
pcsAtSmallBook.some((s) => s.querySelector("h1")?.textContent === "Empty");
|
||||
|
||||
// Long book: every line must reach the print DOM — the guard against the
|
||||
// "PDF does not show the full book" bug where a long manuscript was cut
|
||||
// off after the first screenful.
|
||||
const longLines = Array.from(
|
||||
{ length: 1500 },
|
||||
(_, i) => `Line ${i} of a very long chapter that must all reach the printed book.`
|
||||
);
|
||||
const veryLongId = (await window.folio.createChapter("Very Long")).id;
|
||||
await window.folio.saveChapter(veryLongId, longLines.join("\n"));
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
document.getElementById("fullBookBtn").click();
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
const printBookText = printBookEl.textContent;
|
||||
out.printBookHasFirstLongLine = printBookText.includes("Line 0 of a very long chapter");
|
||||
out.printBookHasLastLongLine = printBookText.includes("Line 1499 of a very long chapter");
|
||||
out.printBookLongChapterCount = printChapters().length;
|
||||
out.printBookLongFull =
|
||||
out.printBookHasFirstLongLine &&
|
||||
out.printBookHasLastLongLine &&
|
||||
printChapters().length === 4;
|
||||
|
||||
const pdfLongRes = await window.folio.exportPdf();
|
||||
out.pdfLongExport =
|
||||
pdfLongRes && "filePath" in pdfLongRes
|
||||
? { filePath: pdfLongRes.filePath, bytes: pdfLongRes.bytes, pdfOk: pdfLongRes.pdfOk }
|
||||
: pdfLongRes;
|
||||
out.pdfLongExportOk =
|
||||
!!pdfLongRes &&
|
||||
!("error" in pdfLongRes) &&
|
||||
"filePath" in pdfLongRes &&
|
||||
pdfLongRes.bytes > pdfRes.bytes * 2 &&
|
||||
pdfLongRes.pdfOk === true;
|
||||
|
||||
const okFlags = [
|
||||
"dndMoved",
|
||||
"kbMoved",
|
||||
|
|
@ -484,6 +533,10 @@ const BOOK2_DIR = __BOOKDIR2_VALUE__;
|
|||
"pdfExportPdfVisible",
|
||||
"pdfStatusShown",
|
||||
"pdfExportOk",
|
||||
"printBookHiddenOnScreen",
|
||||
"printBookHasAllChapters",
|
||||
"printBookLongFull",
|
||||
"pdfLongExportOk",
|
||||
];
|
||||
out.all = okFlags.every((f) => out[f] === true);
|
||||
} catch (e) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue