Support full QWord heading hierarchy in DOCX
This commit is contained in:
+25
-14
@@ -39,8 +39,10 @@ export interface WordParagraphIndent {
|
||||
hanging?: number;
|
||||
}
|
||||
|
||||
export type WordHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
||||
|
||||
export type WordBlock =
|
||||
| { type: "heading"; level: 1 | 2 | 3; text: string; runs: WordInlineRun[]; alignment?: WordParagraphAlignment; indent?: WordParagraphIndent; bookmark?: string }
|
||||
| { type: "heading"; level: WordHeadingLevel; 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[][] }
|
||||
@@ -111,7 +113,10 @@ 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 3'] => h3:fresh"
|
||||
"p[style-name='Heading 3'] => h3:fresh",
|
||||
"p[style-name='Heading 4'] => h4:fresh",
|
||||
"p[style-name='Heading 5'] => h5:fresh",
|
||||
"p[style-name='Heading 6'] => h6:fresh"
|
||||
];
|
||||
const xmlParserOptions = {
|
||||
ignoreAttributes: false,
|
||||
@@ -239,7 +244,7 @@ export function htmlToWordBlocks(html: string): WordBlock[] {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tagName === "h1" || tagName === "h2" || tagName === "h3") {
|
||||
if (isHeadingTagName(tagName)) {
|
||||
const runs = elementInlineRuns(node);
|
||||
const text = inlineRunsText(runs);
|
||||
const alignment = paragraphAlignmentFromElement(node);
|
||||
@@ -382,20 +387,17 @@ 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 isHeadingTagName(tagName: string): tagName is `h${WordHeadingLevel}` {
|
||||
return /^h[1-6]$/.test(tagName);
|
||||
}
|
||||
|
||||
function docxHeadingLevel(level: 1 | 2 | 3, docx: DocxModule) {
|
||||
if (level === 3) {
|
||||
return docx.HeadingLevel.HEADING_3 ?? docx.HeadingLevel.HEADING_2;
|
||||
}
|
||||
function headingLevelFromTagName(tagName: `h${WordHeadingLevel}`): WordHeadingLevel {
|
||||
return Number.parseInt(tagName.slice(1), 10) as WordHeadingLevel;
|
||||
}
|
||||
|
||||
return level === 1 ? docx.HeadingLevel.HEADING_1 : docx.HeadingLevel.HEADING_2;
|
||||
function docxHeadingLevel(level: WordHeadingLevel, docx: DocxModule) {
|
||||
const headingKey = `HEADING_${level}`;
|
||||
return docx.HeadingLevel[headingKey] ?? docx.HeadingLevel.HEADING_2;
|
||||
}
|
||||
|
||||
function wordInlineRunToTextRunOption(run: WordInlineRun) {
|
||||
@@ -1025,6 +1027,15 @@ function docxParagraphTagName(properties: XmlRecord) {
|
||||
if (["heading3", "heading 3"].includes(styleValue)) {
|
||||
return "h3";
|
||||
}
|
||||
if (["heading4", "heading 4"].includes(styleValue)) {
|
||||
return "h4";
|
||||
}
|
||||
if (["heading5", "heading 5"].includes(styleValue)) {
|
||||
return "h5";
|
||||
}
|
||||
if (["heading6", "heading 6"].includes(styleValue)) {
|
||||
return "h6";
|
||||
}
|
||||
|
||||
return "p";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user