Support QWord Heading 3 DOCX roundtrip
This commit is contained in:
+25
-5
@@ -40,7 +40,7 @@ export interface WordParagraphIndent {
|
||||
}
|
||||
|
||||
export type WordBlock =
|
||||
| { type: "heading"; level: 1 | 2; text: string; runs: WordInlineRun[]; alignment?: WordParagraphAlignment; indent?: WordParagraphIndent; bookmark?: string }
|
||||
| { type: "heading"; level: 1 | 2 | 3; text: string; runs: WordInlineRun[]; alignment?: WordParagraphAlignment; indent?: WordParagraphIndent; bookmark?: string }
|
||||
| { type: "paragraph"; text: string; runs: WordInlineRun[]; alignment?: WordParagraphAlignment; indent?: WordParagraphIndent; bookmark?: string }
|
||||
| { type: "list"; ordered: boolean; items: WordListItem[] }
|
||||
| { type: "table"; rows: string[][] }
|
||||
@@ -110,7 +110,8 @@ type DocxListInfo = { ordered: boolean; level: number; key: string };
|
||||
const mammothStyleMap = [
|
||||
"p[style-name='Title'] => h1:fresh",
|
||||
"p[style-name='Heading 1'] => h1:fresh",
|
||||
"p[style-name='Heading 2'] => h2:fresh"
|
||||
"p[style-name='Heading 2'] => h2:fresh",
|
||||
"p[style-name='Heading 3'] => h3:fresh"
|
||||
];
|
||||
const xmlParserOptions = {
|
||||
ignoreAttributes: false,
|
||||
@@ -238,7 +239,7 @@ export function htmlToWordBlocks(html: string): WordBlock[] {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tagName === "h1" || tagName === "h2") {
|
||||
if (tagName === "h1" || tagName === "h2" || tagName === "h3") {
|
||||
const runs = elementInlineRuns(node);
|
||||
const text = inlineRunsText(runs);
|
||||
const alignment = paragraphAlignmentFromElement(node);
|
||||
@@ -247,7 +248,7 @@ export function htmlToWordBlocks(html: string): WordBlock[] {
|
||||
if (text) {
|
||||
blocks.push({
|
||||
type: "heading",
|
||||
level: tagName === "h1" ? 1 : 2,
|
||||
level: headingLevelFromTagName(tagName),
|
||||
text,
|
||||
runs,
|
||||
...(alignment ? { alignment } : {}),
|
||||
@@ -299,7 +300,7 @@ function wordBlockToDocxChildren(block: WordBlock, docx: DocxModule) {
|
||||
const children = wordInlineRunsToTextRuns(block.runs, docx);
|
||||
return [
|
||||
new docx.Paragraph({
|
||||
heading: block.level === 1 ? docx.HeadingLevel.HEADING_1 : docx.HeadingLevel.HEADING_2,
|
||||
heading: docxHeadingLevel(block.level, docx),
|
||||
spacing: { after: 160 },
|
||||
...docxAlignmentOption(block.alignment, docx),
|
||||
...docxIndentOption(block.indent),
|
||||
@@ -381,6 +382,22 @@ export function wordInlineRunsToTextRunOptions(runs: WordInlineRun[]) {
|
||||
return runs.map(wordInlineRunToTextRunOption);
|
||||
}
|
||||
|
||||
function headingLevelFromTagName(tagName: string): 1 | 2 | 3 {
|
||||
if (tagName === "h3") {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return tagName === "h2" ? 2 : 1;
|
||||
}
|
||||
|
||||
function docxHeadingLevel(level: 1 | 2 | 3, docx: DocxModule) {
|
||||
if (level === 3) {
|
||||
return docx.HeadingLevel.HEADING_3 ?? docx.HeadingLevel.HEADING_2;
|
||||
}
|
||||
|
||||
return level === 1 ? docx.HeadingLevel.HEADING_1 : docx.HeadingLevel.HEADING_2;
|
||||
}
|
||||
|
||||
function wordInlineRunToTextRunOption(run: WordInlineRun) {
|
||||
const options: Record<string, unknown> = { text: run.text };
|
||||
if (run.bold) {
|
||||
@@ -1005,6 +1022,9 @@ function docxParagraphTagName(properties: XmlRecord) {
|
||||
if (["heading2", "heading 2"].includes(styleValue)) {
|
||||
return "h2";
|
||||
}
|
||||
if (["heading3", "heading 3"].includes(styleValue)) {
|
||||
return "h3";
|
||||
}
|
||||
|
||||
return "p";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user