diff --git a/package.json b/package.json index e63dd166bf..e10bd3b7ba 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "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", diff --git a/src/file/file.ts b/src/file/file.ts index 8d1b07f827..63d5fa1656 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -345,14 +345,14 @@ export class File { // deep clone the original paragraph const generatedParagraph = paragraph.clone() as Paragraph; - generatedParagraph.clearPageBreaks().rightTabStop(9016, "dot"); + generatedParagraph.clearPageBreaks().maxRightTabStop("dot"); const tabRun = new Run(); tabRun.addChildElement(new Tab()); generatedParagraph.addChildElement(tabRun); const beginRun = new Run(); - beginRun.addChildElement(new Begin()); + beginRun.addChildElement(new Begin(true)); beginRun.addChildElement(new PageReferenceInstruction(bookmarkId)); beginRun.addChildElement(new Separate()); generatedParagraph.addRun(beginRun); diff --git a/src/file/paragraph/formatting/tab-stop.ts b/src/file/paragraph/formatting/tab-stop.ts index bcaeee8371..5dc4f68e4f 100644 --- a/src/file/paragraph/formatting/tab-stop.ts +++ b/src/file/paragraph/formatting/tab-stop.ts @@ -29,8 +29,8 @@ export class TabStopItem extends XmlComponent { } export class MaxRightTabStop extends TabStop { - constructor() { - super(new TabStopItem("right", 9026)); + constructor(leader?: LeaderType) { + super(new TabStopItem("right", 9026, leader)); } } diff --git a/src/file/paragraph/paragraph.spec.ts b/src/file/paragraph/paragraph.spec.ts index 5bf4ee5f15..2ab8836f96 100644 --- a/src/file/paragraph/paragraph.spec.ts +++ b/src/file/paragraph/paragraph.spec.ts @@ -398,18 +398,38 @@ describe("Paragraph", () => { it("changes in a cloned paragraph must not affect the original paragraph", () => { paragraph.pageBreakBefore(); - const clonedParagraph = paragraph.clone() as file.Paragraph; - clonedParagraph.clearPageBreaks(); - const tree = new Formatter().format(paragraph); - expect(tree).to.deep.equal({ - "w:p": [{ "w:pPr": [{ "w:pageBreakBefore": [] }] }], - }); + 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": [] }], - }); + 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.", + ); }); }); }); diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index 2de547bb7a..16f6ef0cd1 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -1,4 +1,6 @@ // 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"; @@ -30,6 +32,10 @@ export class Paragraph extends XmlComponent { } } + public get paragraphProperties(): ParagraphProperties { + return this.properties; + } + public get Borders(): Border { return this.properties.paragraphBorder; } @@ -155,8 +161,8 @@ export class Paragraph extends XmlComponent { return this; } - public maxRightTabStop(): Paragraph { - this.properties.push(new MaxRightTabStop()); + public maxRightTabStop(leader?: LeaderType): Paragraph { + this.properties.push(new MaxRightTabStop(leader)); return this; } @@ -246,4 +252,8 @@ export class Paragraph extends XmlComponent { this.properties.clearPageBreaks(); return this; } + + public clone(): Paragraph { + return cloneDeep(this, false); + } } diff --git a/src/file/paragraph/run/field.ts b/src/file/paragraph/run/field.ts index 8465418cf7..0e72c1d624 100644 --- a/src/file/paragraph/run/field.ts +++ b/src/file/paragraph/run/field.ts @@ -1,26 +1,26 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; -class FidCharAttrs extends XmlAttributeComponent<{ type: "begin" | "end" | "separate" }> { - protected xmlKeys = { type: "w:fldCharType" }; +class FidCharAttrs extends XmlAttributeComponent<{ type: "begin" | "end" | "separate"; dirty?: boolean }> { + protected xmlKeys = { type: "w:fldCharType", dirty: "w:dirty" }; } export class Begin extends XmlComponent { - constructor() { + constructor(dirty?: boolean) { super("w:fldChar"); - this.root.push(new FidCharAttrs({ type: "begin" })); + this.root.push(new FidCharAttrs({ type: "begin", dirty })); } } export class Separate extends XmlComponent { - constructor() { + constructor(dirty?: boolean) { super("w:fldChar"); - this.root.push(new FidCharAttrs({ type: "separate" })); + this.root.push(new FidCharAttrs({ type: "separate", dirty })); } } export class End extends XmlComponent { - constructor() { + constructor(dirty?: boolean) { super("w:fldChar"); - this.root.push(new FidCharAttrs({ type: "end" })); + this.root.push(new FidCharAttrs({ type: "end", dirty })); } } diff --git a/src/file/table-of-contents/table-of-contents.spec.ts b/src/file/table-of-contents/table-of-contents.spec.ts index d29b3ffc75..9ae3c53da5 100644 --- a/src/file/table-of-contents/table-of-contents.spec.ts +++ b/src/file/table-of-contents/table-of-contents.spec.ts @@ -35,6 +35,7 @@ const DEFAULT_TOC = { { _attr: { "w:fldCharType": "begin", + "w:dirty": true, }, }, ], diff --git a/src/file/table-of-contents/table-of-contents.ts b/src/file/table-of-contents/table-of-contents.ts index f6f70558f9..ded1be62cc 100644 --- a/src/file/table-of-contents/table-of-contents.ts +++ b/src/file/table-of-contents/table-of-contents.ts @@ -25,7 +25,7 @@ export class TableOfContents extends XmlComponent { // this.tocProperties = tocProperties || new TableOfContentsProperties(); const beginParagraph = new Paragraph(); const beginRun = new Run(); - beginRun.addChildElement(new Begin()); + beginRun.addChildElement(new Begin(true)); beginRun.addChildElement(this.instruction); beginRun.addChildElement(new Separate()); beginParagraph.addRun(beginRun); diff --git a/src/file/xml-components/xml-component.ts b/src/file/xml-components/xml-component.ts index 68b50da59d..fae843db29 100644 --- a/src/file/xml-components/xml-component.ts +++ b/src/file/xml-components/xml-component.ts @@ -39,10 +39,4 @@ export abstract class XmlComponent extends BaseXmlComponent { public delete(): void { this.deleted = true; } - - public clone(): XmlComponent { - const newXmlComponent = Object.assign(Object.create(Object.getPrototypeOf(this)), this); - newXmlComponent.root = newXmlComponent.root.map((child) => (child instanceof XmlComponent ? child.clone() : child)); - return newXmlComponent as XmlComponent; - } }