Add DOCX and ODT export for the Full Book view
The main process now assembles the manuscript from the chapter files and renders it to a Word document with the docx library, using the same markdown-it plugin set as the on-screen renderer (highlight, callouts, wikilinks). ODT is converted from that DOCX with LibreOffice running headless, keeping the two formats consistent; a clear error is returned when LibreOffice is missing. The Full Book header's single Export PDF button becomes an Export menu (PDF/DOCX/ODT) wired to the File menu. Tests: new run-office-export-test.mjs verifies DOCX/ODT structure, chapter order and formatting; the e2e scenario exports through the real IPC chain and checks magic bytes, extensions and the status notices.
This commit is contained in:
parent
ad0329bbf9
commit
6679294231
12 changed files with 1403 additions and 15 deletions
|
|
@ -408,16 +408,22 @@ const BOOK3_DIR = __BOOKDIR3_VALUE__;
|
|||
out.fbWithEmpty = assembledWithEmpty;
|
||||
out.fbEmptyOk = assembledWithEmpty.includes("# Empty") && assembledWithEmpty.includes("Beta Renamed");
|
||||
|
||||
// --- PDF export of the Full Book ---
|
||||
// The e2e harness sets FOLIO_TEST_PDF, so the main process skips the
|
||||
// native save dialog and writes to that path, returning the byte count
|
||||
// and whether the buffer starts with the PDF magic number. The Full Book
|
||||
// view is on screen here, so what gets printed is exactly the assembled
|
||||
// manuscript (the print stylesheet hides all app chrome).
|
||||
const pdfBtn = document.getElementById("exportPdfBtn");
|
||||
out.pdfBtnPresent = !!pdfBtn && !pdfBtn.disabled;
|
||||
// --- Export of the Full Book (PDF / DOCX / ODT) ---
|
||||
// The e2e harness sets FOLIO_TEST_PDF/DOCX/ODT, so the main process skips
|
||||
// the native save dialog and writes to those paths, returning the byte
|
||||
// count and whether the buffer starts with the right magic number. The
|
||||
// Full Book view is on screen here, so the PDF is the assembled manuscript
|
||||
// (the print stylesheet hides all app chrome).
|
||||
const exportMenuToggle = document.getElementById("exportMenuToggle");
|
||||
const exportMenu = document.getElementById("exportMenu");
|
||||
out.exportMenuPresent = !!exportMenuToggle && !!exportMenu;
|
||||
out.pdfExportPdfVisible = !document.getElementById("fullBookView").classList.contains("hidden");
|
||||
pdfBtn.click();
|
||||
exportMenuToggle.click();
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
out.exportMenuOpened = !exportMenu.classList.contains("hidden");
|
||||
const pdfItem = exportMenu.querySelector('[data-export="pdf"]');
|
||||
out.pdfItemPresent = !!pdfItem;
|
||||
pdfItem.click();
|
||||
await new Promise((r) => setTimeout(r, 2500));
|
||||
out.pdfStatusShown = document
|
||||
.getElementById("fullBookStatus")
|
||||
|
|
@ -485,6 +491,39 @@ const BOOK3_DIR = __BOOKDIR3_VALUE__;
|
|||
pdfLongRes.bytes > pdfRes.bytes * 2 &&
|
||||
pdfLongRes.pdfOk === true;
|
||||
|
||||
// DOCX export: main process assembles the manuscript from the chapter
|
||||
// files (all four chapters, including the very long one), writes a ZIP
|
||||
// (PK magic) to FOLIO_TEST_DOCX, and reports its size. The deep content
|
||||
// checks live in tests/run-office-export-test.mjs; here we verify the
|
||||
// end-to-end IPC path, extension, magic number, and the status notice.
|
||||
const docxRes = await window.folio.exportDocx();
|
||||
out.docxExport =
|
||||
docxRes && "filePath" in docxRes
|
||||
? { filePath: docxRes.filePath, bytes: docxRes.bytes, docxOk: docxRes.docxOk }
|
||||
: docxRes;
|
||||
out.docxExportOk =
|
||||
!!docxRes &&
|
||||
!("error" in docxRes) &&
|
||||
"filePath" in docxRes &&
|
||||
docxRes.filePath.endsWith(".docx") &&
|
||||
typeof docxRes.bytes === "number" &&
|
||||
docxRes.bytes > 1000 &&
|
||||
docxRes.docxOk === true;
|
||||
|
||||
const odtRes = await window.folio.exportOdt();
|
||||
out.odtExport =
|
||||
odtRes && "filePath" in odtRes
|
||||
? { filePath: odtRes.filePath, bytes: odtRes.bytes, odtOk: odtRes.odtOk }
|
||||
: odtRes;
|
||||
out.odtExportOk =
|
||||
!!odtRes &&
|
||||
!("error" in odtRes) &&
|
||||
"filePath" in odtRes &&
|
||||
odtRes.filePath.endsWith(".odt") &&
|
||||
typeof odtRes.bytes === "number" &&
|
||||
odtRes.bytes > 1000 &&
|
||||
odtRes.odtOk === true;
|
||||
|
||||
// Formatting must survive into the printed book: markdown-it is configured
|
||||
// to pass through the toolbar's HTML (<u>, <span style=...>, <div>),
|
||||
// ==highlight== becomes <mark>, callouts become styled divs, and
|
||||
|
|
@ -810,7 +849,9 @@ const BOOK3_DIR = __BOOKDIR3_VALUE__;
|
|||
"fbAfterDeleteOk",
|
||||
"fbAfterRenameOk",
|
||||
"fbEmptyOk",
|
||||
"pdfBtnPresent",
|
||||
"exportMenuPresent",
|
||||
"exportMenuOpened",
|
||||
"pdfItemPresent",
|
||||
"pdfExportPdfVisible",
|
||||
"pdfStatusShown",
|
||||
"pdfExportOk",
|
||||
|
|
@ -818,6 +859,8 @@ const BOOK3_DIR = __BOOKDIR3_VALUE__;
|
|||
"printBookHasAllChapters",
|
||||
"printBookLongFull",
|
||||
"pdfLongExportOk",
|
||||
"docxExportOk",
|
||||
"odtExportOk",
|
||||
"printFmtOk",
|
||||
"navOptionsOk",
|
||||
"navOpenAtOneOk",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue