From 11ce9a52067a372ed251999f7d1ae946934aa789 Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 12 Sep 2018 21:01:52 +0100 Subject: [PATCH 01/15] Add horizontal span --- src/file/table/grid.ts | 1 + src/file/table/table.ts | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/file/table/grid.ts b/src/file/table/grid.ts index d9338e7dc4..0e477df946 100644 --- a/src/file/table/grid.ts +++ b/src/file/table/grid.ts @@ -1,3 +1,4 @@ +// http://officeopenxml.com/WPtableGrid.php import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; export class TableGrid extends XmlComponent { diff --git a/src/file/table/table.ts b/src/file/table/table.ts index 0406bdf549..2dfc051e22 100644 --- a/src/file/table/table.ts +++ b/src/file/table/table.ts @@ -1,3 +1,4 @@ +// http://officeopenxml.com/WPtableGrid.php import { GridSpan, TableCellBorders, @@ -51,7 +52,7 @@ export class Table extends XmlComponent { for (let i = 0; i < rows; i++) { const cells: TableCell[] = []; for (let j = 0; j < cols; j++) { - cells.push(new TableCell()); + cells.push(new TableCell(this, i, j)); } const row = new TableRow(cells); this.rows.push(row); @@ -60,7 +61,13 @@ export class Table extends XmlComponent { } public getRow(ix: number): TableRow { - return this.rows[ix]; + const row = this.rows[ix]; + + if (!row) { + throw Error("Index out of bounds when trying to get row on table"); + } + + return row; } public getCell(row: number, col: number): TableCell { @@ -93,7 +100,13 @@ export class TableRow extends XmlComponent { } public getCell(ix: number): TableCell { - return this.cells[ix]; + const cell = this.cells[ix]; + + if (!cell) { + throw Error("Index out of bounds when trying to get cell on row"); + } + + return cell; } public addGridSpan(ix: number, cellSpan: number): TableCell { @@ -115,7 +128,7 @@ export class TableRowProperties extends XmlComponent { export class TableCell extends XmlComponent { private readonly properties: TableCellProperties; - constructor() { + constructor(private readonly tableReference: Table, private readonly x: number, private readonly y: number) { super("w:tc"); this.properties = new TableCellProperties(); this.root.push(this.properties); @@ -142,6 +155,15 @@ export class TableCell extends XmlComponent { return para; } + public setHorizontalSpan(span: number): TableCell { + for (let i = 1; i < span; i++) { + this.tableReference.getCell(this.x, this.y + i).delete(); + } + this.properties.addGridSpan(span); + + return this; + } + public get CellProperties(): TableCellProperties { return this.properties; } From f1b176670caf4334fb10ef5b64dd451bc470221b Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 12 Sep 2018 21:03:06 +0100 Subject: [PATCH 02/15] Add more table demos --- demo/demo28.ts | 18 ++++++++++++++++++ demo/demo29.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 demo/demo28.ts create mode 100644 demo/demo29.ts diff --git a/demo/demo28.ts b/demo/demo28.ts new file mode 100644 index 0000000000..b7eab7b919 --- /dev/null +++ b/demo/demo28.ts @@ -0,0 +1,18 @@ +// 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"; + +const doc = new Document(); + +const table = doc.createTable(4, 4); +table + .getCell(2, 2) + .addContent(new Paragraph("This text should be in the middle of the cell")) + .CellProperties.setVerticalAlign(VerticalAlign.CENTER); + +const packer = new Packer(); + +packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/demo/demo29.ts b/demo/demo29.ts new file mode 100644 index 0000000000..8a5bc3fc03 --- /dev/null +++ b/demo/demo29.ts @@ -0,0 +1,26 @@ +// 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 } from "../build"; + +const doc = new Document(); + +const table = doc.createTable(2, 2); +table + .getCell(0, 0) + .addContent(new Paragraph("Hello")) + .setHorizontalSpan(2); + +doc.createParagraph("Another table").heading2(); + +const table2 = doc.createTable(2, 3); +table2 + .getCell(0, 0) + .addContent(new Paragraph("World")) + .setHorizontalSpan(3); + +const packer = new Packer(); + +packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); From a9167b48094c46186a5f82f0caafbf0050607b55 Mon Sep 17 00:00:00 2001 From: Dolan Date: Thu, 13 Sep 2018 01:54:37 +0100 Subject: [PATCH 03/15] Update demos --- demo/demo28.ts | 12 ++++++++++-- demo/demo29.ts | 21 +++++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/demo/demo28.ts b/demo/demo28.ts index b7eab7b919..366227102a 100644 --- a/demo/demo28.ts +++ b/demo/demo28.ts @@ -5,12 +5,20 @@ import { Document, Packer, Paragraph, VerticalAlign } from "../build"; const doc = new Document(); -const table = doc.createTable(4, 4); +const table = doc.createTable(2, 2); table - .getCell(2, 2) + .getCell(1, 1) .addContent(new Paragraph("This text should be in the middle of the cell")) .CellProperties.setVerticalAlign(VerticalAlign.CENTER); +table + .getCell(1, 0) + .addContent( + 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(), + ); + const packer = new Packer(); packer.toBuffer(doc).then((buffer) => { diff --git a/demo/demo29.ts b/demo/demo29.ts index 8a5bc3fc03..10a3318e03 100644 --- a/demo/demo29.ts +++ b/demo/demo29.ts @@ -5,20 +5,33 @@ import { Document, Packer, Paragraph } from "../build"; const doc = new Document(); -const table = doc.createTable(2, 2); -table +doc + .createTable(2, 2) .getCell(0, 0) .addContent(new Paragraph("Hello")) .setHorizontalSpan(2); doc.createParagraph("Another table").heading2(); -const table2 = doc.createTable(2, 3); -table2 +doc + .createTable(2, 3) .getCell(0, 0) .addContent(new Paragraph("World")) .setHorizontalSpan(3); +doc.createParagraph("Another table").heading2(); + +const table = doc.createTable(2, 4); +table + .getCell(0, 0) + .addContent(new Paragraph("Foo")) + .setHorizontalSpan(4); + +table.getCell(1, 0).addContent(new Paragraph("Bar1")); +table.getCell(1, 1).addContent(new Paragraph("Bar2")); +table.getCell(1, 2).addContent(new Paragraph("Bar3")); +table.getCell(1, 3).addContent(new Paragraph("Bar4")); + const packer = new Packer(); packer.toBuffer(doc).then((buffer) => { From f27c95191ba12c08ffd8f6cce7276bb6918ffe7c Mon Sep 17 00:00:00 2001 From: Dolan Date: Tue, 25 Sep 2018 21:19:04 +0100 Subject: [PATCH 04/15] Change documentation properties to options --- docs/usage/table-of-contents.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/usage/table-of-contents.md b/docs/usage/table-of-contents.md index 2f43da4c2f..7c226833cd 100644 --- a/docs/usage/table-of-contents.md +++ b/docs/usage/table-of-contents.md @@ -22,9 +22,9 @@ const toc = new TableOfContents("Summary", { doc.addTableOfContents(toc); ``` -## Table of Contents Properties +## Table of Contents Options -Here is the list of all properties that you can use to generate your tables of contents: +Here is the list of all options that you can use to generate your tables of contents: | Option | Type | TOC Field Switch | Description | | --- | --- | --- | --- | @@ -48,7 +48,7 @@ Here is the list of all properties that you can use to generate your tables of c ## Examples ```js -// Let's define the properties for generate a TOC for heading 1-5 and MySpectacularStyle, +// Let's define the options for generate a TOC for heading 1-5 and MySpectacularStyle, // making the entries be hyperlinks for the paragraph const toc = new TableOfContents("Summary", { hyperlink: true, From e08c7cbbfbcd7ea5d53250881f0645b8266014a9 Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 26 Sep 2018 02:12:10 +0100 Subject: [PATCH 05/15] Add table of contents to side bar --- docs/_sidebar.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 0b159a95a8..4b9a626a03 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -16,6 +16,7 @@ * [Bullet Points](usage/bullet-points.md) * [Numbering](usage/numbering.md) * [Tab Stops](usage/tab-stops.md) + * [Table of Contents](usage/table-of-contents.md) * Styling * [Styling with JS](usage/styling-with-js.md) * [Styling with XML](usage/styling-with-xml.md) From 2da3ba02625dc20040afc29f99eb2f1cf84ebc64 Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 26 Sep 2018 02:17:39 +0100 Subject: [PATCH 06/15] Rename variables --- ...ontents-instruction.ts => field-instruction.ts} | 3 ++- src/file/table-of-contents/sdt-content.ts | 2 +- src/file/table-of-contents/sdt-properties.ts | 3 ++- src/file/table-of-contents/table-of-contents.ts | 14 ++++++++------ 4 files changed, 13 insertions(+), 9 deletions(-) rename src/file/table-of-contents/{table-of-contents-instruction.ts => field-instruction.ts} (96%) diff --git a/src/file/table-of-contents/table-of-contents-instruction.ts b/src/file/table-of-contents/field-instruction.ts similarity index 96% rename from src/file/table-of-contents/table-of-contents-instruction.ts rename to src/file/table-of-contents/field-instruction.ts index 1183ebd3de..766e6fc2f2 100644 --- a/src/file/table-of-contents/table-of-contents-instruction.ts +++ b/src/file/table-of-contents/field-instruction.ts @@ -1,3 +1,4 @@ +// http://officeopenxml.com/WPfieldInstructions.php import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { ITableOfContentsOptions } from "./table-of-contents-properties"; @@ -10,7 +11,7 @@ class TextAttributes extends XmlAttributeComponent<{ space: SpaceType }> { protected xmlKeys = { space: "xml:space" }; } -export class TableOfContentsInstruction extends XmlComponent { +export class FieldInstruction extends XmlComponent { private readonly properties: ITableOfContentsOptions; constructor(properties: ITableOfContentsOptions = {}) { diff --git a/src/file/table-of-contents/sdt-content.ts b/src/file/table-of-contents/sdt-content.ts index e668da6052..5228ff447f 100644 --- a/src/file/table-of-contents/sdt-content.ts +++ b/src/file/table-of-contents/sdt-content.ts @@ -1,6 +1,6 @@ import { XmlComponent } from "file/xml-components"; -export class SdtContent extends XmlComponent { +export class StructuredDocumentTagContent extends XmlComponent { constructor() { super("w:sdtContent"); } diff --git a/src/file/table-of-contents/sdt-properties.ts b/src/file/table-of-contents/sdt-properties.ts index bb8ef77a6b..3f7019f561 100644 --- a/src/file/table-of-contents/sdt-properties.ts +++ b/src/file/table-of-contents/sdt-properties.ts @@ -1,7 +1,8 @@ +// http://www.datypic.com/sc/ooxml/e-w_sdtPr-1.html import { XmlComponent } from "file/xml-components"; import { Alias } from "./alias"; -export class SdtProperties extends XmlComponent { +export class StructuredDocumentTagProperties extends XmlComponent { constructor(alias: string) { super("w:sdtPr"); this.root.push(new Alias(alias)); diff --git a/src/file/table-of-contents/table-of-contents.ts b/src/file/table-of-contents/table-of-contents.ts index fb7b709c4f..7b1ff0f66d 100644 --- a/src/file/table-of-contents/table-of-contents.ts +++ b/src/file/table-of-contents/table-of-contents.ts @@ -1,23 +1,25 @@ +// http://officeopenxml.com/WPtableOfContents.php +// http://www.datypic.com/sc/ooxml/e-w_sdt-1.html import { Paragraph } from "file/paragraph"; import { Run } from "file/paragraph/run"; import { Begin, End, Separate } from "file/paragraph/run/field"; import { XmlComponent } from "file/xml-components"; -import { SdtContent } from "./sdt-content"; -import { SdtProperties } from "./sdt-properties"; -import { TableOfContentsInstruction } from "./table-of-contents-instruction"; +import { FieldInstruction } from "./field-instruction"; +import { StructuredDocumentTagContent } from "./sdt-content"; +import { StructuredDocumentTagProperties } from "./sdt-properties"; import { ITableOfContentsOptions } from "./table-of-contents-properties"; export class TableOfContents extends XmlComponent { constructor(alias: string = "Table of Contents", properties?: ITableOfContentsOptions) { super("w:sdt"); - this.root.push(new SdtProperties(alias)); + this.root.push(new StructuredDocumentTagProperties(alias)); - const content = new SdtContent(); + const content = new StructuredDocumentTagContent(); const beginParagraph = new Paragraph(); const beginRun = new Run(); beginRun.addChildElement(new Begin(true)); - beginRun.addChildElement(new TableOfContentsInstruction(properties)); + beginRun.addChildElement(new FieldInstruction(properties)); beginRun.addChildElement(new Separate()); beginParagraph.addRun(beginRun); content.addChildElement(beginParagraph); From 2fb584550167b67ece79d23bf95952a0ad98e9bf Mon Sep 17 00:00:00 2001 From: amitm02 Date: Wed, 26 Sep 2018 17:47:17 +0300 Subject: [PATCH 07/15] contextual spacing --- demo/demo29.ts | 32 ++++++++++++++++++++++++ src/file/paragraph/formatting/spacing.ts | 13 +++++++++- src/file/paragraph/paragraph.ts | 7 +++++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 demo/demo29.ts diff --git a/demo/demo29.ts b/demo/demo29.ts new file mode 100644 index 0000000000..0650aac09c --- /dev/null +++ b/demo/demo29.ts @@ -0,0 +1,32 @@ +import * as fs from "fs"; +import { Document, Indent, Numbering, Packer, Paragraph } from "../build"; + +const doc = new Document(); + +const numbering = new Numbering(); + +const abstractNum = numbering.createAbstractNumbering(); +abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new Indent({ left: 720, hanging: 260 })); + +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); + +doc.addParagraph(item1); +doc.addParagraph(item2); +doc.addParagraph(item3); +doc.addParagraph(item4); + +const packer = new Packer(); + +packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); \ No newline at end of file diff --git a/src/file/paragraph/formatting/spacing.ts b/src/file/paragraph/formatting/spacing.ts index 292864bf53..608a3fe1ab 100644 --- a/src/file/paragraph/formatting/spacing.ts +++ b/src/file/paragraph/formatting/spacing.ts @@ -1,5 +1,5 @@ // http://officeopenxml.com/WPspacing.php -import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; +import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components"; export interface ISpacingProperties { after?: number; @@ -23,3 +23,14 @@ export class Spacing extends XmlComponent { this.root.push(new SpacingAttributes(opts)); } } + +export class ContextualSpacing extends XmlComponent { + constructor(value: boolean) { + super("w:contextualSpacing"); + this.root.push( + new Attributes({ + val: value === false ? 0 : 1, + }), + ); + } +} diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index b7930970b5..8fdfbe2fff 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -10,7 +10,7 @@ import { Border, ThematicBreak } from "./formatting/border"; import { IIndentAttributesProperties, Indent } from "./formatting/indent"; import { KeepLines, KeepNext } from "./formatting/keep"; import { PageBreak, PageBreakBefore } from "./formatting/page-break"; -import { ISpacingProperties, Spacing } from "./formatting/spacing"; +import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing"; import { Style } from "./formatting/style"; import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop"; import { NumberProperties } from "./formatting/unordered-list"; @@ -211,6 +211,11 @@ export class Paragraph extends XmlComponent { 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; From e02ac43c073c6d41ec57d9f5a541b2616ed149c7 Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 10 Oct 2018 20:39:11 +0100 Subject: [PATCH 08/15] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e63dd166bf..9a87375bb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docx", - "version": "4.1.0", + "version": "4.2.0", "description": "Generate .docx documents with JavaScript (formerly Office-Clippy)", "main": "build/index.js", "scripts": { From 9f0b2f707446762b93f63b5b8f5cebf9490ddfcc Mon Sep 17 00:00:00 2001 From: Dolan Date: Mon, 15 Oct 2018 21:54:33 +0100 Subject: [PATCH 09/15] Improve API --- demo/demo29.ts | 26 +++++++++++--------------- src/file/table/table.ts | 27 ++++++++++++--------------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/demo/demo29.ts b/demo/demo29.ts index 10a3318e03..373ca64266 100644 --- a/demo/demo29.ts +++ b/demo/demo29.ts @@ -5,33 +5,29 @@ import { Document, Packer, Paragraph } from "../build"; const doc = new Document(); -doc - .createTable(2, 2) - .getCell(0, 0) - .addContent(new Paragraph("Hello")) - .setHorizontalSpan(2); +let table = doc.createTable(2, 2); + +table.getCell(0, 0).addContent(new Paragraph("Hello")); +table.getRow(0).mergeCells(0, 1); doc.createParagraph("Another table").heading2(); -doc - .createTable(2, 3) - .getCell(0, 0) - .addContent(new Paragraph("World")) - .setHorizontalSpan(3); +table = doc.createTable(2, 3); +table.getCell(0, 0).addContent(new Paragraph("World")); +table.getRow(0).mergeCells(0, 2); doc.createParagraph("Another table").heading2(); -const table = doc.createTable(2, 4); -table - .getCell(0, 0) - .addContent(new Paragraph("Foo")) - .setHorizontalSpan(4); +table = doc.createTable(2, 4); +table.getCell(0, 0).addContent(new Paragraph("Foo")); table.getCell(1, 0).addContent(new Paragraph("Bar1")); table.getCell(1, 1).addContent(new Paragraph("Bar2")); table.getCell(1, 2).addContent(new Paragraph("Bar3")); table.getCell(1, 3).addContent(new Paragraph("Bar4")); +table.getRow(0).mergeCells(0, 3); + const packer = new Packer(); packer.toBuffer(doc).then((buffer) => { diff --git a/src/file/table/table.ts b/src/file/table/table.ts index 2dfc051e22..f6201acedc 100644 --- a/src/file/table/table.ts +++ b/src/file/table/table.ts @@ -52,7 +52,7 @@ export class Table extends XmlComponent { for (let i = 0; i < rows; i++) { const cells: TableCell[] = []; for (let j = 0; j < cols; j++) { - cells.push(new TableCell(this, i, j)); + cells.push(new TableCell()); } const row = new TableRow(cells); this.rows.push(row); @@ -109,14 +109,20 @@ export class TableRow extends XmlComponent { return cell; } - public addGridSpan(ix: number, cellSpan: number): TableCell { - const remainCell = this.cells[ix]; + public addGridSpan(index: number, cellSpan: number): TableCell { + const remainCell = this.cells[index]; remainCell.CellProperties.addGridSpan(cellSpan); - this.cells.splice(ix + 1, cellSpan - 1); - this.root.splice(ix + 2, cellSpan - 1); + this.cells.splice(index + 1, cellSpan - 1); + this.root.splice(index + 2, cellSpan - 1); return remainCell; } + + public mergeCells(startIndex: number, endIndex: number): TableCell { + const cellSpan = endIndex - startIndex + 1; + + return this.addGridSpan(startIndex, cellSpan); + } } export class TableRowProperties extends XmlComponent { @@ -128,7 +134,7 @@ export class TableRowProperties extends XmlComponent { export class TableCell extends XmlComponent { private readonly properties: TableCellProperties; - constructor(private readonly tableReference: Table, private readonly x: number, private readonly y: number) { + constructor() { super("w:tc"); this.properties = new TableCellProperties(); this.root.push(this.properties); @@ -155,15 +161,6 @@ export class TableCell extends XmlComponent { return para; } - public setHorizontalSpan(span: number): TableCell { - for (let i = 1; i < span; i++) { - this.tableReference.getCell(this.x, this.y + i).delete(); - } - this.properties.addGridSpan(span); - - return this; - } - public get CellProperties(): TableCellProperties { return this.properties; } From 8ac19a83b2d55764553ad0a9e944907a75c26a21 Mon Sep 17 00:00:00 2001 From: Dolan Date: Mon, 15 Oct 2018 22:21:40 +0100 Subject: [PATCH 10/15] Rename demos --- demo/{demo28.ts => demo31.ts} | 0 demo/{demo29.ts => demo32.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename demo/{demo28.ts => demo31.ts} (100%) rename demo/{demo29.ts => demo32.ts} (100%) diff --git a/demo/demo28.ts b/demo/demo31.ts similarity index 100% rename from demo/demo28.ts rename to demo/demo31.ts diff --git a/demo/demo29.ts b/demo/demo32.ts similarity index 100% rename from demo/demo29.ts rename to demo/demo32.ts From a4665784670abf7964eb9828bb2e8b48c292c021 Mon Sep 17 00:00:00 2001 From: Dolan Date: Mon, 15 Oct 2018 23:34:35 +0100 Subject: [PATCH 11/15] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9a87375bb2..ee9fa9049a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docx", - "version": "4.2.0", + "version": "4.3.0", "description": "Generate .docx documents with JavaScript (formerly Office-Clippy)", "main": "build/index.js", "scripts": { From 23dee01f063ac517d995d78ed277a1be11b18ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mendon=C3=A7a?= Date: Fri, 19 Oct 2018 16:50:51 -0300 Subject: [PATCH 12/15] Created classes and methods needed to create Sequential Identifiers --- demo/demo33.ts | 22 +++++++ src/file/paragraph/paragraph.ts | 7 ++- src/file/paragraph/run/index.ts | 1 + .../run/sequential-identifier-instruction.ts | 19 ++++++ .../run/sequential-identifier.spec.ts | 60 +++++++++++++++++++ .../paragraph/run/sequential-identifier.ts | 13 ++++ 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 demo/demo33.ts create mode 100644 src/file/paragraph/run/sequential-identifier-instruction.ts create mode 100644 src/file/paragraph/run/sequential-identifier.spec.ts create mode 100644 src/file/paragraph/run/sequential-identifier.ts diff --git a/demo/demo33.ts b/demo/demo33.ts new file mode 100644 index 0000000000..c6efe2ed0f --- /dev/null +++ b/demo/demo33.ts @@ -0,0 +1,22 @@ +// Sequential Captions +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer, Paragraph, TextRun } from "../build"; + +const doc = new Document(); + +const paragraph = new Paragraph("Hello World 1->").addSequentialIdentifier("Caption").addRun(new TextRun(" text after sequencial caption 2->")).addSequentialIdentifier("Caption"); +const paragraph2 = new Paragraph("Hello World 1->").addSequentialIdentifier("Label").addRun(new TextRun(" text after sequencial caption 2->")).addSequentialIdentifier("Label"); +const paragraph3 = new Paragraph("Hello World 1->").addSequentialIdentifier("Another").addRun(new TextRun(" text after sequencial caption 3->")).addSequentialIdentifier("Label"); +const paragraph4 = new Paragraph("Hello World 2->").addSequentialIdentifier("Another").addRun(new TextRun(" text after sequencial caption 4->")).addSequentialIdentifier("Label"); + +doc.addParagraph(paragraph); +doc.addParagraph(paragraph2); +doc.addParagraph(paragraph3); +doc.addParagraph(paragraph4); + +const packer = new Packer(); + +packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/src/file/paragraph/paragraph.ts b/src/file/paragraph/paragraph.ts index 8fdfbe2fff..263064d2fa 100644 --- a/src/file/paragraph/paragraph.ts +++ b/src/file/paragraph/paragraph.ts @@ -16,7 +16,7 @@ import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } import { NumberProperties } from "./formatting/unordered-list"; import { Bookmark, Hyperlink } from "./links"; import { ParagraphProperties } from "./properties"; -import { PictureRun, Run, TextRun } from "./run"; +import { PictureRun, Run, SequentialIdentifier, TextRun } from "./run"; export class Paragraph extends XmlComponent { private readonly properties: ParagraphProperties; @@ -245,4 +245,9 @@ export class Paragraph extends XmlComponent { this.root.splice(1, 0, run); return this; } + + public addSequentialIdentifier(identifier: string): Paragraph { + this.root.push(new SequentialIdentifier(identifier)); + return this; + } } diff --git a/src/file/paragraph/run/index.ts b/src/file/paragraph/run/index.ts index 6ac823e9bb..a30a1d6037 100644 --- a/src/file/paragraph/run/index.ts +++ b/src/file/paragraph/run/index.ts @@ -1,3 +1,4 @@ export * from "./run"; export * from "./text-run"; export * from "./picture-run"; +export * from "./sequential-identifier"; diff --git a/src/file/paragraph/run/sequential-identifier-instruction.ts b/src/file/paragraph/run/sequential-identifier-instruction.ts new file mode 100644 index 0000000000..6f48738db7 --- /dev/null +++ b/src/file/paragraph/run/sequential-identifier-instruction.ts @@ -0,0 +1,19 @@ +// http://officeopenxml.com/WPfieldInstructions.php +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +enum SpaceType { + DEFAULT = "default", + PRESERVE = "preserve", +} + +class TextAttributes extends XmlAttributeComponent<{ space: SpaceType }> { + protected xmlKeys = { space: "xml:space" }; +} + +export class SequentialIdentifierInstruction extends XmlComponent { + constructor(identifier: string) { + super("w:instrText"); + this.root.push(new TextAttributes({ space: SpaceType.PRESERVE })); + this.root.push(`SEQ ${identifier}`); + } +} diff --git a/src/file/paragraph/run/sequential-identifier.spec.ts b/src/file/paragraph/run/sequential-identifier.spec.ts new file mode 100644 index 0000000000..1b34997b9c --- /dev/null +++ b/src/file/paragraph/run/sequential-identifier.spec.ts @@ -0,0 +1,60 @@ +import { expect } from "chai"; + +import { Formatter } from "../../../export/formatter"; +import { SequentialIdentifier } from "./sequential-identifier"; + +describe("Sequential Identifier", () => { + describe("#constructor", () => { + it("should construct a SEQ without options", () => { + const seq = new SequentialIdentifier("Figure"); + const tree = new Formatter().format(seq); + expect(tree).to.be.deep.equal(DEFAULT_SEQ); + }); + }); +}); + +const DEFAULT_SEQ = { + "w:r": [ + { + "w:rPr": [], + }, + { + "w:fldChar": [ + { + _attr: { + "w:fldCharType": "begin", + "w:dirty": true, + }, + }, + ], + }, + { + "w:instrText": [ + { + _attr: { + "xml:space": "preserve", + }, + }, + "SEQ Figure", + ], + }, + { + "w:fldChar": [ + { + _attr: { + "w:fldCharType": "separate", + }, + }, + ], + }, + { + "w:fldChar": [ + { + _attr: { + "w:fldCharType": "end", + }, + }, + ], + }, + ], +}; diff --git a/src/file/paragraph/run/sequential-identifier.ts b/src/file/paragraph/run/sequential-identifier.ts new file mode 100644 index 0000000000..5536eca4ae --- /dev/null +++ b/src/file/paragraph/run/sequential-identifier.ts @@ -0,0 +1,13 @@ +import { Run } from "file/paragraph/run"; +import { Begin, End, Separate } from "file/paragraph/run/field"; +import { SequentialIdentifierInstruction } from "./sequential-identifier-instruction"; + +export class SequentialIdentifier extends Run { + constructor(identifier: string) { + super(); + this.root.push(new Begin(true)); + this.root.push(new SequentialIdentifierInstruction(identifier)); + this.root.push(new Separate()); + this.root.push(new End()); + } +} From b6f431e14d5a36ba922232b3260f5b73dda1b65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mendon=C3=A7a?= Date: Sat, 20 Oct 2018 09:17:37 -0300 Subject: [PATCH 13/15] fixed TOC instruction that was missing quotes for some switches --- src/file/table-of-contents/field-instruction.ts | 10 +++++----- src/file/table-of-contents/table-of-contents.spec.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/file/table-of-contents/field-instruction.ts b/src/file/table-of-contents/field-instruction.ts index 766e6fc2f2..7194cf3f16 100644 --- a/src/file/table-of-contents/field-instruction.ts +++ b/src/file/table-of-contents/field-instruction.ts @@ -41,19 +41,19 @@ export class FieldInstruction extends XmlComponent { instruction = `${instruction} \\h`; } if (this.properties.tcFieldLevelRange) { - instruction = `${instruction} \\l "${this.properties.tcFieldLevelRange}`; + instruction = `${instruction} \\l "${this.properties.tcFieldLevelRange}"`; } if (this.properties.pageNumbersEntryLevelsRange) { - instruction = `${instruction} \\n "${this.properties.pageNumbersEntryLevelsRange}`; + instruction = `${instruction} \\n "${this.properties.pageNumbersEntryLevelsRange}"`; } if (this.properties.headingStyleRange) { - instruction = `${instruction} \\o "${this.properties.headingStyleRange}`; + instruction = `${instruction} \\o "${this.properties.headingStyleRange}"`; } if (this.properties.entryAndPageNumberSeparator) { - instruction = `${instruction} \\p "${this.properties.entryAndPageNumberSeparator}`; + instruction = `${instruction} \\p "${this.properties.entryAndPageNumberSeparator}"`; } if (this.properties.seqFieldIdentifierForPrefix) { - instruction = `${instruction} \\s "${this.properties.seqFieldIdentifierForPrefix}`; + instruction = `${instruction} \\s "${this.properties.seqFieldIdentifierForPrefix}"`; } if (this.properties.stylesWithLevels && this.properties.stylesWithLevels.length) { const styles = this.properties.stylesWithLevels.map((sl) => `${sl.styleName},${sl.level}`).join(","); 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 7d7d4a55b6..6729f004ba 100644 --- a/src/file/table-of-contents/table-of-contents.spec.ts +++ b/src/file/table-of-contents/table-of-contents.spec.ts @@ -174,7 +174,7 @@ const COMPLETE_TOC = { "xml:space": "preserve", }, }, - 'TOC \\a "A" \\b "B" \\c "C" \\d "D" \\f "F" \\h \\l "L \\n "N \\o "O \\p "P \\s "S \\t "SL,1,SL,2" \\u \\w \\x \\z', + 'TOC \\a "A" \\b "B" \\c "C" \\d "D" \\f "F" \\h \\l "L" \\n "N" \\o "O" \\p "P" \\s "S" \\t "SL,1,SL,2" \\u \\w \\x \\z', ], }, { From 7e8ebb2af2f608332d94f5c31e1d99e72992d76f Mon Sep 17 00:00:00 2001 From: Dolan Date: Sun, 21 Oct 2018 04:50:57 +0100 Subject: [PATCH 14/15] Contribution guidelines improve --- docs/contribution-guidelines.md | 111 +++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/docs/contribution-guidelines.md b/docs/contribution-guidelines.md index 5d1442fe0c..a212a081c2 100644 --- a/docs/contribution-guidelines.md +++ b/docs/contribution-guidelines.md @@ -1,5 +1,30 @@ # Contribution Guidelines +## Always think about the user + +The number one pillar for contribution is to **ALWAYS** think about how the user will use the library. + +Put yourself in their position, and imagine how they would feel about your feature you wrote. + +1. Is it easy to use? +2. Has it been documented well? +3. Is it intuative? +4. Is it consistent with the rest of the API? +5. Is it fun to use? + +## Good Commit Names + +Please write good commit messages when making a commit: https://chris.beams.io/posts/git-commit/ + +**Do not:** +``` +c // What? +rtl // Adding acryonyms without explaining anything else is not helpful +works! // Glad its working, but the message is not helpful +demo updated // Getting better, but capitalize the first letter +Unesesary coment removed // Make sure to use correct spelling +``` + ## Writing Code * Include documentation reference(s) at the top of each file: @@ -45,18 +70,98 @@ public get Level() { There is no performance advantage by doing this. It means we don't need to prefix all private variables with the ugly `_`: -**Do not:** +**Do not:** ```js private get _level: string; ``` -**Do** +**Do** ```js private get level: string; ``` +## Interfaces over type alias + +Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it. + +> "In general, use what you want ( type alias / interface ) just be consistent" +> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions" +> +> * https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c + +`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types + +**Do not:** + +```js +type RelationshipFileInfo = { id: number, target: string }; +``` + +**Do:** + +```js +interface IRelationshipFileInfo { + id: number; + target: string; +} +``` + +## String enums vs type + +To take full advantage of TypeScript's typing system, its best to use `string enums`: + +**Do not:** + +```js +type WeaponType = "bow" | "sword" | "wand"; +``` + +**Do:** + +```js +enum WeaponType = { + BOW = "bow", + SWORD = "sword", + WAND = "wand", +} +``` + +## Spell correctly, full and in American English + +I am not sure where these habit in software development comes from, but I do not believe it is beneficial: + +**Do not:** +```js +readdy // misspelling +perm // abbreviation +conf // abbreviation +cnty // abbreviation +relationFile // abbreviation +colour // U.K. English +``` + +**Do:** +```js +ready +permission +config +country +relationshipFile +color +``` + +## Keep files small (within reason) + +To minimize merge conflicts, reduce complexity, and improve readability, keep the files small. + +## Name files and folders with `/foo-bar/kebab-case.ts` + +To be consistent and in-line with the project, name files `like-this.ts`. + +https://stackoverflow.com/questions/7273316/what-is-the-javascript-filename-naming-convention + ## Testing Please write a test of every file you make and suffix it with `.spec.ts`. @@ -78,3 +183,5 @@ describe("ClassName", () => { }); }); ``` + +Try not to use the `tests/utility.ts` file as this is being deprecated. From b67a9de0e96837f6a979cf4632e4066b7ffd3479 Mon Sep 17 00:00:00 2001 From: Dolan Date: Sun, 21 Oct 2018 05:14:14 +0100 Subject: [PATCH 15/15] Angular README example --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 020cb78f96..f387c41a14 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,10 @@ Here are examples of `docx` being used with basic `HTML/JS` in a browser environ * https://codepen.io/anon/pen/dqoVgQ * https://jsfiddle.net/3xhezb5w/2 +Here is an example of `docx` working in `Angular`: + +* https://stackblitz.com/edit/angular-afvxtz + ## Node Press `endpoint` on the `RunKit` website: