TOC content generation aborted
This commit is contained in:
@ -52,7 +52,6 @@
|
||||
"fast-xml-parser": "^3.3.6",
|
||||
"image-size": "^0.6.2",
|
||||
"jszip": "^3.1.5",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"xml": "^1.0.1"
|
||||
},
|
||||
"author": "Dolan Miu",
|
||||
|
@ -34,8 +34,6 @@ export class Compiler {
|
||||
}
|
||||
|
||||
public async compile(file: File): Promise<JSZip> {
|
||||
file.generateTablesOfContents();
|
||||
|
||||
const zip = new JSZip();
|
||||
|
||||
const xmlifiedFileMapping = this.xmlifyFile(file);
|
||||
@ -65,6 +63,7 @@ export class Compiler {
|
||||
}
|
||||
|
||||
private xmlifyFile(file: File): IXmlifyedFileMapping {
|
||||
file.verifyUpdateFields();
|
||||
return {
|
||||
Document: {
|
||||
data: xml(this.formatter.format(file.Document), true),
|
||||
|
@ -8,16 +8,14 @@ import { FootNotes } from "./footnotes";
|
||||
import { HeaderWrapper } from "./header-wrapper";
|
||||
import { Image, Media } from "./media";
|
||||
import { Numbering } from "./numbering";
|
||||
import { Bookmark, Hyperlink, Paragraph, Run, TextRun } from "./paragraph";
|
||||
import { Begin, End, Separate } from "./paragraph/run/field";
|
||||
import { Tab } from "./paragraph/run/tab";
|
||||
import { Bookmark, Hyperlink, Paragraph } from "./paragraph";
|
||||
import { Relationships } from "./relationships";
|
||||
import { Settings } from "./settings";
|
||||
import { Styles } from "./styles";
|
||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||
import { DefaultStylesFactory } from "./styles/factory";
|
||||
import { Table } from "./table";
|
||||
import { PageReferenceInstruction, TableOfContents } from "./table-of-contents";
|
||||
import { TableOfContents } from "./table-of-contents";
|
||||
|
||||
export class File {
|
||||
private readonly document: Document;
|
||||
@ -36,7 +34,6 @@ export class File {
|
||||
private readonly appProperties: AppProperties;
|
||||
|
||||
private currentRelationshipId: number = 1;
|
||||
private currentTocBookmarkId: number = 1;
|
||||
|
||||
constructor(options?: IPropertiesOptions, sectionPropertiesOptions?: SectionPropertiesOptions) {
|
||||
if (!options) {
|
||||
@ -297,76 +294,9 @@ export class File {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
public generateTablesOfContents(): void {
|
||||
// console.log("generateTablesOfContents");
|
||||
const TOCs = this.document.getTablesOfContents();
|
||||
if (TOCs && TOCs.length) {
|
||||
public verifyUpdateFields(): void {
|
||||
if (this.document.getTablesOfContents().length) {
|
||||
this.settings.addUpdateFields();
|
||||
TOCs.forEach((child) => this.generateContent(child));
|
||||
}
|
||||
}
|
||||
|
||||
private generateContent(toc: TableOfContents): void {
|
||||
// console.log("TOC", JSON.stringify(toc));
|
||||
if (toc.getHeaderRange()) {
|
||||
this.generateContentForHeaderRange(toc);
|
||||
}
|
||||
}
|
||||
|
||||
private generateContentForHeaderRange(toc: TableOfContents): void {
|
||||
const headerRange = toc.getHeaderRange();
|
||||
const hyphenIndex = headerRange.indexOf("-");
|
||||
// console.log("Hyphen Index: ", hyphenIndex);
|
||||
if (hyphenIndex !== -1) {
|
||||
const rangeBegin = parseInt(headerRange.substring(0, hyphenIndex), 10);
|
||||
const rangeEnd = parseInt(headerRange.substring(hyphenIndex + 1), 10);
|
||||
const styles = new Array<string>();
|
||||
for (let i = rangeBegin; i <= rangeEnd; i++) {
|
||||
styles.push(`Heading${i}`);
|
||||
}
|
||||
// console.log("Find Headers for range ", rangeBegin, " - ", rangeEnd, styles.join(","));
|
||||
this.document
|
||||
.getParagraphs()
|
||||
.filter((paragraph) => this.paragraphContainAnyStyle(paragraph, styles))
|
||||
.forEach((paragraph) => this.generateContentForParagraph(paragraph, toc));
|
||||
} else {
|
||||
throw new Error(`Invalid headerRange: '${headerRange}'`);
|
||||
}
|
||||
}
|
||||
|
||||
private paragraphContainAnyStyle(paragraph: Paragraph, styles: string[]): boolean {
|
||||
return paragraph.getStyles().some((style) => styles.indexOf(style.styleId) !== -1);
|
||||
}
|
||||
|
||||
private generateContentForParagraph(paragraph: Paragraph, toc: TableOfContents): void {
|
||||
const bookmarkId = `_TOC_${this.currentTocBookmarkId}`;
|
||||
// console.log("Generating content for paragraph: ", bookmarkId);
|
||||
|
||||
// deep clone the original paragraph
|
||||
const generatedParagraph = paragraph.clone() as Paragraph;
|
||||
|
||||
generatedParagraph.clearPageBreaks().maxRightTabStop("dot");
|
||||
|
||||
const tabRun = new Run();
|
||||
tabRun.addChildElement(new Tab());
|
||||
generatedParagraph.addChildElement(tabRun);
|
||||
|
||||
const beginRun = new Run();
|
||||
beginRun.addChildElement(new Begin(true));
|
||||
beginRun.addChildElement(new PageReferenceInstruction(bookmarkId));
|
||||
beginRun.addChildElement(new Separate());
|
||||
generatedParagraph.addRun(beginRun);
|
||||
|
||||
generatedParagraph.addRun(new TextRun("?"));
|
||||
|
||||
const endRun = new Run();
|
||||
endRun.addChildElement(new End());
|
||||
generatedParagraph.addRun(endRun);
|
||||
|
||||
toc.addGeneratedContent(generatedParagraph);
|
||||
|
||||
paragraph.addBookmark(this.createBookmark(bookmarkId, ""));
|
||||
// console.log("Paragraph after content generation", JSON.stringify(paragraph, null, 2));
|
||||
this.currentTocBookmarkId++;
|
||||
}
|
||||
}
|
||||
|
@ -393,43 +393,4 @@ describe("Paragraph", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#clone", () => {
|
||||
it("changes in a cloned paragraph must not affect the original paragraph", () => {
|
||||
paragraph.pageBreakBefore();
|
||||
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({ "w:p": [{ "w:pPr": [{ "w:pageBreakBefore": [] }] }] }, "Paragraph with a page break before");
|
||||
|
||||
const clonedParagraph = paragraph.clone();
|
||||
expect(clonedParagraph).to.be.instanceof(file.Paragraph);
|
||||
expect(clonedParagraph.paragraphProperties).to.be.instanceof(file.ParagraphProperties);
|
||||
|
||||
const clonedTree = new Formatter().format(clonedParagraph);
|
||||
expect(clonedTree).to.deep.equal(
|
||||
{
|
||||
"w:p": [{ "w:pPr": [{ "w:pageBreakBefore": [] }] }],
|
||||
},
|
||||
"Cloned Paragraph with page break before",
|
||||
);
|
||||
|
||||
clonedParagraph.clearPageBreaks();
|
||||
|
||||
const clonedTreeAfter = new Formatter().format(clonedParagraph);
|
||||
expect(clonedTreeAfter).to.deep.equal(
|
||||
{
|
||||
"w:p": [{ "w:pPr": [] }],
|
||||
},
|
||||
"Cloned Paragraph after clearPageBreaks must have no properties",
|
||||
);
|
||||
|
||||
const treeAfter = new Formatter().format(paragraph);
|
||||
expect(treeAfter).to.deep.equal(
|
||||
{
|
||||
"w:p": [{ "w:pPr": [{ "w:pageBreakBefore": [] }] }],
|
||||
},
|
||||
"Paragraph after clearPageBreaks in Cloned Paragraph must keep the properties.",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,4 @@
|
||||
// http://officeopenxml.com/WPparagraph.php
|
||||
import * as cloneDeep from "lodash.clonedeep";
|
||||
|
||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
import { Image } from "file/media";
|
||||
import { Num } from "file/numbering/num";
|
||||
@ -252,8 +250,4 @@ export class Paragraph extends XmlComponent {
|
||||
this.properties.clearPageBreaks();
|
||||
return this;
|
||||
}
|
||||
|
||||
public clone(): Paragraph {
|
||||
return cloneDeep(this, false);
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1 @@
|
||||
export * from "./table-of-contents";
|
||||
export * from "./page-reference-instruction";
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class TextAttributes extends XmlAttributeComponent<{ space: "default" | "preserve" }> {
|
||||
protected xmlKeys = { space: "xml:space" };
|
||||
}
|
||||
|
||||
export class PageReferenceInstruction extends XmlComponent {
|
||||
constructor(bookmarkId: string) {
|
||||
super("w:instrText");
|
||||
this.root.push(new TextAttributes({ space: "preserve" }));
|
||||
this.root.push(`PAGEREF ${bookmarkId} \h`);
|
||||
}
|
||||
}
|
@ -1,12 +1,7 @@
|
||||
import { Paragraph } from "file/paragraph";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
export class SdtContent extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:sdtContent");
|
||||
}
|
||||
|
||||
public addGeneratedContent(paragraph: Paragraph): void {
|
||||
this.root.splice(this.root.length - 1, 0, paragraph);
|
||||
}
|
||||
}
|
||||
|
@ -8,41 +8,26 @@ import { SdtProperties } from "./sdt-properties";
|
||||
import { TableOfContentsInstruction } from "./table-of-contents-instruction";
|
||||
|
||||
export class TableOfContents extends XmlComponent {
|
||||
// private readonly tocProperties: TableOfContentsProperties;
|
||||
private readonly properties: SdtProperties;
|
||||
|
||||
private readonly content: SdtContent;
|
||||
|
||||
private readonly instruction: TableOfContentsInstruction;
|
||||
|
||||
constructor(/*tocProperties?: TableOfContentsProperties*/) {
|
||||
constructor() {
|
||||
super("w:sdt");
|
||||
this.properties = new SdtProperties("Table of Contents");
|
||||
this.content = new SdtContent();
|
||||
this.instruction = new TableOfContentsInstruction();
|
||||
this.root.push(this.properties);
|
||||
this.root.push(this.content);
|
||||
// this.tocProperties = tocProperties || new TableOfContentsProperties();
|
||||
this.root.push(new SdtProperties("Table of Contents"));
|
||||
|
||||
const content = new SdtContent();
|
||||
|
||||
const beginParagraph = new Paragraph();
|
||||
const beginRun = new Run();
|
||||
beginRun.addChildElement(new Begin(true));
|
||||
beginRun.addChildElement(this.instruction);
|
||||
beginRun.addChildElement(new TableOfContentsInstruction());
|
||||
beginRun.addChildElement(new Separate());
|
||||
beginParagraph.addRun(beginRun);
|
||||
this.content.addChildElement(beginParagraph);
|
||||
content.addChildElement(beginParagraph);
|
||||
|
||||
const endParagraph = new Paragraph();
|
||||
const endRun = new Run();
|
||||
endRun.addChildElement(new End());
|
||||
endParagraph.addRun(endRun);
|
||||
this.content.addChildElement(endParagraph);
|
||||
}
|
||||
content.addChildElement(endParagraph);
|
||||
|
||||
public getHeaderRange(): string {
|
||||
return this.instruction.getHeaderRange();
|
||||
}
|
||||
|
||||
public addGeneratedContent(paragraph: Paragraph): void {
|
||||
this.content.addGeneratedContent(paragraph);
|
||||
this.root.push(content);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user