diff --git a/src/io/wordOffice.test.ts b/src/io/wordOffice.test.ts index 5e9a703..3533205 100644 --- a/src/io/wordOffice.test.ts +++ b/src/io/wordOffice.test.ts @@ -376,6 +376,39 @@ describe("wordOffice helpers", () => { expect(documentXml).toContain("Итог"); }); + it("сохраняет inline-форматирование ячеек таблицы для DOCX", async () => { + const html = ` +
| Итог готов | +Отчет | +
Normal Large Pixel size
diff --git a/src/io/wordOffice.ts b/src/io/wordOffice.ts index 560b2e1..9848e8c 100644 --- a/src/io/wordOffice.ts +++ b/src/io/wordOffice.ts @@ -25,6 +25,8 @@ export interface WordListItem { runs: WordInlineRun[]; } +export type WordTableCell = string | { text: string; runs: WordInlineRun[] }; + export interface WordImageBlock { type: "image"; src: string; @@ -74,7 +76,7 @@ export type WordBlock = quote?: boolean; } | { type: "list"; ordered: boolean; items: WordListItem[] } - | { type: "table"; rows: string[][] } + | { type: "table"; rows: WordTableCell[][] } | WordImageBlock; type MammothModule = { @@ -405,11 +407,7 @@ function wordBlockToDocxChildren(block: WordBlock, docx: DocxModule) { children: row.map( (cell) => new docx.TableCell({ - children: [ - new docx.Paragraph({ - children: [new docx.TextRun(cell)] - }) - ] + children: wordTableCellToDocxParagraphs(cell, docx) }) ) }) @@ -418,6 +416,15 @@ function wordBlockToDocxChildren(block: WordBlock, docx: DocxModule) { ]; } +function wordTableCellToDocxParagraphs(cell: WordTableCell, docx: DocxModule) { + const runs = typeof cell === "string" ? [{ text: cell }] : cell.runs; + return [ + new docx.Paragraph({ + children: wordInlineRunsToTextRuns(runs, docx) + }) + ]; +} + export function wordInlineRunsToTextRunOptions(runs: WordInlineRun[]) { return runs.map(wordInlineRunToTextRunOption); } @@ -647,10 +654,17 @@ function parseHtmlFragment(html: string) { function tableRows(table: Element) { return Array.from(table.querySelectorAll("tr")) - .map((row) => Array.from(row.querySelectorAll("th,td")).map(elementText)) + .map((row) => Array.from(row.querySelectorAll("th,td")).map(tableCellValue)) .filter((row) => row.length > 0); } +function tableCellValue(cell: Element): WordTableCell { + const runs = elementInlineRuns(cell); + const text = inlineRunsText(runs); + const hasFormattedRuns = runs.some((run) => Object.keys(cleanInlineFormat(run)).length > 0); + return hasFormattedRuns ? { text, runs } : text; +} + function paragraphElementToBlocks(element: Element, options: { quote?: boolean } = {}): WordBlock[] { const segments = collectInlineSegments(Array.from(element.childNodes), {}); const alignment = paragraphAlignmentFromElement(element);