diff --git a/demo/demo44.ts b/demo/demo44.ts new file mode 100644 index 0000000000..e4553df05e --- /dev/null +++ b/demo/demo44.ts @@ -0,0 +1,26 @@ +// Sections with multiple columns +// Import from 'docx' rather than '../build' if you install from npm +import * as fs from "fs"; +import { Document, Packer} from "../build"; + +const doc = new Document(); + +doc.addSection({ + num: 2, +}); + +doc.createParagraph("This text will be split into 2 columns on a page."); +doc.createParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); + +doc.addSection({ + num: 3, +}); + +doc.createParagraph("This text will be split into 3 columns on a page."); +doc.createParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."); + +const packer = new Packer(); + +packer.toBuffer(doc).then((buffer) => { + fs.writeFileSync("My Document.docx", buffer); +}); diff --git a/src/file/document/body/body.spec.ts b/src/file/document/body/body.spec.ts index 502c10692e..6eb8cdddad 100644 --- a/src/file/document/body/body.spec.ts +++ b/src/file/document/body/body.spec.ts @@ -71,7 +71,7 @@ describe("Body", () => { }, }, }, - { "w:cols": { _attr: { "w:space": 708 } } }, + { "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }, { "w:docGrid": { _attr: { "w:linePitch": 360 } } }, ], }, @@ -96,7 +96,7 @@ describe("Body", () => { }, }, }, - { "w:cols": { _attr: { "w:space": 708 } } }, + { "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }, { "w:docGrid": { _attr: { "w:linePitch": 360 } } }, ], }, diff --git a/src/file/document/body/section-properties/columns/columns-attributes.ts b/src/file/document/body/section-properties/columns/columns-attributes.ts index b5cf098c5a..b5a14315cc 100644 --- a/src/file/document/body/section-properties/columns/columns-attributes.ts +++ b/src/file/document/body/section-properties/columns/columns-attributes.ts @@ -2,10 +2,12 @@ import { XmlAttributeComponent } from "file/xml-components"; export interface IColumnsAttributes { readonly space?: number; + readonly num?: number; } export class ColumnsAttributes extends XmlAttributeComponent { protected readonly xmlKeys = { space: "w:space", + num: "w:num", }; } diff --git a/src/file/document/body/section-properties/columns/columns.ts b/src/file/document/body/section-properties/columns/columns.ts index aa6e144f62..d8c7eef577 100644 --- a/src/file/document/body/section-properties/columns/columns.ts +++ b/src/file/document/body/section-properties/columns/columns.ts @@ -2,11 +2,12 @@ import { XmlComponent } from "file/xml-components"; import { ColumnsAttributes } from "./columns-attributes"; export class Columns extends XmlComponent { - constructor(space: number) { + constructor(space: number, num: number) { super("w:cols"); this.root.push( new ColumnsAttributes({ space: space, + num: num, }), ); } diff --git a/src/file/document/body/section-properties/section-properties.spec.ts b/src/file/document/body/section-properties/section-properties.spec.ts index b545a058c4..5b85f09c97 100644 --- a/src/file/document/body/section-properties/section-properties.spec.ts +++ b/src/file/document/body/section-properties/section-properties.spec.ts @@ -26,6 +26,7 @@ describe("SectionProperties", () => { gutter: 0, mirror: false, space: 708, + num: 1, linePitch: 360, headers: { default: new HeaderWrapper(media, 100), @@ -55,7 +56,7 @@ describe("SectionProperties", () => { }, }); - expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708 } } }); + expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }); expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } }); expect(tree["w:sectPr"][4]).to.deep.equal({ "w:headerReference": { _attr: { "r:id": "rId100", "w:type": "default" } } }); expect(tree["w:sectPr"][5]).to.deep.equal({ "w:footerReference": { _attr: { "r:id": "rId200", "w:type": "even" } } }); @@ -82,7 +83,7 @@ describe("SectionProperties", () => { }, }, }); - expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708 } } }); + expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } }); expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } }); }); diff --git a/src/file/document/body/section-properties/section-properties.ts b/src/file/document/body/section-properties/section-properties.ts index 5a50012578..ee5de8b45a 100644 --- a/src/file/document/body/section-properties/section-properties.ts +++ b/src/file/document/body/section-properties/section-properties.ts @@ -67,6 +67,7 @@ export class SectionProperties extends XmlComponent { gutter = 0, mirror = false, space = 708, + num = 1, linePitch = 360, orientation = PageOrientation.PORTRAIT, headers, @@ -88,7 +89,7 @@ export class SectionProperties extends XmlComponent { this.options = options; this.root.push(new PageSize(width, height, orientation)); this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter, mirror)); - this.root.push(new Columns(space)); + this.root.push(new Columns(space, num)); this.root.push(new DocumentGrid(linePitch)); this.addHeaders(headers); diff --git a/src/file/index.ts b/src/file/index.ts index fc022088d1..199679bee3 100644 --- a/src/file/index.ts +++ b/src/file/index.ts @@ -9,3 +9,5 @@ export * from "./document"; export * from "./styles"; export * from "./table-of-contents"; export * from "./xml-components"; +export * from "./header-wrapper"; +export * from "./footer-wrapper"; diff --git a/src/file/styles/index.ts b/src/file/styles/index.ts index 737bec0771..144bbcb1fd 100644 --- a/src/file/styles/index.ts +++ b/src/file/styles/index.ts @@ -1 +1,3 @@ export * from "./styles"; +export * from "./style/character-style"; +export * from "./style/paragraph-style"; diff --git a/src/file/table/index.ts b/src/file/table/index.ts index 47e0549503..cec3788f8e 100644 --- a/src/file/table/index.ts +++ b/src/file/table/index.ts @@ -2,3 +2,4 @@ export * from "./table"; export * from "./table-cell"; export * from "./table-properties"; export * from "./shading"; +export * from "./table-row"; diff --git a/src/file/table/table-row/index.ts b/src/file/table/table-row/index.ts index c8a880cf50..455c143d9a 100644 --- a/src/file/table/table-row/index.ts +++ b/src/file/table/table-row/index.ts @@ -1,2 +1,3 @@ export * from "./table-row"; export * from "./table-row-properties"; +export * from "./table-row-height"; diff --git a/src/file/table/table-row/table-row-height.ts b/src/file/table/table-row/table-row-height.ts new file mode 100644 index 0000000000..71e2c36aa1 --- /dev/null +++ b/src/file/table/table-row/table-row-height.ts @@ -0,0 +1,32 @@ +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +export enum HeightRule { + /** Height is determined based on the content, so value is ignored. */ + AUTO = "auto", + /** At least the value specified */ + ATLEAST = "atLeast", + /** Exactly the value specified */ + EXACT = "exact", +} + +interface ITableRowHeight { + readonly height: number; + readonly rule: HeightRule; +} + +export class TableRowHeightAttributes extends XmlAttributeComponent { + protected readonly xmlKeys = { height: "w:val", rule: "w:hRule" }; +} + +export class TableRowHeight extends XmlComponent { + constructor(value: number, rule: HeightRule) { + super("w:trHeight"); + + this.root.push( + new TableRowHeightAttributes({ + height: value, + rule: rule, + }), + ); + } +} diff --git a/src/file/table/table-row/table-row-properties.spec.ts b/src/file/table/table-row/table-row-properties.spec.ts index 155238cb88..05092d4178 100644 --- a/src/file/table/table-row/table-row-properties.spec.ts +++ b/src/file/table/table-row/table-row-properties.spec.ts @@ -1,5 +1,6 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; +import { HeightRule } from "file/table/table-row/table-row-height"; import { TableRowProperties } from "./table-row-properties"; describe("TableRowProperties", () => { @@ -31,4 +32,25 @@ describe("TableRowProperties", () => { expect(tree).to.deep.equal({ "w:trPr": [{ "w:tblHeader": { _attr: { "w:val": true } } }] }); }); }); + + describe("#setHeight", () => { + it("sets row height exact", () => { + const rowProperties = new TableRowProperties(); + rowProperties.setHeight(100, HeightRule.EXACT); + const tree = new Formatter().format(rowProperties); + expect(tree).to.deep.equal({ "w:trPr": [{ "w:trHeight": { _attr: { "w:val": 100, "w:hRule": "exact" } } }] }); + }); + it("sets row height auto", () => { + const rowProperties = new TableRowProperties(); + rowProperties.setHeight(100, HeightRule.AUTO); + const tree = new Formatter().format(rowProperties); + expect(tree).to.deep.equal({ "w:trPr": [{ "w:trHeight": { _attr: { "w:val": 100, "w:hRule": "auto" } } }] }); + }); + it("sets row height at least", () => { + const rowProperties = new TableRowProperties(); + rowProperties.setHeight(100, HeightRule.ATLEAST); + const tree = new Formatter().format(rowProperties); + expect(tree).to.deep.equal({ "w:trPr": [{ "w:trHeight": { _attr: { "w:val": 100, "w:hRule": "atLeast" } } }] }); + }); + }); }); diff --git a/src/file/table/table-row/table-row-properties.ts b/src/file/table/table-row/table-row-properties.ts index ed8332cc84..c9b60c13f4 100644 --- a/src/file/table/table-row/table-row-properties.ts +++ b/src/file/table/table-row/table-row-properties.ts @@ -1,3 +1,4 @@ +import { HeightRule, TableRowHeight } from "file/table/table-row/table-row-height"; import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent, XmlComponent } from "file/xml-components"; export class TableRowProperties extends IgnoreIfEmptyXmlComponent { @@ -16,6 +17,12 @@ export class TableRowProperties extends IgnoreIfEmptyXmlComponent { return this; } + + public setHeight(height: number, rule: HeightRule): TableRowProperties { + this.root.push(new TableRowHeight(height, rule)); + + return this; + } } class CantSplitAttributes extends XmlAttributeComponent<{ readonly val: boolean }> { diff --git a/src/file/table/table-row/table-row.spec.ts b/src/file/table/table-row/table-row.spec.ts index 73b996cac2..3e9a479949 100644 --- a/src/file/table/table-row/table-row.spec.ts +++ b/src/file/table/table-row/table-row.spec.ts @@ -2,11 +2,11 @@ import { expect } from "chai"; import { Formatter } from "export/formatter"; +import { HeightRule } from "file/table/table-row/table-row-height"; +import { EMPTY_OBJECT } from "file/xml-components"; import { TableCell } from "../table-cell"; import { TableRow } from "./table-row"; -import { EMPTY_OBJECT } from "file/xml-components"; - describe("TableRow", () => { describe("#constructor", () => { it("should create with no cells", () => { @@ -67,4 +67,28 @@ describe("TableRow", () => { expect(() => tableRow.getCell(1)).to.throw(); }); }); + + describe("#setHeight", () => { + it("should set row height", () => { + const tableRow = new TableRow([]); + tableRow.setHeight(100, HeightRule.EXACT); + const tree = new Formatter().format(tableRow); + expect(tree).to.deep.equal({ + "w:tr": [ + { + "w:trPr": [ + { + "w:trHeight": { + _attr: { + "w:hRule": "exact", + "w:val": 100, + }, + }, + }, + ], + }, + ], + }); + }); + }); }); diff --git a/src/file/table/table-row/table-row.ts b/src/file/table/table-row/table-row.ts index 6e091abffd..f811392348 100644 --- a/src/file/table/table-row/table-row.ts +++ b/src/file/table/table-row/table-row.ts @@ -1,5 +1,5 @@ +import { HeightRule } from "file/table/table-row/table-row-height"; import { XmlComponent } from "file/xml-components"; - import { TableCell } from "../table-cell"; import { TableRowProperties } from "./table-row-properties"; @@ -49,4 +49,10 @@ export class TableRow extends XmlComponent { return this; } + + public setHeight(height: number, rule: HeightRule): TableRow { + this.properties.setHeight(height, rule); + + return this; + } }