From fb65bb4207ce9b94f4d248ae05337a2b7eb3e3e8 Mon Sep 17 00:00:00 2001 From: Dolan Date: Mon, 17 Jun 2019 01:51:57 +0100 Subject: [PATCH] Turn Run into a declaritive API --- demo/demo1.ts | 10 +- demo/demo10.ts | 15 +- demo/demo19.ts | 10 +- demo/demo2.ts | 32 +++- demo/demo22.ts | 29 +++- demo/demo26.ts | 20 ++- demo/demo28.ts | 25 ++- demo/demo29.ts | 65 +++++--- demo/demo3.ts | 65 ++++++-- demo/demo31.ts | 10 +- demo/demo35.ts | 3 +- demo/demo6.ts | 10 +- src/export/formatter.spec.ts | 7 +- src/file/file.ts | 4 +- .../run/continuation-seperator-run.ts | 2 +- .../footnote/run/footnote-ref-run.ts | 5 +- .../footnotes/footnote/run/reference-run.ts | 2 +- .../footnotes/footnote/run/seperator-run.ts | 2 +- src/file/paragraph/formatting/page-break.ts | 2 +- src/file/paragraph/links/hyperlink.ts | 5 +- src/file/paragraph/run/picture-run.ts | 2 +- src/file/paragraph/run/run.spec.ts | 78 ++++++---- src/file/paragraph/run/run.ts | 147 ++++++++++-------- .../paragraph/run/sequential-identifier.ts | 2 +- src/file/paragraph/run/text-run.ts | 18 ++- src/file/paragraph/run/underline.ts | 20 +++ .../table-of-contents/table-of-contents.ts | 4 +- 27 files changed, 411 insertions(+), 183 deletions(-) diff --git a/demo/demo1.ts b/demo/demo1.ts index ba3a0bcc2f..83a9a3abd8 100644 --- a/demo/demo1.ts +++ b/demo/demo1.ts @@ -6,8 +6,14 @@ import { Document, Packer, Paragraph, TextRun } from "../build"; const doc = new Document(); const paragraph = new Paragraph("Hello World"); -const institutionText = new TextRun("Foo Bar").bold(); -const dateText = new TextRun("Github is the best").tab().bold(); +const institutionText = new TextRun({ + text: "Foo Bar", + bold: true, +}); +const dateText = new TextRun({ + text: "Github is the best", + bold: true, +}).tab(); paragraph.addRun(institutionText); paragraph.addRun(dateText); diff --git a/demo/demo10.ts b/demo/demo10.ts index 5cb04d1cdb..8f312af128 100644 --- a/demo/demo10.ts +++ b/demo/demo10.ts @@ -241,8 +241,14 @@ class DocumentCreator { maxRight: {}, }, }); - const institution = new TextRun(institutionName).bold(); - const date = new TextRun(dateText).tab().bold(); + const institution = new TextRun({ + text: institutionName, + bold: true, + }); + const date = new TextRun({ + text: dateText, + bold: true, + }).tab(); paragraph.addRun(institution); paragraph.addRun(date); @@ -252,7 +258,10 @@ class DocumentCreator { public createRoleText(roleText: string): Paragraph { const paragraph = new Paragraph({}); - const role = new TextRun(roleText).italics(); + const role = new TextRun({ + text: roleText, + italics: true, + }); paragraph.addRun(role); diff --git a/demo/demo19.ts b/demo/demo19.ts index 52b5fd6694..819de0bd74 100644 --- a/demo/demo19.ts +++ b/demo/demo19.ts @@ -6,8 +6,14 @@ import { Document, Packer, Paragraph, TextRun } from "../build"; const doc = new Document(); const paragraph = new Paragraph("Hello World"); -const institutionText = new TextRun("Foo").bold(); -const dateText = new TextRun("Bar").tab().bold(); +const institutionText = new TextRun({ + text: "Foo", + bold: true, +}); +const dateText = new TextRun({ + text: "Bar", + bold: true, +}).tab(); paragraph.addRun(institutionText); paragraph.addRun(dateText); diff --git a/demo/demo2.ts b/demo/demo2.ts index 9960234dc7..c15942db5b 100644 --- a/demo/demo2.ts +++ b/demo/demo2.ts @@ -92,7 +92,16 @@ doc.addParagraph( }), ); -doc.addParagraph(new Paragraph({}).addRun(new TextRun("Some monospaced content").font("Monospace"))); +doc.addParagraph( + new Paragraph({}).addRun( + new TextRun({ + text: "Some monospaced content", + font: { + name: "Monospace", + }, + }), + ), +); doc.addParagraph( new Paragraph({ @@ -108,10 +117,25 @@ doc.addParagraph( ); const para = new Paragraph({}); doc.addParagraph(para); -para.addRun(new TextRun("This is a bold run,").bold()); +// Showing the different ways to create a TextRun +para.addRun( + new TextRun({ + text: "This is a bold run,", + bold: true, + }), +); para.addRun(new TextRun(" switching to normal ")); -para.addRun(new TextRun("and then underlined ").underline()); -para.addRun(new TextRun("and back to normal.")); +para.addRun( + new TextRun({ + text: "and then underlined ", + underline: {}, + }), +); +para.addRun( + new TextRun({ + text: "and back to normal.", + }), +); const packer = new Packer(); diff --git a/demo/demo22.ts b/demo/demo22.ts index 6f5baa970c..c13d867f5d 100644 --- a/demo/demo22.ts +++ b/demo/demo22.ts @@ -5,18 +5,35 @@ import { Document, Packer, Paragraph, TextRun } from "../build"; const doc = new Document(); -const paragraph1 = new Paragraph().bidirectional(); -const textRun1 = new TextRun("שלום עולם").rightToLeft(); +const paragraph1 = new Paragraph({ + bidirectional: true, +}); +const textRun1 = new TextRun({ + text: "שלום עולם", + rightToLeft: true, +}); paragraph1.addRun(textRun1); doc.addParagraph(paragraph1); -const paragraph2 = new Paragraph().bidirectional(); -const textRun2 = new TextRun("שלום עולם").bold().rightToLeft(); +const paragraph2 = new Paragraph({ + bidirectional: true, +}); +const textRun2 = new TextRun({ + text: "שלום עולם", + bold: true, + rightToLeft: true, +}); paragraph2.addRun(textRun2); doc.addParagraph(paragraph2); -const paragraph3 = new Paragraph().bidirectional(); -const textRun3 = new TextRun("שלום עולם").italics().rightToLeft(); +const paragraph3 = new Paragraph({ + bidirectional: true, +}); +const textRun3 = new TextRun({ + text: "שלום עולם", + italics: true, + rightToLeft: true, +}); paragraph3.addRun(textRun3); doc.addParagraph(paragraph3); diff --git a/demo/demo26.ts b/demo/demo26.ts index 9fa560d260..613d624091 100644 --- a/demo/demo26.ts +++ b/demo/demo26.ts @@ -9,9 +9,23 @@ const paragraph = new Paragraph("No border!"); doc.addParagraph(paragraph); -const borderParagraph = new Paragraph("I have borders on my top and bottom sides!").createBorder(); -borderParagraph.Borders.addTopBorder(); -borderParagraph.Borders.addBottomBorder(); +const borderParagraph = new Paragraph({ + text: "I have borders on my top and bottom sides!", + border: { + top: { + color: "auto", + space: 1, + value: "single", + size: 6, + }, + bottom: { + color: "auto", + space: 1, + value: "single", + size: 6, + }, + }, +}); doc.addParagraph(borderParagraph); diff --git a/demo/demo28.ts b/demo/demo28.ts index aec36f5bfd..20e4a50026 100644 --- a/demo/demo28.ts +++ b/demo/demo28.ts @@ -1,7 +1,7 @@ // Table of contents // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { File, Packer, Paragraph, StyleLevel, TableOfContents } from "../build"; +import { File, HeadingLevel, Packer, Paragraph, StyleLevel, TableOfContents } from "../build"; const doc = new File(); @@ -26,15 +26,30 @@ const toc = new TableOfContents("Summary", { doc.addTableOfContents(toc); -doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore()); +doc.addParagraph(new Paragraph({ + text: "Header #1", + heading: HeadingLevel.HEADING_1, + pageBreakBefore: true, +})); doc.addParagraph(new Paragraph("I'm a little text very nicely written.'")); -doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore()); +doc.addParagraph(new Paragraph({ + text: "Header #2", + heading: HeadingLevel.HEADING_1, + pageBreakBefore: true, +})); doc.addParagraph(new Paragraph("I'm a other text very nicely written.'")); -doc.addParagraph(new Paragraph("Header #2.1").heading2()); +doc.addParagraph(new Paragraph({ + text: "Header #2.1", + heading: HeadingLevel.HEADING_2, +})); doc.addParagraph(new Paragraph("I'm a another text very nicely written.'")); -doc.addParagraph(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pageBreakBefore()); +doc.addParagraph(new Paragraph({ + text: "My Spectacular Style #1", + style: "MySpectacularStyle", + pageBreakBefore: true, +})); const packer = new Packer(); diff --git a/demo/demo29.ts b/demo/demo29.ts index 0439d372d7..bbf6b8d125 100644 --- a/demo/demo29.ts +++ b/demo/demo29.ts @@ -12,27 +12,50 @@ abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new const concrete = numbering.createConcreteNumbering(abstractNum); -const item1 = new Paragraph("line with contextual spacing"); -const item2 = new Paragraph("line with contextual spacing"); -const item3 = new Paragraph("line without contextual spacing"); -const item4 = new Paragraph("line without contextual spacing"); - -item1 - .setNumbering(concrete, 0) - .spacing({ before: 200 }) - .contextualSpacing(true); -item2 - .setNumbering(concrete, 0) - .spacing({ before: 200 }) - .contextualSpacing(true); -item3 - .setNumbering(concrete, 0) - .spacing({ before: 200 }) - .contextualSpacing(false); -item4 - .setNumbering(concrete, 0) - .spacing({ before: 200 }) - .contextualSpacing(false); +const item1 = new Paragraph({ + text: "line with contextual spacing", + numbering: { + num: concrete, + level: 0, + }, + contextualSpacing: true, + spacing: { + before: 200, + }, +}); +const item2 = new Paragraph({ + text: "line with contextual spacing", + numbering: { + num: concrete, + level: 0, + }, + contextualSpacing: true, + spacing: { + before: 200, + }, +}); +const item3 = new Paragraph({ + text: "line without contextual spacing", + numbering: { + num: concrete, + level: 0, + }, + contextualSpacing: false, + spacing: { + before: 200, + }, +}); +const item4 = new Paragraph({ + text: "line without contextual spacing", + numbering: { + num: concrete, + level: 0, + }, + contextualSpacing: false, + spacing: { + before: 200, + }, +}); doc.addParagraph(item1); doc.addParagraph(item2); diff --git a/demo/demo3.ts b/demo/demo3.ts index ac3680ef32..e526b8e523 100644 --- a/demo/demo3.ts +++ b/demo/demo3.ts @@ -14,25 +14,64 @@ abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(n const concrete = numbering.createConcreteNumbering(abstractNum); -const topLevelP = new Paragraph("Hey you"); -const subP = new Paragraph("What's up fam"); -const secondSubP = new Paragraph("Hello World 2"); -const subSubP = new Paragraph("Yeah boi"); - -topLevelP.setNumbering(concrete, 0); -subP.setNumbering(concrete, 1); -secondSubP.setNumbering(concrete, 1); -subSubP.setNumbering(concrete, 2); +const topLevelP = new Paragraph({ + text: "Hey you", + numbering: { + num: concrete, + level: 0, + }, +}); +const subP = new Paragraph({ + text: "What's up fam", + numbering: { + num: concrete, + level: 1, + }, +}); +const secondSubP = new Paragraph({ + text: "Hello World 2", + numbering: { + num: concrete, + level: 1, + }, +}); +const subSubP = new Paragraph({ + text: "Yeah boi", + numbering: { + num: concrete, + level: 2, + }, +}); doc.addParagraph(topLevelP); doc.addParagraph(subP); doc.addParagraph(secondSubP); doc.addParagraph(subSubP); -const bullet1 = new Paragraph("Hey you").bullet(); -const bullet2 = new Paragraph("What's up fam").bullet(1); -const bullet3 = new Paragraph("Hello World 2").bullet(2); -const bullet4 = new Paragraph("Yeah boi").bullet(3); +const bullet1 = new Paragraph({ + text: "Hey you", + bullet: { + level: 0, + }, +}); +const bullet2 = new Paragraph({ + text: "What's up fam", + bullet: { + level: 1, + }, +}); +const bullet3 = new Paragraph({ + text: "Hello World 2", + bullet: { + level: 2, + }, +}); +const bullet4 = new Paragraph({ + text: "Yeah boi", + bullet: { + level: 3, + }, +}); doc.addParagraph(bullet1); doc.addParagraph(bullet2); diff --git a/demo/demo31.ts b/demo/demo31.ts index e05a20f454..a17f18b94c 100644 --- a/demo/demo31.ts +++ b/demo/demo31.ts @@ -1,7 +1,7 @@ // Example of how you would create a table and add data to it // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph, VerticalAlign } from "../build"; +import { Document, HeadingLevel, Packer, Paragraph, VerticalAlign } from "../build"; const doc = new Document(); @@ -17,9 +17,11 @@ table table .getCell(1, 0) .addParagraph( - new Paragraph( - "Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah", - ).heading1(), + new Paragraph({ + text: + "Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah", + heading: HeadingLevel.HEADING_1, + }), ); const packer = new Packer(); diff --git a/demo/demo35.ts b/demo/demo35.ts index 05ef010c1a..04573edc1e 100644 --- a/demo/demo35.ts +++ b/demo/demo35.ts @@ -4,10 +4,9 @@ import * as fs from "fs"; import { Document, Packer, Paragraph } from "../build"; const doc = new Document(); -const paragraph = new Paragraph(); +const paragraph = new Paragraph({}); const link = doc.createHyperlink("http://www.example.com", "Hyperlink"); -link.bold(); paragraph.addHyperLink(link); doc.addParagraph(paragraph); diff --git a/demo/demo6.ts b/demo/demo6.ts index 524a801d8a..042f6d7d94 100644 --- a/demo/demo6.ts +++ b/demo/demo6.ts @@ -11,8 +11,14 @@ const doc = new Document(undefined, { }); const paragraph = new Paragraph("Hello World"); -const institutionText = new TextRun("Foo bar").bold(); -const dateText = new TextRun("Github is the best").tab().bold(); +const institutionText = new TextRun({ + text: "Foo bar", + bold: true, +}); +const dateText = new TextRun({ + text: "Github is the best", + bold: true, +}).tab(); paragraph.addRun(institutionText); paragraph.addRun(dateText); diff --git a/src/export/formatter.spec.ts b/src/export/formatter.spec.ts index a76bad29c0..a2f0c971ab 100644 --- a/src/export/formatter.spec.ts +++ b/src/export/formatter.spec.ts @@ -29,7 +29,12 @@ describe("Formatter", () => { it("should format simple paragraph with bold text", () => { const paragraph = new file.Paragraph(""); - paragraph.addRun(new file.TextRun("test").bold()); + paragraph.addRun( + new file.TextRun({ + text: "test", + bold: true, + }), + ); const newJson = formatter.format(paragraph); assert.isDefined(newJson["w:p"][1]["w:r"][0]["w:rPr"][0]["w:b"]._attr["w:val"]); }); diff --git a/src/file/file.ts b/src/file/file.ts index 747077bd36..50f4ff9613 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -30,6 +30,8 @@ import { TableOfContents } from "./table-of-contents"; export class File { // tslint:disable-next-line:readonly-keyword private currentRelationshipId: number = 1; + // tslint:disable-next-line:readonly-keyword + private styles: Styles; private readonly document: Document; private readonly headers: IDocumentHeader[] = []; @@ -43,8 +45,6 @@ export class File { private readonly settings: Settings; private readonly contentTypes: ContentTypes; private readonly appProperties: AppProperties; - // tslint:disable-next-line:readonly-keyword - private styles: Styles; constructor( options: IPropertiesOptions = { diff --git a/src/file/footnotes/footnote/run/continuation-seperator-run.ts b/src/file/footnotes/footnote/run/continuation-seperator-run.ts index 4cf3ad2d21..8e55b9bb7f 100644 --- a/src/file/footnotes/footnote/run/continuation-seperator-run.ts +++ b/src/file/footnotes/footnote/run/continuation-seperator-run.ts @@ -3,7 +3,7 @@ import { ContinuationSeperator } from "./continuation-seperator"; export class ContinuationSeperatorRun extends Run { constructor() { - super(); + super({}); this.root.push(new ContinuationSeperator()); } diff --git a/src/file/footnotes/footnote/run/footnote-ref-run.ts b/src/file/footnotes/footnote/run/footnote-ref-run.ts index 65ef0b697a..4be3493b33 100644 --- a/src/file/footnotes/footnote/run/footnote-ref-run.ts +++ b/src/file/footnotes/footnote/run/footnote-ref-run.ts @@ -3,9 +3,10 @@ import { FootnoteRef } from "./footnote-ref"; export class FootnoteRefRun extends Run { constructor() { - super(); + super({ + style: "FootnoteReference", + }); - this.style("FootnoteReference"); this.root.push(new FootnoteRef()); } } diff --git a/src/file/footnotes/footnote/run/reference-run.ts b/src/file/footnotes/footnote/run/reference-run.ts index 278120ed70..7dec91473d 100644 --- a/src/file/footnotes/footnote/run/reference-run.ts +++ b/src/file/footnotes/footnote/run/reference-run.ts @@ -26,7 +26,7 @@ export class FootnoteReference extends XmlComponent { export class FootnoteReferenceRun extends Run { constructor(id: number) { - super(); + super({}); this.properties.push(new Style("FootnoteReference")); diff --git a/src/file/footnotes/footnote/run/seperator-run.ts b/src/file/footnotes/footnote/run/seperator-run.ts index 17cc69d8ec..c5a0f9b252 100644 --- a/src/file/footnotes/footnote/run/seperator-run.ts +++ b/src/file/footnotes/footnote/run/seperator-run.ts @@ -3,7 +3,7 @@ import { Seperator } from "./seperator"; export class SeperatorRun extends Run { constructor() { - super(); + super({}); this.root.push(new Seperator()); } diff --git a/src/file/paragraph/formatting/page-break.ts b/src/file/paragraph/formatting/page-break.ts index 13556d12e2..af08f766d3 100644 --- a/src/file/paragraph/formatting/page-break.ts +++ b/src/file/paragraph/formatting/page-break.ts @@ -15,7 +15,7 @@ class Break extends XmlComponent { export class PageBreak extends Run { constructor() { - super(); + super({}); this.root.push(new Break()); } } diff --git a/src/file/paragraph/links/hyperlink.ts b/src/file/paragraph/links/hyperlink.ts index 3ed33f44ad..b41980ed77 100644 --- a/src/file/paragraph/links/hyperlink.ts +++ b/src/file/paragraph/links/hyperlink.ts @@ -20,7 +20,10 @@ export class Hyperlink extends XmlComponent { const attributes = new HyperlinkAttributes(props); this.root.push(attributes); - this.textRun = new TextRun(text).style("Hyperlink"); + this.textRun = new TextRun({ + text: text, + style: "Hyperlink", + }); this.root.push(this.textRun); } diff --git a/src/file/paragraph/run/picture-run.ts b/src/file/paragraph/run/picture-run.ts index 15da74eb56..9f8cd7393c 100644 --- a/src/file/paragraph/run/picture-run.ts +++ b/src/file/paragraph/run/picture-run.ts @@ -7,7 +7,7 @@ export class PictureRun extends Run { private readonly drawing: Drawing; constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { - super(); + super({}); if (imageData === undefined) { throw new Error("imageData cannot be undefined"); diff --git a/src/file/paragraph/run/run.spec.ts b/src/file/paragraph/run/run.spec.ts index c30147d22f..bb72e65b3a 100644 --- a/src/file/paragraph/run/run.spec.ts +++ b/src/file/paragraph/run/run.spec.ts @@ -4,17 +4,14 @@ import { Formatter } from "export/formatter"; import { Utility } from "tests/utility"; import { Run } from "./"; +import { UnderlineType } from "./underline"; describe("Run", () => { - let run: Run; - - beforeEach(() => { - run = new Run(); - }); - describe("#bold()", () => { it("it should add bold to the properties", () => { - run.bold(); + const run = new Run({ + bold: true, + }); const newJson = Utility.jsonify(run); assert.equal(newJson.root[0].root[0].rootKey, "w:b"); assert.equal(newJson.root[0].root[1].rootKey, "w:bCs"); @@ -23,7 +20,9 @@ describe("Run", () => { describe("#italics()", () => { it("it should add italics to the properties", () => { - run.italics(); + const run = new Run({ + italics: true, + }); const newJson = Utility.jsonify(run); assert.equal(newJson.root[0].root[0].rootKey, "w:i"); assert.equal(newJson.root[0].root[1].rootKey, "w:iCs"); @@ -31,14 +30,10 @@ describe("Run", () => { }); describe("#underline()", () => { - it("it should add underline to the properties", () => { - run.underline(); - const newJson = Utility.jsonify(run); - assert.equal(newJson.root[0].root[0].rootKey, "w:u"); - }); - it("should default to 'single' and no color", () => { - run.underline(); + const run = new Run({ + underline: {}, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [{ "w:rPr": [{ "w:u": { _attr: { "w:val": "single" } } }] }], @@ -46,7 +41,12 @@ describe("Run", () => { }); it("should set the style type and color if given", () => { - run.underline("double", "990011"); + const run = new Run({ + underline: { + type: UnderlineType.DOUBLE, + color: "990011", + }, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [{ "w:rPr": [{ "w:u": { _attr: { "w:val": "double", "w:color": "990011" } } }] }], @@ -56,7 +56,9 @@ describe("Run", () => { describe("#smallCaps()", () => { it("it should add smallCaps to the properties", () => { - run.smallCaps(); + const run = new Run({ + smallCaps: true, + }); const newJson = Utility.jsonify(run); assert.equal(newJson.root[0].root[0].rootKey, "w:smallCaps"); }); @@ -64,7 +66,9 @@ describe("Run", () => { describe("#caps()", () => { it("it should add caps to the properties", () => { - run.allCaps(); + const run = new Run({ + allCaps: true, + }); const newJson = Utility.jsonify(run); assert.equal(newJson.root[0].root[0].rootKey, "w:caps"); }); @@ -72,7 +76,9 @@ describe("Run", () => { describe("#strike()", () => { it("it should add strike to the properties", () => { - run.strike(); + const run = new Run({ + strike: true, + }); const newJson = Utility.jsonify(run); assert.equal(newJson.root[0].root[0].rootKey, "w:strike"); }); @@ -80,7 +86,9 @@ describe("Run", () => { describe("#doubleStrike()", () => { it("it should add caps to the properties", () => { - run.doubleStrike(); + const run = new Run({ + doubleStrike: true, + }); const newJson = Utility.jsonify(run); assert.equal(newJson.root[0].root[0].rootKey, "w:dstrike"); }); @@ -88,6 +96,7 @@ describe("Run", () => { describe("#break()", () => { it("it should add break to the run", () => { + const run = new Run({}); run.break(); const newJson = Utility.jsonify(run); assert.equal(newJson.root[1].rootKey, "w:br"); @@ -96,6 +105,7 @@ describe("Run", () => { describe("#tab()", () => { it("it should add break to the run", () => { + const run = new Run({}); run.tab(); const newJson = Utility.jsonify(run); assert.equal(newJson.root[1].rootKey, "w:tab"); @@ -103,12 +113,12 @@ describe("Run", () => { }); describe("#font()", () => { - it("should allow chaining calls", () => { - expect(run.font("Times")).to.equal(run); - }); - it("should set the font as named", () => { - run.font("Times"); + const run = new Run({ + font: { + name: "Times", + }, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [ @@ -124,7 +134,9 @@ describe("Run", () => { describe("#color", () => { it("should set the run to the color given", () => { - run.color("001122"); + const run = new Run({ + color: "001122", + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [{ "w:rPr": [{ "w:color": { _attr: { "w:val": "001122" } } }] }], @@ -134,7 +146,9 @@ describe("Run", () => { describe("#size", () => { it("should set the run to the given size", () => { - run.size(24); + const run = new Run({ + size: 24, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [ @@ -148,7 +162,9 @@ describe("Run", () => { describe("#rtl", () => { it("should set the run to the RTL mode", () => { - run.rightToLeft(); + const run = new Run({ + rightToLeft: true, + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [{ "w:rPr": [{ "w:rtl": { _attr: { "w:val": true } } }] }], @@ -158,6 +174,7 @@ describe("Run", () => { describe("#numberOfTotalPages", () => { it("should set the run to the RTL mode", () => { + const run = new Run({}); run.numberOfTotalPages(); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ @@ -173,6 +190,7 @@ describe("Run", () => { describe("#pageNumber", () => { it("should set the run to the RTL mode", () => { + const run = new Run({}); run.pageNumber(); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ @@ -188,7 +206,9 @@ describe("Run", () => { describe("#style", () => { it("should set the style to the given styleId", () => { - run.style("myRunStyle"); + const run = new Run({ + style: "myRunStyle", + }); const tree = new Formatter().format(run); expect(tree).to.deep.equal({ "w:r": [{ "w:rPr": [{ "w:rStyle": { _attr: { "w:val": "myRunStyle" } } }] }], diff --git a/src/file/paragraph/run/run.ts b/src/file/paragraph/run/run.ts index 32777cd31d..8909fe66bf 100644 --- a/src/file/paragraph/run/run.ts +++ b/src/file/paragraph/run/run.ts @@ -20,50 +20,99 @@ import { RunFonts } from "./run-fonts"; import { SubScript, SuperScript } from "./script"; import { Style } from "./style"; import { Tab } from "./tab"; -import { Underline } from "./underline"; +import { Underline, UnderlineType } from "./underline"; import { XmlComponent } from "file/xml-components"; +export interface IRunOptions { + readonly bold?: true; + readonly italics?: true; + readonly underline?: { + readonly color?: string; + readonly type?: UnderlineType; + }; + readonly color?: string; + readonly size?: number; + readonly rightToLeft?: boolean; + readonly smallCaps?: boolean; + readonly allCaps?: boolean; + readonly strike?: boolean; + readonly doubleStrike?: boolean; + readonly subScript?: boolean; + readonly superScript?: boolean; + readonly style?: string; + readonly font?: { + readonly name: string; + readonly hint?: string; + }; +} + export class Run extends XmlComponent { protected readonly properties: RunProperties; - constructor() { + constructor(options: IRunOptions) { super("w:r"); this.properties = new RunProperties(); this.root.push(this.properties); - } - public bold(): Run { - this.properties.push(new Bold()); - this.properties.push(new BoldComplexScript()); - return this; - } + if (options.bold) { + this.properties.push(new Bold()); + this.properties.push(new BoldComplexScript()); + } - public italics(): Run { - this.properties.push(new Italics()); - this.properties.push(new ItalicsComplexScript()); - return this; - } + if (options.italics) { + this.properties.push(new Italics()); + this.properties.push(new ItalicsComplexScript()); + } - public underline(underlineType?: string, color?: string): Run { - this.properties.push(new Underline(underlineType, color)); - return this; - } + if (options.underline) { + this.properties.push(new Underline(options.underline.type, options.underline.color)); + } - public color(color: string): Run { - this.properties.push(new Color(color)); - return this; - } + if (options.color) { + this.properties.push(new Color(options.color)); + } - public size(size: number): Run { - this.properties.push(new Size(size)); - this.properties.push(new SizeComplexScript(size)); - return this; - } + if (options.size) { + this.properties.push(new Size(options.size)); + this.properties.push(new SizeComplexScript(options.size)); + } - public rightToLeft(): Run { - this.properties.push(new RightToLeft()); - return this; + if (options.rightToLeft) { + this.properties.push(new RightToLeft()); + } + + if (options.smallCaps) { + this.properties.push(new SmallCaps()); + } + + if (options.allCaps) { + this.properties.push(new Caps()); + } + + if (options.strike) { + this.properties.push(new Strike()); + } + + if (options.doubleStrike) { + this.properties.push(new DoubleStrike()); + } + + if (options.subScript) { + this.properties.push(new SubScript()); + } + + if (options.superScript) { + this.properties.push(new SuperScript()); + } + + if (options.style) { + this.properties.push(new Style(options.style)); + } + + if (options.font) { + this.properties.push(new RunFonts(options.font.name, options.font.hint)); + } } public break(): Run { @@ -91,44 +140,4 @@ export class Run extends XmlComponent { this.root.push(new End()); return this; } - - public smallCaps(): Run { - this.properties.push(new SmallCaps()); - return this; - } - - public allCaps(): Run { - this.properties.push(new Caps()); - return this; - } - - public strike(): Run { - this.properties.push(new Strike()); - return this; - } - - public doubleStrike(): Run { - this.properties.push(new DoubleStrike()); - return this; - } - - public subScript(): Run { - this.properties.push(new SubScript()); - return this; - } - - public superScript(): Run { - this.properties.push(new SuperScript()); - return this; - } - - public font(fontName: string, hint?: string | undefined): Run { - this.properties.push(new RunFonts(fontName, hint)); - return this; - } - - public style(styleId: string): Run { - this.properties.push(new Style(styleId)); - return this; - } } diff --git a/src/file/paragraph/run/sequential-identifier.ts b/src/file/paragraph/run/sequential-identifier.ts index 5536eca4ae..e193307e83 100644 --- a/src/file/paragraph/run/sequential-identifier.ts +++ b/src/file/paragraph/run/sequential-identifier.ts @@ -4,7 +4,7 @@ import { SequentialIdentifierInstruction } from "./sequential-identifier-instruc export class SequentialIdentifier extends Run { constructor(identifier: string) { - super(); + super({}); this.root.push(new Begin(true)); this.root.push(new SequentialIdentifierInstruction(identifier)); this.root.push(new Separate()); diff --git a/src/file/paragraph/run/text-run.ts b/src/file/paragraph/run/text-run.ts index 4b0474edc6..eeacf2dfd5 100644 --- a/src/file/paragraph/run/text-run.ts +++ b/src/file/paragraph/run/text-run.ts @@ -1,9 +1,19 @@ -import { Run } from "../run"; +import { IRunOptions, Run } from "./run"; import { Text } from "./run-components/text"; +export interface ITextRunOptions extends IRunOptions { + readonly text: string; +} + export class TextRun extends Run { - constructor(text: string) { - super(); - this.root.push(new Text(text)); + constructor(options: ITextRunOptions | string) { + if (typeof options === "string") { + super({}); + this.root.push(new Text(options)); + return; + } + + super(options); + this.root.push(new Text(options.text)); } } diff --git a/src/file/paragraph/run/underline.ts b/src/file/paragraph/run/underline.ts index bb994e040b..7d4a1c98d1 100644 --- a/src/file/paragraph/run/underline.ts +++ b/src/file/paragraph/run/underline.ts @@ -1,5 +1,25 @@ import { Attributes, XmlComponent } from "file/xml-components"; +export enum UnderlineType { + SINGLE = "single", + WORDS = "words", + DOUBLE = "double", + THICK = "thick", + DOTTED = "dotted", + DOTTEDHEAVY = "dottedHeavy", + DASH = "dash", + DASHEDHEAVY = "dashedHeavy", + DASHLONG = "dashLong", + DASHLONGHEAVY = "dashLongHeavy", + DOTDASH = "dotDash", + DASHDOTHEAVY = "dashDotHeavy", + DOTDOTDASH = "dotDotDash", + DASHDOTDOTHEAVY = "dashDotDotHeavy", + WAVE = "wave", + WAVYHEAVY = "wavyHeavy", + WAVYDOUBLE = "wavyDouble", +} + export abstract class BaseUnderline extends XmlComponent { constructor(underlineType: string, color?: string) { super("w:u"); diff --git a/src/file/table-of-contents/table-of-contents.ts b/src/file/table-of-contents/table-of-contents.ts index 6b2c69e1bf..57acbb3ace 100644 --- a/src/file/table-of-contents/table-of-contents.ts +++ b/src/file/table-of-contents/table-of-contents.ts @@ -17,7 +17,7 @@ export class TableOfContents extends XmlComponent { const content = new StructuredDocumentTagContent(); const beginParagraph = new Paragraph({}); - const beginRun = new Run(); + const beginRun = new Run({}); beginRun.addChildElement(new Begin(true)); beginRun.addChildElement(new FieldInstruction(properties)); beginRun.addChildElement(new Separate()); @@ -25,7 +25,7 @@ export class TableOfContents extends XmlComponent { content.addChildElement(beginParagraph); const endParagraph = new Paragraph({}); - const endRun = new Run(); + const endRun = new Run({}); endRun.addChildElement(new End()); endParagraph.addRun(endRun); content.addChildElement(endParagraph);