From cb42c74a8d865d67a329af978e36aba52ef3a424 Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 12 Jun 2019 01:03:36 +0100 Subject: [PATCH] Make Paragraph declaritive --- src/export/formatter.spec.ts | 10 +- src/export/packer/packer.spec.ts | 21 +- src/file/document/body/body.ts | 4 +- src/file/document/document.spec.ts | 27 -- src/file/document/document.ts | 6 - src/file/file.spec.ts | 12 +- src/file/file.ts | 4 - src/file/footer-wrapper.spec.ts | 12 +- src/file/footer-wrapper.ts | 6 - src/file/footer/footer.ts | 6 - src/file/footnotes/footnotes.ts | 16 +- src/file/header-wrapper.spec.ts | 12 +- src/file/header-wrapper.ts | 6 - src/file/header/header.ts | 6 - src/file/numbering/level.ts | 12 +- src/file/numbering/numbering.spec.ts | 4 +- src/file/paragraph/formatting/alignment.ts | 7 +- .../paragraph/formatting/border-attributes.ts | 17 + src/file/paragraph/formatting/border.spec.ts | 4 +- src/file/paragraph/formatting/border.ts | 85 ++--- src/file/paragraph/formatting/style.ts | 10 + src/file/paragraph/image.ts | 2 +- .../paragraph/links/outline-level.spec.ts | 8 +- src/file/paragraph/links/outline-level.ts | 6 +- src/file/paragraph/paragraph.spec.ts | 237 ++++++++----- src/file/paragraph/paragraph.ts | 321 ++++++++---------- src/file/paragraph/properties.ts | 18 +- .../styles/defaults/paragraph-properties.ts | 2 +- src/file/styles/style/paragraph-style.spec.ts | 8 +- src/file/styles/style/paragraph-style.ts | 14 +- .../table-of-contents/table-of-contents.ts | 4 +- src/file/table/table-cell/table-cell.ts | 10 +- src/file/table/table.spec.ts | 31 -- 33 files changed, 451 insertions(+), 497 deletions(-) create mode 100644 src/file/paragraph/formatting/border-attributes.ts diff --git a/src/export/formatter.spec.ts b/src/export/formatter.spec.ts index 47d7773529..a76bad29c0 100644 --- a/src/export/formatter.spec.ts +++ b/src/export/formatter.spec.ts @@ -15,23 +15,23 @@ describe("Formatter", () => { describe("#format()", () => { it("should format simple paragraph", () => { - const paragraph = new file.Paragraph(); + const paragraph = new file.Paragraph(""); const newJson = formatter.format(paragraph); assert.isDefined(newJson["w:p"]); }); it("should remove xmlKeys", () => { - const paragraph = new file.Paragraph(); + const paragraph = new file.Paragraph(""); const newJson = formatter.format(paragraph); const stringifiedJson = JSON.stringify(newJson); assert(stringifiedJson.indexOf("xmlKeys") < 0); }); it("should format simple paragraph with bold text", () => { - const paragraph = new file.Paragraph(); + const paragraph = new file.Paragraph(""); paragraph.addRun(new file.TextRun("test").bold()); const newJson = formatter.format(paragraph); - assert.isDefined(newJson["w:p"][0]["w:r"][0]["w:rPr"][0]["w:b"]._attr["w:val"]); + assert.isDefined(newJson["w:p"][1]["w:r"][0]["w:rPr"][0]["w:b"]._attr["w:val"]); }); it("should format attributes (rsidSect)", () => { @@ -61,7 +61,7 @@ describe("Formatter", () => { }); it("should should change 'p' tag into 'w:p' tag", () => { - const paragraph = new file.Paragraph(); + const paragraph = new file.Paragraph(""); const newJson = formatter.format(paragraph); assert.isDefined(newJson["w:p"]); }); diff --git a/src/export/packer/packer.spec.ts b/src/export/packer/packer.spec.ts index b61165ab46..944b5892e2 100644 --- a/src/export/packer/packer.spec.ts +++ b/src/export/packer/packer.spec.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import { stub } from "sinon"; -import { File, Paragraph } from "file"; +import { File, HeadingLevel, Paragraph } from "file"; import { Packer } from "./packer"; @@ -17,11 +17,24 @@ describe("Packer", () => { lastModifiedBy: "Dolan Miu", }); const paragraph = new Paragraph("test text"); - const heading = new Paragraph("Hello world").heading1(); + const heading = new Paragraph({ + text: "Hello world", + heading: HeadingLevel.HEADING_1, + }); - file.addParagraph(new Paragraph("title").title()); + file.addParagraph( + new Paragraph({ + text: "title", + heading: HeadingLevel.TITLE, + }), + ); file.addParagraph(heading); - file.addParagraph(new Paragraph("heading 2").heading2()); + file.addParagraph( + new Paragraph({ + text: "heading 2", + heading: HeadingLevel.HEADING_2, + }), + ); file.addParagraph(paragraph); packer = new Packer(); diff --git a/src/file/document/body/body.ts b/src/file/document/body/body.ts index fb8a187645..54d08ef9c5 100644 --- a/src/file/document/body/body.ts +++ b/src/file/document/body/body.ts @@ -60,8 +60,8 @@ export class Body extends XmlComponent { } private createSectionParagraph(section: SectionProperties): Paragraph { - const paragraph = new Paragraph(); - const properties = new ParagraphProperties(); + const paragraph = new Paragraph({}); + const properties = new ParagraphProperties({}); properties.addChildElement(section); paragraph.addChildElement(properties); return paragraph; diff --git a/src/file/document/document.spec.ts b/src/file/document/document.spec.ts index 111d42efdf..6b20515138 100644 --- a/src/file/document/document.spec.ts +++ b/src/file/document/document.spec.ts @@ -2,7 +2,6 @@ import { assert, expect } from "chai"; import { Formatter } from "export/formatter"; -import { Paragraph } from "../paragraph"; import { Table } from "../table"; import { Document } from "./document"; @@ -31,32 +30,6 @@ describe("Document", () => { }); }); - describe("#createParagraph", () => { - it("should create a new paragraph and append it to body", () => { - const para = document.createParagraph(); - expect(para).to.be.an.instanceof(Paragraph); - const body = new Formatter().format(document)["w:document"][1]["w:body"]; - expect(body) - .to.be.an("array") - .which.has.length.at.least(1); - expect(body[0]).to.have.property("w:p"); - }); - - it("should use the text given to create a run in the paragraph", () => { - const para = document.createParagraph("sample paragraph text"); - expect(para).to.be.an.instanceof(Paragraph); - const body = new Formatter().format(document)["w:document"][1]["w:body"]; - expect(body) - .to.be.an("array") - .which.has.length.at.least(1); - expect(body[0]) - .to.have.property("w:p") - .which.includes({ - "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "sample paragraph text"] }], - }); - }); - }); - describe("#createTable", () => { it("should create a new table and append it to body", () => { const table = document.createTable({ diff --git a/src/file/document/document.ts b/src/file/document/document.ts index e9a0e71c27..8c36c70a84 100644 --- a/src/file/document/document.ts +++ b/src/file/document/document.ts @@ -47,12 +47,6 @@ export class Document extends XmlComponent { return this; } - public createParagraph(text?: string): Paragraph { - const para = new Paragraph(text); - this.addParagraph(para); - return para; - } - public addTable(table: Table): Document { this.body.push(table); return this; diff --git a/src/file/file.spec.ts b/src/file/file.spec.ts index 1ceb87cd85..33a2c09432 100644 --- a/src/file/file.spec.ts +++ b/src/file/file.spec.ts @@ -83,7 +83,7 @@ describe("File", () => { it("should call the underlying document's addParagraph", () => { const file = new File(); const spy = sinon.spy(file.Document, "addParagraph"); - file.addParagraph(new Paragraph()); + file.addParagraph(new Paragraph({})); expect(spy.called).to.equal(true); }); @@ -128,16 +128,6 @@ describe("File", () => { }); }); - describe("#createParagraph", () => { - it("should call the underlying document's createParagraph", () => { - const wrapper = new File(); - const spy = sinon.spy(wrapper.Document, "createParagraph"); - wrapper.createParagraph("test"); - - expect(spy.called).to.equal(true); - }); - }); - describe("#addImage", () => { it("should call the underlying document's addImage", () => { const wrapper = new File(); diff --git a/src/file/file.ts b/src/file/file.ts index f6cf109b94..747077bd36 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -122,10 +122,6 @@ export class File { return this; } - public createParagraph(text?: string): Paragraph { - return this.document.createParagraph(text); - } - public addTable(table: Table): File { this.document.addTable(table); return this; diff --git a/src/file/footer-wrapper.spec.ts b/src/file/footer-wrapper.spec.ts index c7bc5564fa..90f9e71865 100644 --- a/src/file/footer-wrapper.spec.ts +++ b/src/file/footer-wrapper.spec.ts @@ -11,7 +11,7 @@ describe("FooterWrapper", () => { it("should call the underlying footer's addParagraph", () => { const file = new FooterWrapper(new Media(), 1); const spy = sinon.spy(file.Footer, "addParagraph"); - file.addParagraph(new Paragraph()); + file.addParagraph(new Paragraph({})); expect(spy.called).to.equal(true); }); @@ -42,16 +42,6 @@ describe("FooterWrapper", () => { }); }); - describe("#createParagraph", () => { - it("should call the underlying footer's createParagraph", () => { - const file = new FooterWrapper(new Media(), 1); - const spy = sinon.spy(file.Footer, "addParagraph"); - file.createParagraph(); - - expect(spy.called).to.equal(true); - }); - }); - describe("#addImage", () => { it("should call the underlying footer's addImage", () => { const file = new FooterWrapper(new Media(), 1); diff --git a/src/file/footer-wrapper.ts b/src/file/footer-wrapper.ts index 6b55730f9f..b8302dc5ca 100644 --- a/src/file/footer-wrapper.ts +++ b/src/file/footer-wrapper.ts @@ -25,12 +25,6 @@ export class FooterWrapper { this.footer.addParagraph(paragraph); } - public createParagraph(text?: string): Paragraph { - const para = new Paragraph(text); - this.addParagraph(para); - return para; - } - public addTable(table: Table): void { this.footer.addTable(table); } diff --git a/src/file/footer/footer.ts b/src/file/footer/footer.ts index 6934447d83..cbd69a8a3d 100644 --- a/src/file/footer/footer.ts +++ b/src/file/footer/footer.ts @@ -42,12 +42,6 @@ export class Footer extends InitializableXmlComponent { return this; } - public createParagraph(text?: string): Paragraph { - const para = new Paragraph(text); - this.addParagraph(para); - return para; - } - public addTable(table: Table): void { this.root.push(table); } diff --git a/src/file/footnotes/footnotes.ts b/src/file/footnotes/footnotes.ts index 7877eea9a0..1681928afb 100644 --- a/src/file/footnotes/footnotes.ts +++ b/src/file/footnotes/footnotes.ts @@ -38,25 +38,25 @@ export class FootNotes extends XmlComponent { const begin = new Footnote(-1, FootnoteType.SEPERATOR); begin.addParagraph( - new Paragraph() - .spacing({ + new Paragraph({ + spacing: { after: 0, line: 240, lineRule: "auto", - }) - .addRun(new SeperatorRun()), + }, + }).addRun(new SeperatorRun()), ); this.root.push(begin); const spacing = new Footnote(0, FootnoteType.CONTINUATION_SEPERATOR); spacing.addParagraph( - new Paragraph() - .spacing({ + new Paragraph({ + spacing: { after: 0, line: 240, lineRule: "auto", - }) - .addRun(new ContinuationSeperatorRun()), + }, + }).addRun(new ContinuationSeperatorRun()), ); this.root.push(spacing); } diff --git a/src/file/header-wrapper.spec.ts b/src/file/header-wrapper.spec.ts index c457753ced..01e54847ca 100644 --- a/src/file/header-wrapper.spec.ts +++ b/src/file/header-wrapper.spec.ts @@ -11,7 +11,7 @@ describe("HeaderWrapper", () => { it("should call the underlying header's addParagraph", () => { const wrapper = new HeaderWrapper(new Media(), 1); const spy = sinon.spy(wrapper.Header, "addParagraph"); - wrapper.addParagraph(new Paragraph()); + wrapper.addParagraph(new Paragraph({})); expect(spy.called).to.equal(true); }); @@ -42,16 +42,6 @@ describe("HeaderWrapper", () => { }); }); - describe("#createParagraph", () => { - it("should call the underlying header's createParagraph", () => { - const file = new HeaderWrapper(new Media(), 1); - const spy = sinon.spy(file.Header, "addParagraph"); - file.createParagraph(); - - expect(spy.called).to.equal(true); - }); - }); - describe("#addImage", () => { it("should call the underlying header's addImage", () => { const file = new HeaderWrapper(new Media(), 1); diff --git a/src/file/header-wrapper.ts b/src/file/header-wrapper.ts index 878d23bc9e..b06dbb4933 100644 --- a/src/file/header-wrapper.ts +++ b/src/file/header-wrapper.ts @@ -25,12 +25,6 @@ export class HeaderWrapper { this.header.addParagraph(paragraph); } - public createParagraph(text?: string): Paragraph { - const para = new Paragraph(text); - this.addParagraph(para); - return para; - } - public addTable(table: Table): void { this.header.addTable(table); } diff --git a/src/file/header/header.ts b/src/file/header/header.ts index a812b1b453..65a89e4943 100644 --- a/src/file/header/header.ts +++ b/src/file/header/header.ts @@ -53,12 +53,6 @@ export class Header extends InitializableXmlComponent { this.root.push(paragraph); } - public createParagraph(text?: string): Paragraph { - const para = new Paragraph(text); - this.addParagraph(para); - return para; - } - public addTable(table: Table): void { this.root.push(table); } diff --git a/src/file/numbering/level.ts b/src/file/numbering/level.ts index 716f313104..bd213cfa6c 100644 --- a/src/file/numbering/level.ts +++ b/src/file/numbering/level.ts @@ -1,7 +1,7 @@ import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { Alignment, - AlignmentOptions, + AlignmentType, Indent, ISpacingProperties, KeepLines, @@ -114,7 +114,7 @@ export class LevelBase extends XmlComponent { this.root.push(new LevelJc(lvlJc)); } - this.paragraphProperties = new ParagraphProperties(); + this.paragraphProperties = new ParagraphProperties({}); this.runProperties = new RunProperties(); this.root.push(this.paragraphProperties); @@ -201,22 +201,22 @@ export class LevelBase extends XmlComponent { // --------------------- Paragraph formatting ------------------------ // public center(): Level { - this.addParagraphProperty(new Alignment(AlignmentOptions.CENTER)); + this.addParagraphProperty(new Alignment(AlignmentType.CENTER)); return this; } public left(): Level { - this.addParagraphProperty(new Alignment(AlignmentOptions.LEFT)); + this.addParagraphProperty(new Alignment(AlignmentType.LEFT)); return this; } public right(): Level { - this.addParagraphProperty(new Alignment(AlignmentOptions.RIGHT)); + this.addParagraphProperty(new Alignment(AlignmentType.RIGHT)); return this; } public justified(): Level { - this.addParagraphProperty(new Alignment(AlignmentOptions.BOTH)); + this.addParagraphProperty(new Alignment(AlignmentType.BOTH)); return this; } diff --git a/src/file/numbering/numbering.spec.ts b/src/file/numbering/numbering.spec.ts index 3ba39b15f6..ab74e1c39c 100644 --- a/src/file/numbering/numbering.spec.ts +++ b/src/file/numbering/numbering.spec.ts @@ -175,9 +175,9 @@ describe("AbstractNumbering", () => { "w:bottom": { _attr: { "w:color": "auto", - "w:space": "1", + "w:space": 1, "w:val": "single", - "w:sz": "6", + "w:sz": 6, }, }, }, diff --git a/src/file/paragraph/formatting/alignment.ts b/src/file/paragraph/formatting/alignment.ts index 838c1dc700..8acf41ee4b 100644 --- a/src/file/paragraph/formatting/alignment.ts +++ b/src/file/paragraph/formatting/alignment.ts @@ -1,22 +1,23 @@ // http://officeopenxml.com/WPalignment.php import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; -export enum AlignmentOptions { +export enum AlignmentType { START = "start", END = "end", CENTER = "center", BOTH = "both", + JUSTIFIED = "both", DISTRIBUTE = "distribute", LEFT = "left", RIGHT = "right", } -export class AlignmentAttributes extends XmlAttributeComponent<{ readonly val: AlignmentOptions }> { +export class AlignmentAttributes extends XmlAttributeComponent<{ readonly val: AlignmentType }> { protected readonly xmlKeys = { val: "w:val" }; } export class Alignment extends XmlComponent { - constructor(type: AlignmentOptions) { + constructor(type: AlignmentType) { super("w:jc"); this.root.push(new AlignmentAttributes({ val: type })); } diff --git a/src/file/paragraph/formatting/border-attributes.ts b/src/file/paragraph/formatting/border-attributes.ts new file mode 100644 index 0000000000..d389f7adc7 --- /dev/null +++ b/src/file/paragraph/formatting/border-attributes.ts @@ -0,0 +1,17 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IBorderAttributesProperties { + readonly color: string; + readonly space: number; + readonly val: string; + readonly sz: number; +} + +export class BorderAttributes extends XmlAttributeComponent { + protected readonly xmlKeys = { + val: "w:val", + color: "w:color", + space: "w:space", + sz: "w:sz", + }; +} diff --git a/src/file/paragraph/formatting/border.spec.ts b/src/file/paragraph/formatting/border.spec.ts index d0fda56359..45c65cc620 100644 --- a/src/file/paragraph/formatting/border.spec.ts +++ b/src/file/paragraph/formatting/border.spec.ts @@ -31,9 +31,9 @@ describe("ThematicBreak", () => { const newJson = Utility.jsonify(thematicBreak); const attributes = { color: "auto", - space: "1", + space: 1, val: "single", - sz: "6", + sz: 6, }; assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes)); }); diff --git a/src/file/paragraph/formatting/border.ts b/src/file/paragraph/formatting/border.ts index f37854a3c7..d44bc51c06 100644 --- a/src/file/paragraph/formatting/border.ts +++ b/src/file/paragraph/formatting/border.ts @@ -1,13 +1,30 @@ // http://officeopenxml.com/WPborders.php -import { Attributes, XmlComponent } from "file/xml-components"; +import { XmlComponent } from "file/xml-components"; +import { BorderAttributes } from "./border-attributes"; + +interface IBorderPropertyOptions { + readonly color: string; + readonly space: number; + readonly value: string; + readonly size: number; +} + +export interface IBorderOptions { + readonly top?: IBorderPropertyOptions; + readonly bottom?: IBorderPropertyOptions; + readonly left?: IBorderPropertyOptions; + readonly right?: IBorderPropertyOptions; +} class BorderProperty extends XmlComponent { - public setProperties(color: string, space: string, value: string, size: string): XmlComponent { - const attrs = new Attributes({ - color: color, - space: space, - val: value, - sz: size, + constructor(rootKey: string, options: IBorderPropertyOptions = { color: "auto", space: 1, value: "single", size: 6 }) { + super(rootKey); + + const attrs = new BorderAttributes({ + color: options.color, + space: options.space, + val: options.value, + sz: options.size, }); this.root.push(attrs); @@ -16,48 +33,40 @@ class BorderProperty extends XmlComponent { } export class Border extends XmlComponent { - constructor() { + constructor(options: IBorderOptions) { super("w:pBdr"); - } - public addTopBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { - const top = new BorderProperty("w:top"); - top.setProperties(color, space, value, size); - this.root.push(top); + if (options.top !== undefined) { + const borderProperty = new BorderProperty("w:top", options.top); + this.root.push(borderProperty); + } - return this; - } + if (options.bottom !== undefined) { + const borderProperty = new BorderProperty("w:bottom", options.bottom); + this.root.push(borderProperty); + } - public addBottomBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { - const bottom = new BorderProperty("w:bottom"); - bottom.setProperties(color, space, value, size); - this.root.push(bottom); + if (options.left !== undefined) { + const borderProperty = new BorderProperty("w:left", options.left); + this.root.push(borderProperty); + } - return this; - } - - public addLeftBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { - const left = new BorderProperty("w:left"); - left.setProperties(color, space, value, size); - this.root.push(left); - - return this; - } - - public addRightBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { - const right = new BorderProperty("w:right"); - right.setProperties(color, space, value, size); - this.root.push(right); - - return this; + if (options.right !== undefined) { + const borderProperty = new BorderProperty("w:right", options.right); + this.root.push(borderProperty); + } } } export class ThematicBreak extends XmlComponent { constructor() { super("w:pBdr"); - const bottom = new BorderProperty("w:bottom"); - bottom.setProperties("auto", "1", "single", "6"); + const bottom = new BorderProperty("w:bottom", { + color: "auto", + space: 1, + value: "single", + size: 6, + }); this.root.push(bottom); } } diff --git a/src/file/paragraph/formatting/style.ts b/src/file/paragraph/formatting/style.ts index 30d57eb997..a493e4b025 100644 --- a/src/file/paragraph/formatting/style.ts +++ b/src/file/paragraph/formatting/style.ts @@ -1,5 +1,15 @@ import { Attributes, XmlComponent } from "file/xml-components"; +export enum HeadingLevel { + HEADING_1 = "Heading1", + HEADING_2 = "Heading2", + HEADING_3 = "Heading3", + HEADING_4 = "Heading4", + HEADING_5 = "Heading5", + HEADING_6 = "Heading6", + TITLE = "Title", +} + export class Style extends XmlComponent { public readonly styleId: string; diff --git a/src/file/paragraph/image.ts b/src/file/paragraph/image.ts index 634f76e517..f4adffbdd4 100644 --- a/src/file/paragraph/image.ts +++ b/src/file/paragraph/image.ts @@ -7,7 +7,7 @@ export class ImageParagraph extends Paragraph { private readonly pictureRun: PictureRun; constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { - super(); + super({}); this.pictureRun = new PictureRun(imageData, drawingOptions); this.root.push(this.pictureRun); } diff --git a/src/file/paragraph/links/outline-level.spec.ts b/src/file/paragraph/links/outline-level.spec.ts index 6ba188fd9d..1b7873ea47 100644 --- a/src/file/paragraph/links/outline-level.spec.ts +++ b/src/file/paragraph/links/outline-level.spec.ts @@ -9,15 +9,9 @@ describe("ParagraphOutlineLevel", () => { describe("#constructor()", () => { it("should create an outlineLevel with given value", () => { - outlineLevel = new OutlineLevel("0"); + outlineLevel = new OutlineLevel(0); const newJson = Utility.jsonify(outlineLevel); assert.equal(newJson.root[0].root.val, "0"); }); - - it("should create an outlineLevel with blank val", () => { - outlineLevel = new OutlineLevel(""); - const newJson = Utility.jsonify(outlineLevel); - assert.equal(newJson.root[0].root.val, ""); - }); }); }); diff --git a/src/file/paragraph/links/outline-level.ts b/src/file/paragraph/links/outline-level.ts index 512638bcc7..bb3258a02b 100644 --- a/src/file/paragraph/links/outline-level.ts +++ b/src/file/paragraph/links/outline-level.ts @@ -2,11 +2,9 @@ import { Attributes, XmlComponent } from "file/xml-components"; export class OutlineLevel extends XmlComponent { - public readonly level: string; - - constructor(level: string) { + constructor(public readonly level: number) { super("w:outlineLvl"); - this.level = level; + this.root.push( new Attributes({ val: level, diff --git a/src/file/paragraph/paragraph.spec.ts b/src/file/paragraph/paragraph.spec.ts index ed9dfbe6c4..91ee616a4e 100644 --- a/src/file/paragraph/paragraph.spec.ts +++ b/src/file/paragraph/paragraph.spec.ts @@ -1,22 +1,16 @@ import { assert, expect } from "chai"; import { Formatter } from "export/formatter"; -import * as file from "file"; - -import { Numbering } from "../numbering"; -import { LeaderType } from "./formatting"; - import { EMPTY_OBJECT } from "file/xml-components"; +import { Numbering } from "../numbering"; +import { AlignmentType, HeadingLevel, LeaderType } from "./formatting"; +import { Paragraph } from "./paragraph"; + describe("Paragraph", () => { - let paragraph: file.Paragraph; - - beforeEach(() => { - paragraph = new file.Paragraph(); - }); - describe("#constructor()", () => { it("should create valid JSON", () => { + const paragraph = new Paragraph(""); const stringifiedJson = JSON.stringify(paragraph); try { @@ -28,28 +22,18 @@ describe("Paragraph", () => { }); it("should create have valid properties", () => { + const paragraph = new Paragraph(""); const stringifiedJson = JSON.stringify(paragraph); const newJson = JSON.parse(stringifiedJson); assert.equal(newJson.root[0].rootKey, "w:pPr"); }); }); - describe("#createTextRun", () => { - it("should add a new run to the paragraph and return it", () => { - const run = paragraph.createTextRun("this is a test run"); - expect(run).to.be.instanceof(file.TextRun); - const tree = new Formatter().format(paragraph)["w:p"]; - expect(tree) - .to.be.an("array") - .which.includes({ - "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "this is a test run"] }], - }); - }); - }); - describe("#heading1()", () => { it("should add heading style to JSON", () => { - paragraph.heading1(); + const paragraph = new Paragraph({ + heading: HeadingLevel.HEADING_1, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -63,7 +47,9 @@ describe("Paragraph", () => { describe("#heading2()", () => { it("should add heading style to JSON", () => { - paragraph.heading2(); + const paragraph = new Paragraph({ + heading: HeadingLevel.HEADING_2, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -77,7 +63,9 @@ describe("Paragraph", () => { describe("#heading3()", () => { it("should add heading style to JSON", () => { - paragraph.heading3(); + const paragraph = new Paragraph({ + heading: HeadingLevel.HEADING_3, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -91,7 +79,9 @@ describe("Paragraph", () => { describe("#heading4()", () => { it("should add heading style to JSON", () => { - paragraph.heading4(); + const paragraph = new Paragraph({ + heading: HeadingLevel.HEADING_4, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -105,7 +95,9 @@ describe("Paragraph", () => { describe("#heading5()", () => { it("should add heading style to JSON", () => { - paragraph.heading5(); + const paragraph = new Paragraph({ + heading: HeadingLevel.HEADING_5, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -119,7 +111,9 @@ describe("Paragraph", () => { describe("#heading6()", () => { it("should add heading style to JSON", () => { - paragraph.heading6(); + const paragraph = new Paragraph({ + heading: HeadingLevel.HEADING_6, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -133,7 +127,9 @@ describe("Paragraph", () => { describe("#title()", () => { it("should add title style to JSON", () => { - paragraph.title(); + const paragraph = new Paragraph({ + heading: HeadingLevel.TITLE, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -147,7 +143,9 @@ describe("Paragraph", () => { describe("#center()", () => { it("should add center alignment to JSON", () => { - paragraph.center(); + const paragraph = new Paragraph({ + alignment: AlignmentType.CENTER, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -161,7 +159,9 @@ describe("Paragraph", () => { describe("#left()", () => { it("should add left alignment to JSON", () => { - paragraph.left(); + const paragraph = new Paragraph({ + alignment: AlignmentType.LEFT, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -175,7 +175,9 @@ describe("Paragraph", () => { describe("#right()", () => { it("should add right alignment to JSON", () => { - paragraph.right(); + const paragraph = new Paragraph({ + alignment: AlignmentType.RIGHT, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -189,7 +191,9 @@ describe("Paragraph", () => { describe("#start()", () => { it("should add start alignment to JSON", () => { - paragraph.start(); + const paragraph = new Paragraph({ + alignment: AlignmentType.START, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -203,7 +207,9 @@ describe("Paragraph", () => { describe("#end()", () => { it("should add end alignment to JSON", () => { - paragraph.end(); + const paragraph = new Paragraph({ + alignment: AlignmentType.END, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -217,7 +223,9 @@ describe("Paragraph", () => { describe("#distribute()", () => { it("should add distribute alignment to JSON", () => { - paragraph.distribute(); + const paragraph = new Paragraph({ + alignment: AlignmentType.DISTRIBUTE, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -231,7 +239,9 @@ describe("Paragraph", () => { describe("#justified()", () => { it("should add justified alignment to JSON", () => { - paragraph.justified(); + const paragraph = new Paragraph({ + alignment: AlignmentType.JUSTIFIED, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -245,7 +255,11 @@ describe("Paragraph", () => { describe("#maxRightTabStop()", () => { it("should add maxRightTabStop to JSON", () => { - paragraph.maxRightTabStop(); + const paragraph = new Paragraph({ + tabStop: { + maxRight: {}, + }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -272,7 +286,14 @@ describe("Paragraph", () => { describe("#leftTabStop()", () => { it("should add leftTabStop to JSON", () => { - paragraph.leftTabStop(100, LeaderType.HYPHEN); + const paragraph = new Paragraph({ + tabStop: { + left: { + position: 100, + leader: LeaderType.HYPHEN, + }, + }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -300,7 +321,14 @@ describe("Paragraph", () => { describe("#rightTabStop()", () => { it("should add rightTabStop to JSON", () => { - paragraph.rightTabStop(100, LeaderType.DOT); + const paragraph = new Paragraph({ + tabStop: { + right: { + position: 100, + leader: LeaderType.DOT, + }, + }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -328,7 +356,14 @@ describe("Paragraph", () => { describe("#centerTabStop()", () => { it("should add centerTabStop to JSON", () => { - paragraph.centerTabStop(100, LeaderType.MIDDLE_DOT); + const paragraph = new Paragraph({ + tabStop: { + center: { + position: 100, + leader: LeaderType.MIDDLE_DOT, + }, + }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -356,7 +391,9 @@ describe("Paragraph", () => { describe("#contextualSpacing()", () => { it("should add contextualSpacing to JSON, and set 1 if true", () => { - paragraph.contextualSpacing(true); + const paragraph = new Paragraph({ + contextualSpacing: true, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -366,23 +403,13 @@ describe("Paragraph", () => { ], }); }); - - it("should add contextualSpacing to JSON, and set 0 if false", () => { - paragraph.contextualSpacing(false); - const tree = new Formatter().format(paragraph); - expect(tree).to.deep.equal({ - "w:p": [ - { - "w:pPr": [{ "w:contextualSpacing": { _attr: { "w:val": 0 } } }], - }, - ], - }); - }); }); describe("#thematicBreak()", () => { it("should add thematic break to JSON", () => { - paragraph.thematicBreak(); + const paragraph = new Paragraph({ + thematicBreak: true, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -395,8 +422,8 @@ describe("Paragraph", () => { _attr: { "w:val": "single", "w:color": "auto", - "w:space": "1", - "w:sz": "6", + "w:space": 1, + "w:sz": 6, }, }, }, @@ -411,9 +438,22 @@ describe("Paragraph", () => { describe("#paragraphBorders()", () => { it("should add a left and right border to a paragraph", () => { - paragraph.createBorder(); - paragraph.Borders.addLeftBorder(); - paragraph.Borders.addRightBorder(); + const paragraph = new Paragraph({ + border: { + left: { + color: "auto", + space: 1, + value: "single", + size: 6, + }, + right: { + color: "auto", + space: 1, + value: "single", + size: 6, + }, + }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -425,8 +465,8 @@ describe("Paragraph", () => { "w:left": { _attr: { "w:color": "auto", - "w:space": "1", - "w:sz": "6", + "w:space": 1, + "w:sz": 6, "w:val": "single", }, }, @@ -435,8 +475,8 @@ describe("Paragraph", () => { "w:right": { _attr: { "w:color": "auto", - "w:space": "1", - "w:sz": "6", + "w:space": 1, + "w:sz": 6, "w:val": "single", }, }, @@ -452,6 +492,7 @@ describe("Paragraph", () => { describe("#pageBreak()", () => { it("should add page break to JSON", () => { + const paragraph = new Paragraph({}); paragraph.pageBreak(); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ @@ -466,7 +507,9 @@ describe("Paragraph", () => { describe("#pageBreakBefore()", () => { it("should add page break before to JSON", () => { - paragraph.pageBreakBefore(); + const paragraph = new Paragraph({ + pageBreakBefore: true, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -484,7 +527,11 @@ describe("Paragraph", () => { describe("#bullet()", () => { it("should default to 0 indent level if no bullet was specified", () => { - paragraph.bullet(); + const paragraph = new Paragraph({ + bullet: { + level: 0, + }, + }); const tree = new Formatter().format(paragraph); expect(tree) .to.have.property("w:p") @@ -500,7 +547,11 @@ describe("Paragraph", () => { }); it("should add list paragraph style to JSON", () => { - paragraph.bullet(0); + const paragraph = new Paragraph({ + bullet: { + level: 0, + }, + }); const tree = new Formatter().format(paragraph); expect(tree) .to.have.property("w:p") @@ -516,7 +567,11 @@ describe("Paragraph", () => { }); it("it should add numbered properties", () => { - paragraph.bullet(1); + const paragraph = new Paragraph({ + bullet: { + level: 1, + }, + }); const tree = new Formatter().format(paragraph); expect(tree) .to.have.property("w:p") @@ -539,7 +594,12 @@ describe("Paragraph", () => { numberedAbstract.createLevel(0, "lowerLetter", "%1)", "start"); const letterNumbering = numbering.createConcreteNumbering(numberedAbstract); - paragraph.setNumbering(letterNumbering, 0); + const paragraph = new Paragraph({ + numbering: { + num: letterNumbering, + level: 0, + }, + }); const tree = new Formatter().format(paragraph); expect(tree) .to.have.property("w:p") @@ -560,7 +620,12 @@ describe("Paragraph", () => { numberedAbstract.createLevel(0, "lowerLetter", "%1)", "start"); const letterNumbering = numbering.createConcreteNumbering(numberedAbstract); - paragraph.setNumbering(letterNumbering, 0); + const paragraph = new Paragraph({ + numbering: { + num: letterNumbering, + level: 0, + }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -582,7 +647,9 @@ describe("Paragraph", () => { describe("#style", () => { it("should set the paragraph style to the given styleId", () => { - paragraph.style("myFancyStyle"); + const paragraph = new Paragraph({ + style: "myFancyStyle", + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -596,7 +663,9 @@ describe("Paragraph", () => { describe("#indent", () => { it("should set the paragraph indent to the given values", () => { - paragraph.indent({ left: 720 }); + const paragraph = new Paragraph({ + indent: { left: 720 }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -610,7 +679,9 @@ describe("Paragraph", () => { describe("#spacing", () => { it("should set the paragraph spacing to the given values", () => { - paragraph.spacing({ before: 90, line: 50 }); + const paragraph = new Paragraph({ + spacing: { before: 90, line: 50 }, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ @@ -624,7 +695,9 @@ describe("Paragraph", () => { describe("#keepLines", () => { it("should set the paragraph keepLines sub-component", () => { - paragraph.keepLines(); + const paragraph = new Paragraph({ + keepLines: true, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [{ "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }], @@ -634,7 +707,9 @@ describe("Paragraph", () => { describe("#keepNext", () => { it("should set the paragraph keepNext sub-component", () => { - paragraph.keepNext(); + const paragraph = new Paragraph({ + keepNext: true, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [{ "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }], @@ -644,7 +719,9 @@ describe("Paragraph", () => { describe("#bidirectional", () => { it("set paragraph right to left layout", () => { - paragraph.bidirectional(); + const paragraph = new Paragraph({ + bidirectional: true, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [{ "w:pPr": [{ "w:bidi": EMPTY_OBJECT }] }], @@ -654,12 +731,14 @@ describe("Paragraph", () => { describe("#outlineLevel", () => { it("should set paragraph outline level to the given value", () => { - paragraph.outlineLevel("0"); + const paragraph = new Paragraph({ + outlineLevel: 0, + }); const tree = new Formatter().format(paragraph); expect(tree).to.deep.equal({ "w:p": [ { - "w:pPr": [{ "w:outlineLvl": { _attr: { "w:val": "0" } } }], + "w:pPr": [{ "w:outlineLvl": { _attr: { "w:val": 0 } } }], }, ], }); diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index cfd32322c2..51940a6373 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -4,43 +4,165 @@ import { Image } from "file/media"; import { Num } from "file/numbering/num"; import { XmlComponent } from "file/xml-components"; -import { Alignment, AlignmentOptions } from "./formatting/alignment"; +import { Alignment, AlignmentType } from "./formatting/alignment"; import { Bidirectional } from "./formatting/bidirectional"; -import { Border, ThematicBreak } from "./formatting/border"; +import { IBorderOptions, ThematicBreak } from "./formatting/border"; import { IIndentAttributesProperties, Indent } from "./formatting/indent"; import { KeepLines, KeepNext } from "./formatting/keep"; import { PageBreak, PageBreakBefore } from "./formatting/page-break"; import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing"; -import { Style } from "./formatting/style"; +import { HeadingLevel, Style } from "./formatting/style"; import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop"; import { NumberProperties } from "./formatting/unordered-list"; import { Bookmark, Hyperlink, OutlineLevel } from "./links"; import { ParagraphProperties } from "./properties"; import { PictureRun, Run, SequentialIdentifier, TextRun } from "./run"; +interface ITabStopOptions { + readonly position: number; + readonly leader?: LeaderType; +} + +export interface IParagraphOptions { + readonly text?: string; + readonly border?: IBorderOptions; + readonly spacing?: ISpacingProperties; + readonly runs?: Run[]; + readonly outlineLevel?: number; + readonly alignment?: AlignmentType; + readonly heading?: HeadingLevel; + readonly bidirectional?: boolean; + readonly thematicBreak?: boolean; + readonly pageBreakBefore?: boolean; + readonly contextualSpacing?: boolean; + readonly indent?: IIndentAttributesProperties; + readonly keepLines?: boolean; + readonly keepNext?: boolean; + readonly tabStop?: { + readonly left?: ITabStopOptions; + readonly right?: ITabStopOptions; + readonly maxRight?: { + readonly leader?: LeaderType; + }; + readonly center?: ITabStopOptions; + }; + readonly style?: string; + readonly bullet?: { + readonly level: number; + }; + readonly numbering?: { + readonly num: Num; + readonly level: number; + readonly custom?: boolean; + }; +} + export class Paragraph extends XmlComponent { private readonly properties: ParagraphProperties; - constructor(text?: string) { + constructor(options: string | IParagraphOptions) { super("w:p"); - this.properties = new ParagraphProperties(); - this.root.push(this.properties); - if (text !== undefined) { - this.root.push(new TextRun(text)); + + if (typeof options === "string") { + this.properties = new ParagraphProperties({}); + this.root.push(this.properties); + this.root.push(new TextRun(options)); + return; } - } - public get paragraphProperties(): ParagraphProperties { - return this.properties; - } + this.properties = new ParagraphProperties({ + border: options.border, + }); - public get Borders(): Border { - return this.properties.paragraphBorder; - } + this.root.push(this.properties); - public createBorder(): Paragraph { - this.properties.createBorder(); - return this; + if (options.text) { + this.root.push(new TextRun(options.text)); + } + + if (options.spacing) { + this.properties.push(new Spacing(options.spacing)); + } + + if (options.outlineLevel !== undefined) { + this.properties.push(new OutlineLevel(options.outlineLevel)); + } + + if (options.alignment) { + this.properties.push(new Alignment(options.alignment)); + } + + if (options.heading) { + this.properties.push(new Style(options.heading)); + } + + if (options.bidirectional) { + this.properties.push(new Bidirectional()); + } + + if (options.thematicBreak) { + this.properties.push(new ThematicBreak()); + } + + if (options.pageBreakBefore) { + this.properties.push(new PageBreakBefore()); + } + + if (options.contextualSpacing) { + this.properties.push(new ContextualSpacing(options.contextualSpacing)); + } + + if (options.indent) { + this.properties.push(new Indent(options.indent)); + } + + if (options.keepLines) { + this.properties.push(new KeepLines()); + } + + if (options.keepNext) { + this.properties.push(new KeepNext()); + } + + if (options.tabStop) { + if (options.tabStop.left) { + this.properties.push(new LeftTabStop(options.tabStop.left.position, options.tabStop.left.leader)); + } + + if (options.tabStop.right) { + this.properties.push(new RightTabStop(options.tabStop.right.position, options.tabStop.right.leader)); + } + + if (options.tabStop.maxRight) { + this.properties.push(new MaxRightTabStop(options.tabStop.maxRight.leader)); + } + + if (options.tabStop.center) { + this.properties.push(new CenterTabStop(options.tabStop.center.position, options.tabStop.center.leader)); + } + } + + if (options.style) { + this.properties.push(new Style(options.style)); + } + + if (options.bullet) { + this.properties.push(new Style("ListParagraph")); + this.properties.push(new NumberProperties(1, options.bullet.level)); + } + + if (options.numbering) { + if (!options.numbering.custom) { + this.properties.push(new Style("ListParagraph")); + } + this.properties.push(new NumberProperties(options.numbering.num.id, options.numbering.level)); + } + + if (options.runs) { + for (const run of options.runs) { + this.root.push(run); + } + } } public addRun(run: Run): Paragraph { @@ -61,12 +183,6 @@ export class Paragraph extends XmlComponent { return this; } - public createTextRun(text: string): TextRun { - const run = new TextRun(text); - this.addRun(run); - return run; - } - public addImage(image: Image): PictureRun { const run = image.Run; this.addRun(run); @@ -74,158 +190,11 @@ export class Paragraph extends XmlComponent { return run; } - public heading1(): Paragraph { - this.properties.push(new Style("Heading1")); - return this; - } - - public heading2(): Paragraph { - this.properties.push(new Style("Heading2")); - return this; - } - - public heading3(): Paragraph { - this.properties.push(new Style("Heading3")); - return this; - } - - public heading4(): Paragraph { - this.properties.push(new Style("Heading4")); - return this; - } - - public heading5(): Paragraph { - this.properties.push(new Style("Heading5")); - return this; - } - - public heading6(): Paragraph { - this.properties.push(new Style("Heading6")); - return this; - } - - public title(): Paragraph { - this.properties.push(new Style("Title")); - return this; - } - - public center(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.CENTER)); - return this; - } - - public left(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.LEFT)); - return this; - } - - public right(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.RIGHT)); - return this; - } - - public start(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.START)); - return this; - } - - public end(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.END)); - return this; - } - - public distribute(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.DISTRIBUTE)); - return this; - } - - public justified(): Paragraph { - this.properties.push(new Alignment(AlignmentOptions.BOTH)); - return this; - } - - public thematicBreak(): Paragraph { - this.properties.push(new ThematicBreak()); - return this; - } - public pageBreak(): Paragraph { this.root.push(new PageBreak()); return this; } - public pageBreakBefore(): Paragraph { - this.properties.push(new PageBreakBefore()); - return this; - } - - public maxRightTabStop(leader?: LeaderType): Paragraph { - this.properties.push(new MaxRightTabStop(leader)); - return this; - } - - public leftTabStop(position: number, leader?: LeaderType): Paragraph { - this.properties.push(new LeftTabStop(position, leader)); - return this; - } - - public rightTabStop(position: number, leader?: LeaderType): Paragraph { - this.properties.push(new RightTabStop(position, leader)); - return this; - } - - public centerTabStop(position: number, leader?: LeaderType): Paragraph { - this.properties.push(new CenterTabStop(position, leader)); - return this; - } - - public bullet(indentLevel: number = 0): Paragraph { - this.properties.push(new Style("ListParagraph")); - this.properties.push(new NumberProperties(1, indentLevel)); - return this; - } - - public setNumbering(numbering: Num, indentLevel: number): Paragraph { - this.properties.push(new Style("ListParagraph")); - this.properties.push(new NumberProperties(numbering.id, indentLevel)); - return this; - } - - public setCustomNumbering(numberId: number, indentLevel: number): Paragraph { - this.properties.push(new NumberProperties(numberId, indentLevel)); - return this; - } - - public style(styleId: string): Paragraph { - this.properties.push(new Style(styleId)); - return this; - } - - public indent(attrs: IIndentAttributesProperties): Paragraph { - this.properties.push(new Indent(attrs)); - return this; - } - - public spacing(params: ISpacingProperties): Paragraph { - this.properties.push(new Spacing(params)); - return this; - } - - public contextualSpacing(value: boolean): Paragraph { - this.properties.push(new ContextualSpacing(value)); - return this; - } - - public keepNext(): Paragraph { - this.properties.push(new KeepNext()); - return this; - } - - public keepLines(): Paragraph { - this.properties.push(new KeepLines()); - return this; - } - public referenceFootnote(id: number): Paragraph { this.root.push(new FootnoteReferenceRun(id)); return this; @@ -236,18 +205,8 @@ export class Paragraph extends XmlComponent { return this; } - public bidirectional(): Paragraph { - this.properties.push(new Bidirectional()); - return this; - } - public addSequentialIdentifier(identifier: string): Paragraph { this.root.push(new SequentialIdentifier(identifier)); return this; } - - public outlineLevel(level: string): Paragraph { - this.properties.push(new OutlineLevel(level)); - return this; - } } diff --git a/src/file/paragraph/properties.ts b/src/file/paragraph/properties.ts index 188960145c..35836ce30e 100644 --- a/src/file/paragraph/properties.ts +++ b/src/file/paragraph/properties.ts @@ -1,17 +1,19 @@ // http://officeopenxml.com/WPparagraphProperties.php import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components"; -import { Border } from "./formatting/border"; + +import { Border, IBorderOptions } from "./formatting/border"; + +interface IParagraphPropertiesOptions { + readonly border?: IBorderOptions; +} export class ParagraphProperties extends IgnoreIfEmptyXmlComponent { - public readonly paragraphBorder: Border; - - constructor() { + constructor(options: IParagraphPropertiesOptions) { super("w:pPr"); - this.paragraphBorder = new Border(); - } - public createBorder(): void { - this.push(this.paragraphBorder); + if (options.border) { + this.push(new Border(options.border)); + } } public push(item: XmlComponent): void { diff --git a/src/file/styles/defaults/paragraph-properties.ts b/src/file/styles/defaults/paragraph-properties.ts index 1ab3b623d6..c5f2bee86c 100644 --- a/src/file/styles/defaults/paragraph-properties.ts +++ b/src/file/styles/defaults/paragraph-properties.ts @@ -4,6 +4,6 @@ import { XmlComponent } from "file/xml-components"; export class ParagraphPropertiesDefaults extends XmlComponent { constructor() { super("w:pPrDefault"); - this.root.push(new ParagraphProperties()); + this.root.push(new ParagraphProperties({})); } } diff --git a/src/file/styles/style/paragraph-style.spec.ts b/src/file/styles/style/paragraph-style.spec.ts index 41ef0fddab..47e447abfd 100644 --- a/src/file/styles/style/paragraph-style.spec.ts +++ b/src/file/styles/style/paragraph-style.spec.ts @@ -166,9 +166,9 @@ describe("ParagraphStyle", () => { "w:bottom": { _attr: { "w:color": "auto", - "w:space": "1", + "w:space": 1, "w:val": "single", - "w:sz": "6", + "w:sz": 6, }, }, }, @@ -231,12 +231,12 @@ describe("ParagraphStyle", () => { }); it("#outlineLevel", () => { - const style = new ParagraphStyle("myStyleId").outlineLevel("1"); + const style = new ParagraphStyle("myStyleId").outlineLevel(1); const tree = new Formatter().format(style); expect(tree).to.deep.equal({ "w:style": [ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, - { "w:pPr": [{ "w:outlineLvl": { _attr: { "w:val": "1" } } }] }, + { "w:pPr": [{ "w:outlineLvl": { _attr: { "w:val": 1 } } }] }, ], }); }); diff --git a/src/file/styles/style/paragraph-style.ts b/src/file/styles/style/paragraph-style.ts index d231c58f33..46e02155be 100644 --- a/src/file/styles/style/paragraph-style.ts +++ b/src/file/styles/style/paragraph-style.ts @@ -1,6 +1,6 @@ import { Alignment, - AlignmentOptions, + AlignmentType, Indent, ISpacingProperties, KeepLines, @@ -24,7 +24,7 @@ export class ParagraphStyle extends Style { constructor(styleId: string, name?: string) { super({ type: "paragraph", styleId: styleId }, name); - this.paragraphProperties = new ParagraphProperties(); + this.paragraphProperties = new ParagraphProperties({}); this.runProperties = new RunProperties(); this.root.push(this.paragraphProperties); this.root.push(this.runProperties); @@ -35,7 +35,7 @@ export class ParagraphStyle extends Style { return this; } - public outlineLevel(level: string): ParagraphStyle { + public outlineLevel(level: number): ParagraphStyle { this.paragraphProperties.push(new OutlineLevel(level)); return this; } @@ -117,19 +117,19 @@ export class ParagraphStyle extends Style { // --------------------- Paragraph formatting ------------------------ // public center(): ParagraphStyle { - return this.addParagraphProperty(new Alignment(AlignmentOptions.CENTER)); + return this.addParagraphProperty(new Alignment(AlignmentType.CENTER)); } public left(): ParagraphStyle { - return this.addParagraphProperty(new Alignment(AlignmentOptions.LEFT)); + return this.addParagraphProperty(new Alignment(AlignmentType.LEFT)); } public right(): ParagraphStyle { - return this.addParagraphProperty(new Alignment(AlignmentOptions.RIGHT)); + return this.addParagraphProperty(new Alignment(AlignmentType.RIGHT)); } public justified(): ParagraphStyle { - return this.addParagraphProperty(new Alignment(AlignmentOptions.BOTH)); + return this.addParagraphProperty(new Alignment(AlignmentType.BOTH)); } public thematicBreak(): ParagraphStyle { diff --git a/src/file/table-of-contents/table-of-contents.ts b/src/file/table-of-contents/table-of-contents.ts index 7b1ff0f66d..6b2c69e1bf 100644 --- a/src/file/table-of-contents/table-of-contents.ts +++ b/src/file/table-of-contents/table-of-contents.ts @@ -16,7 +16,7 @@ export class TableOfContents extends XmlComponent { const content = new StructuredDocumentTagContent(); - const beginParagraph = new Paragraph(); + const beginParagraph = new Paragraph({}); const beginRun = new Run(); beginRun.addChildElement(new Begin(true)); beginRun.addChildElement(new FieldInstruction(properties)); @@ -24,7 +24,7 @@ export class TableOfContents extends XmlComponent { beginParagraph.addRun(beginRun); content.addChildElement(beginParagraph); - const endParagraph = new Paragraph(); + const endParagraph = new Paragraph({}); const endRun = new Run(); endRun.addChildElement(new End()); endParagraph.addRun(endRun); diff --git a/src/file/table/table-cell/table-cell.ts b/src/file/table/table-cell/table-cell.ts index a3c8b427e1..99acef0b31 100644 --- a/src/file/table/table-cell/table-cell.ts +++ b/src/file/table/table-cell/table-cell.ts @@ -31,18 +31,12 @@ export class TableCell extends XmlComponent { public prepForXml(): IXmlableObject | undefined { // Cells must end with a paragraph if (!(this.root[this.root.length - 1] instanceof Paragraph)) { - this.createParagraph(); + const para = new Paragraph({}); + this.addParagraph(para); } return super.prepForXml(); } - public createParagraph(text?: string): Paragraph { - const para = new Paragraph(text); - this.addParagraph(para); - - return para; - } - public setVerticalAlign(type: VerticalAlign): TableCell { this.properties.setVerticalAlign(type); diff --git a/src/file/table/table.spec.ts b/src/file/table/table.spec.ts index 0407b85718..de814ace20 100644 --- a/src/file/table/table.spec.ts +++ b/src/file/table/table.spec.ts @@ -341,37 +341,6 @@ describe("Table", () => { }); }); }); - - describe("#createParagraph", () => { - it("inserts a new paragraph in the cell", () => { - const table = new Table({ - rows: 1, - columns: 1, - }); - const para = table.getCell(0, 0).createParagraph("Test paragraph"); - expect(para).to.be.an.instanceof(Paragraph); - const tree = new Formatter().format(table); - expect(tree) - .to.have.property("w:tbl") - .which.is.an("array"); - const row = tree["w:tbl"].find((x) => x["w:tr"]); - expect(row).not.to.be.undefined; - expect(row["w:tr"]) - .to.be.an("array") - .which.has.length.at.least(1); - expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({ - "w:tc": [ - { - "w:p": [ - { - "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "Test paragraph"] }], - }, - ], - }, - ], - }); - }); - }); }); describe("#float", () => {