diff --git a/demo/11-declaritive-styles-2.ts b/demo/11-declaritive-styles-2.ts index bb6428d518..c6780c440f 100644 --- a/demo/11-declaritive-styles-2.ts +++ b/demo/11-declaritive-styles-2.ts @@ -1,7 +1,7 @@ // Setting styles with JavaScript configuration // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { AlignmentType, Document, Footer, HeadingLevel, Media, Packer, Paragraph, Table } from "../build"; +import { AlignmentType, Document, Footer, HeadingLevel, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); @@ -81,13 +81,37 @@ doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph") const image = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif")); const table = new Table({ - rows: 4, - columns: 4, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Test cell 1.")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Test cell 2.")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Test cell 3.")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Test cell 4.")], + }), + ], + }), + ], }); -table - .getRow(0) - .getCell(0) - .add(new Paragraph("Pole No.")); const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif")); const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif")); diff --git a/demo/20-table-cell-borders.ts b/demo/20-table-cell-borders.ts index 13809a6164..028d9fdb04 100644 --- a/demo/20-table-cell-borders.ts +++ b/demo/20-table-cell-borders.ts @@ -1,23 +1,102 @@ // Add custom borders to table cell // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { BorderStyle, Document, Packer, Paragraph, Table } from "../build"; +import { BorderStyle, Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); const table = new Table({ - rows: 4, - columns: 4, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph("Hello")], + borders: { + top: { + style: BorderStyle.DASH_DOT_STROKED, + size: 3, + color: "red", + }, + bottom: { + style: BorderStyle.DOUBLE, + size: 3, + color: "blue", + }, + left: { + style: BorderStyle.DASH_DOT_STROKED, + size: 3, + color: "green", + }, + right: { + style: BorderStyle.DASH_DOT_STROKED, + size: 3, + color: "#ff8000", + }, + }, + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], }); doc.addSection({ children: [table] }); -table - .getCell(2, 2) - .add(new Paragraph("Hello")) - .Borders.addTopBorder(BorderStyle.DASH_DOT_STROKED, 3, "red") - .addBottomBorder(BorderStyle.DOUBLE, 3, "blue") - .addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green") - .addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000"); Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); diff --git a/demo/24-images-to-table-cell.ts b/demo/24-images-to-table-cell.ts index 114be5491e..e37d1aa812 100644 --- a/demo/24-images-to-table-cell.ts +++ b/demo/24-images-to-table-cell.ts @@ -1,24 +1,85 @@ // Add image to table cell // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Media, Packer, Paragraph, Table } from "../build"; +import { Document, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); +const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg")); + const table = new Table({ - rows: 4, - columns: 4, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph(image)], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph("Hello")], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], }); doc.addSection({ children: [table], }); -table.getCell(2, 2).add(new Paragraph("Hello")); - -const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg")); -table.getCell(1, 1).add(new Paragraph(image)); - Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); }); diff --git a/demo/31-tables.ts b/demo/31-tables.ts index 050403bb99..7daec1506d 100644 --- a/demo/31-tables.ts +++ b/demo/31-tables.ts @@ -1,28 +1,48 @@ // 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, HeadingLevel, Packer, Paragraph, Table, VerticalAlign } from "../build"; +import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "../build"; const doc = new Document(); const table = new Table({ - rows: 2, - columns: 2, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph({}), new Paragraph({})], + verticalAlign: VerticalAlign.CENTER, + }), + new TableCell({ + children: [new Paragraph({}), new Paragraph({})], + verticalAlign: VerticalAlign.CENTER, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [ + 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, + }), + ], + }), + new TableCell({ + children: [ + new Paragraph({ + text: "This text should be in the middle of the cell", + }), + ], + verticalAlign: VerticalAlign.CENTER, + }), + ], + }), + ], }); -table - .getCell(1, 1) - .add(new Paragraph("This text should be in the middle of the cell")) - .setVerticalAlign(VerticalAlign.CENTER); - -table.getCell(1, 0).add( - 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, - }), -); - doc.addSection({ children: [table], }); diff --git a/demo/32-merge-table-cells.ts b/demo/32-merge-table-cells.ts index cd850067e5..55a9181281 100644 --- a/demo/32-merge-table-cells.ts +++ b/demo/32-merge-table-cells.ts @@ -1,40 +1,118 @@ // Example of how you would merge cells together // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, WidthType } from "../build"; +import { Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, TableCell, TableRow, WidthType } from "../build"; const doc = new Document(); const table = new Table({ - rows: 2, - columns: 2, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Hello")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], }); -table.getCell(0, 0).add(new Paragraph("Hello")); -table.getRow(0).mergeCells(0, 1); - const table2 = new Table({ - rows: 2, - columns: 3, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("World")], + margins: { + top: 1000, + bottom: 1000, + left: 1000, + right: 1000, + }, + columnSpan: 3, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], width: 100, widthUnitType: WidthType.AUTO, columnWidths: [1000, 1000, 1000], }); -table2 - .getCell(0, 0) - .add(new Paragraph("World")) - .setMargins({ - top: 1000, - bottom: 1000, - left: 1000, - right: 1000, - }); -table.getRow(0).mergeCells(0, 2); - const table3 = new Table({ - rows: 2, - columns: 4, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Foo")], + }), + new TableCell({ + children: [new Paragraph("v")], + columnSpan: 3, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Bar1")], + shading: { + fill: "b79c2f", + val: ShadingType.REVERSE_DIAGONAL_STRIPE, + color: "auto", + }, + }), + new TableCell({ + children: [new Paragraph("Bar2")], + shading: { + fill: "42c5f4", + val: ShadingType.PERCENT_95, + color: "auto", + }, + }), + new TableCell({ + children: [new Paragraph("Bar3")], + shading: { + fill: "880aa8", + val: ShadingType.PERCENT_10, + color: "e2df0b", + }, + }), + new TableCell({ + children: [new Paragraph("Bar4")], + shading: { + fill: "FF0000", + val: ShadingType.CLEAR, + color: "auto", + }, + }), + ], + }), + ], width: 7000, widthUnitType: WidthType.DXA, margins: { @@ -45,47 +123,29 @@ const table3 = new Table({ }, }); -table3.getCell(0, 0).add(new Paragraph("Foo")); -table3.getCell(0, 1).add(new Paragraph("v")); - -table3 - .getCell(1, 0) - .add(new Paragraph("Bar1")) - .setShading({ - fill: "b79c2f", - val: ShadingType.REVERSE_DIAGONAL_STRIPE, - color: "auto", - }); -table3 - .getCell(1, 1) - .add(new Paragraph("Bar2")) - .setShading({ - fill: "42c5f4", - val: ShadingType.PERCENT_95, - color: "auto", - }); -table3 - .getCell(1, 2) - .add(new Paragraph("Bar3")) - .setShading({ - fill: "880aa8", - val: ShadingType.PERCENT_10, - color: "e2df0b", - }); -table3 - .getCell(1, 3) - .add(new Paragraph("Bar4")) - .setShading({ - fill: "FF0000", - val: ShadingType.CLEAR, - color: "auto", - }); - -table3.getRow(0).mergeCells(0, 3); - const table4 = new Table({ - rows: 2, - columns: 2, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], width: 100, widthUnitType: WidthType.PERCENTAGE, }); diff --git a/demo/34-floating-tables.ts b/demo/34-floating-tables.ts index c5b8a18cf8..4a20ae2eee 100644 --- a/demo/34-floating-tables.ts +++ b/demo/34-floating-tables.ts @@ -9,15 +9,35 @@ import { RelativeVerticalPosition, Table, TableAnchorType, + TableCell, TableLayoutType, + TableRow, WidthType, } from "../build"; const doc = new Document(); const table = new Table({ - rows: 2, - columns: 2, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Hello")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], float: { horizontalAnchor: TableAnchorType.MARGIN, verticalAnchor: TableAnchorType.MARGIN, @@ -29,9 +49,6 @@ const table = new Table({ layout: TableLayoutType.FIXED, }); -table.getCell(0, 0).add(new Paragraph("Hello")); -table.getRow(0).mergeCells(0, 1); - doc.addSection({ children: [table], }); diff --git a/demo/36-image-to-table-cell.ts b/demo/36-image-to-table-cell.ts index 1c7897c558..a0d87230a2 100644 --- a/demo/36-image-to-table-cell.ts +++ b/demo/36-image-to-table-cell.ts @@ -1,16 +1,61 @@ -// Add image to table cell +// Add image to table cell in a header and body // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Header, Media, Packer, Paragraph, Table } from "../build"; +import { Document, Header, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg")); const table = new Table({ - rows: 2, - columns: 2, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph(image)], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], }); -table.getCell(1, 1).add(new Paragraph(image)); // Adding same table in the body and in the header doc.addSection({ diff --git a/demo/4-basic-table.ts b/demo/4-basic-table.ts index 78367caab9..593fe821a5 100644 --- a/demo/4-basic-table.ts +++ b/demo/4-basic-table.ts @@ -1,17 +1,35 @@ // 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, Table } from "../build"; +import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); const table = new Table({ - rows: 4, - columns: 4, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("Hello")], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph("World")], + }), + ], + }), + ], }); -table.getCell(2, 2).add(new Paragraph("Hello")); - doc.addSection({ children: [table], }); diff --git a/demo/41-merge-table-cells-2.ts b/demo/41-merge-table-cells-2.ts index 1801eb4a6e..50141a1a7a 100644 --- a/demo/41-merge-table-cells-2.ts +++ b/demo/41-merge-table-cells-2.ts @@ -1,50 +1,122 @@ // Multiple cells merging in the same table // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph, Table } from "../build"; +import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); const table = new Table({ - rows: 13, - columns: 6, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("0,0")], + }), + new TableCell({ + children: [new Paragraph("0,1")], + columnSpan: 2, + }), + new TableCell({ + children: [new Paragraph("0,3")], + }), + new TableCell({ + children: [new Paragraph("0,4")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("1,0")], + columnSpan: 2, + }), + new TableCell({ + children: [new Paragraph("1,2")], + columnSpan: 2, + }), + new TableCell({ + children: [new Paragraph("1,4")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("2,0")], + }), + new TableCell({ + children: [new Paragraph("2,1")], + columnSpan: 2, + }), + new TableCell({ + children: [new Paragraph("2,3")], + }), + new TableCell({ + children: [new Paragraph("2,4")], + columnSpan: 2, + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("3,0")], + }), + new TableCell({ + children: [new Paragraph("3,1")], + }), + new TableCell({ + children: [new Paragraph("3,2")], + }), + new TableCell({ + children: [new Paragraph("3,3")], + }), + new TableCell({ + children: [new Paragraph("3,4")], + }), + new TableCell({ + children: [new Paragraph("3,5")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("4,0")], + columnSpan: 5, + }), + new TableCell({ + children: [new Paragraph("4,5")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], }); -let row = 0; -table.getCell(row, 0).add(new Paragraph("0,0")); -table.getCell(row, 1).add(new Paragraph("0,1")); -table.getCell(row, 3).add(new Paragraph("0,3")); -table.getCell(row, 4).add(new Paragraph("0,4")); -table.getRow(row).mergeCells(4, 5); -table.getRow(row).mergeCells(1, 2); -row = 1; -table.getCell(row, 0).add(new Paragraph("1,0")); -table.getCell(row, 2).add(new Paragraph("1,2")); -table.getCell(row, 4).add(new Paragraph("1,4")); -table.getRow(row).mergeCells(4, 5); -table.getRow(row).mergeCells(2, 3); -table.getRow(row).mergeCells(0, 1); - -row = 2; -table.getCell(row, 0).add(new Paragraph("2,0")); -table.getCell(row, 1).add(new Paragraph("2,1")); -table.getCell(row, 2).add(new Paragraph("2,2")); -table.getCell(row, 3).add(new Paragraph("2,3")); -table.getCell(row, 4).add(new Paragraph("2,4")); -table.getRow(row).mergeCells(4, 5); -table.getRow(row).mergeCells(1, 2); -row = 3; -table.getCell(row, 0).add(new Paragraph("3,0")); -table.getCell(row, 1).add(new Paragraph("3,1")); -table.getCell(row, 2).add(new Paragraph("3,2")); -table.getCell(row, 3).add(new Paragraph("3,3")); -table.getCell(row, 4).add(new Paragraph("3,4")); -table.getCell(row, 5).add(new Paragraph("3,5")); -row = 4; -table.getCell(row, 0).add(new Paragraph("4,0")); -table.getCell(row, 5).add(new Paragraph("4,5")); -table.getRow(row).mergeCells(0, 4); - doc.addSection({ children: [table], }); diff --git a/demo/43-images-to-table-cell-2.ts b/demo/43-images-to-table-cell-2.ts index 90d6322bb7..1840c9382c 100644 --- a/demo/43-images-to-table-cell-2.ts +++ b/demo/43-images-to-table-cell-2.ts @@ -1,16 +1,79 @@ // Add image to table cell // Import from 'docx' rather than '../build' if you install from npm import * as fs from "fs"; -import { Document, Packer, Paragraph, Table } from "../build"; +import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build"; const doc = new Document(); const table = new Table({ - rows: 4, - columns: 4, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [new Paragraph("Hello")], + }), + new TableCell({ + children: [], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ], + }), + ], }); -table.getCell(2, 2).add(new Paragraph("Hello")); table.getColumn(3).mergeCells(1, 2); doc.addSection({ diff --git a/src/file/file.spec.ts b/src/file/file.spec.ts index e8c081d1ec..59b42e009c 100644 --- a/src/file/file.spec.ts +++ b/src/file/file.spec.ts @@ -6,7 +6,7 @@ import { Formatter } from "export/formatter"; import { File } from "./file"; import { Footer, Header } from "./header"; import { Paragraph } from "./paragraph"; -import { Table } from "./table"; +import { Table, TableCell, TableRow } from "./table"; import { TableOfContents } from "./table-of-contents"; describe("File", () => { @@ -108,8 +108,15 @@ describe("File", () => { file.addSection({ children: [ new Table({ - rows: 1, - columns: 1, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], }), ], }); diff --git a/src/file/footer-wrapper.spec.ts b/src/file/footer-wrapper.spec.ts index 3f6fb01b82..899bd22e70 100644 --- a/src/file/footer-wrapper.spec.ts +++ b/src/file/footer-wrapper.spec.ts @@ -4,7 +4,7 @@ import * as sinon from "sinon"; import { FooterWrapper } from "./footer-wrapper"; import { Media } from "./media"; import { Paragraph } from "./paragraph"; -import { Table } from "./table"; +import { Table, TableCell, TableRow } from "./table"; describe("FooterWrapper", () => { describe("#add", () => { @@ -21,8 +21,15 @@ describe("FooterWrapper", () => { const spy = sinon.spy(file.Footer, "add"); file.add( new Table({ - rows: 1, - columns: 1, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], }), ); diff --git a/src/file/header-wrapper.spec.ts b/src/file/header-wrapper.spec.ts index d07473f03a..7c3073a094 100644 --- a/src/file/header-wrapper.spec.ts +++ b/src/file/header-wrapper.spec.ts @@ -4,7 +4,7 @@ import * as sinon from "sinon"; import { HeaderWrapper } from "./header-wrapper"; import { Media } from "./media"; import { Paragraph } from "./paragraph"; -import { Table } from "./table"; +import { Table, TableCell, TableRow } from "./table"; describe("HeaderWrapper", () => { describe("#add", () => { @@ -21,8 +21,15 @@ describe("HeaderWrapper", () => { const spy = sinon.spy(wrapper.Header, "add"); wrapper.add( new Table({ - rows: 1, - columns: 1, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], }), ); diff --git a/src/file/table/grid.ts b/src/file/table/grid.ts index b91f6ac9d4..5ce6486fcc 100644 --- a/src/file/table/grid.ts +++ b/src/file/table/grid.ts @@ -2,9 +2,11 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; export class TableGrid extends XmlComponent { - constructor(cols: number[]) { + constructor(widths: number[]) { super("w:tblGrid"); - cols.forEach((col) => this.root.push(new GridCol(col))); + for (const width of widths) { + this.root.push(new GridCol(width)); + } } } diff --git a/src/file/table/table-cell/table-cell.ts b/src/file/table/table-cell/table-cell.ts index 1c546ab934..05416b34d5 100644 --- a/src/file/table/table-cell/table-cell.ts +++ b/src/file/table/table-cell/table-cell.ts @@ -1,77 +1,107 @@ // http://officeopenxml.com/WPtableGrid.php import { Paragraph } from "file/paragraph"; +import { BorderStyle } from "file/styles"; import { IXmlableObject, XmlComponent } from "file/xml-components"; import { ITableShadingAttributesProperties } from "../shading"; import { Table } from "../table"; import { ITableCellMarginOptions } from "./cell-margin/table-cell-margins"; -import { TableCellBorders, VerticalAlign, VMergeType } from "./table-cell-components"; +import { VerticalAlign, VMergeType } from "./table-cell-components"; import { TableCellProperties } from "./table-cell-properties"; export interface ITableCellOptions { readonly shading?: ITableShadingAttributesProperties; + readonly margins?: ITableCellMarginOptions; + readonly verticalAlign?: VerticalAlign; + readonly verticalMerge?: VMergeType; + readonly columnSpan?: number; + readonly borders?: { + readonly top?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly bottom?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly left?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + readonly right?: { + readonly style: BorderStyle; + readonly size: number; + readonly color: string; + }; + }; + readonly children: Array; } export class TableCell extends XmlComponent { private readonly properties: TableCellProperties; - constructor() { + constructor(readonly options: ITableCellOptions) { super("w:tc"); this.properties = new TableCellProperties(); this.root.push(this.properties); - } - public add(item: Paragraph | Table): TableCell { - this.root.push(item); + for (const child of options.children) { + this.root.push(child); + } - return this; + if (options.verticalAlign) { + this.properties.setVerticalAlign(options.verticalAlign); + } + + if (options.verticalMerge) { + this.properties.addVerticalMerge(options.verticalMerge); + } + + if (options.margins) { + this.properties.addMargins(options.margins); + } + + if (options.shading) { + this.properties.setShading(options.shading); + } + + if (options.columnSpan) { + this.properties.addGridSpan(options.columnSpan); + } + + if (options.borders) { + if (options.borders.top) { + this.properties.Borders.addTopBorder(options.borders.top.style, options.borders.top.size, options.borders.top.color); + } + if (options.borders.bottom) { + this.properties.Borders.addBottomBorder( + options.borders.bottom.style, + options.borders.bottom.size, + options.borders.bottom.color, + ); + } + if (options.borders.left) { + this.properties.Borders.addLeftBorder(options.borders.left.style, options.borders.left.size, options.borders.left.color); + } + if (options.borders.right) { + this.properties.Borders.addRightBorder( + options.borders.right.style, + options.borders.right.size, + options.borders.right.color, + ); + } + } } public prepForXml(): IXmlableObject | undefined { // Cells must end with a paragraph if (!(this.root[this.root.length - 1] instanceof Paragraph)) { - const para = new Paragraph({}); - this.add(para); + this.root.push(new Paragraph({})); } return super.prepForXml(); } - - public setVerticalAlign(type: VerticalAlign): TableCell { - this.properties.setVerticalAlign(type); - - return this; - } - - public addGridSpan(cellSpan: number): TableCell { - this.properties.addGridSpan(cellSpan); - - return this; - } - - public addVerticalMerge(type: VMergeType): TableCell { - this.properties.addVerticalMerge(type); - - return this; - } - - public setMargins(margins: ITableCellMarginOptions): TableCell { - this.properties.addMargins(margins); - - return this; - } - - public setShading(attrs: ITableShadingAttributesProperties): TableCell { - this.properties.setShading(attrs); - - return this; - } - - public get Borders(): TableCellBorders { - return this.properties.Borders; - } - - public get Properties(): TableCellProperties { - return this.properties; - } } diff --git a/src/file/table/table-column.spec.ts b/src/file/table/table-column.spec.ts index aa031423a3..50e9cb8aa4 100644 --- a/src/file/table/table-column.spec.ts +++ b/src/file/table/table-column.spec.ts @@ -1,16 +1,25 @@ import { expect } from "chai"; -import { Formatter } from "export/formatter"; +// import { Formatter } from "export/formatter"; +// import { EMPTY_OBJECT } from "file/xml-components"; import { TableCell } from "./table-cell"; import { TableColumn } from "./table-column"; -import { EMPTY_OBJECT } from "file/xml-components"; - describe("TableColumn", () => { let cells: TableCell[]; beforeEach(() => { - cells = [new TableCell(), new TableCell(), new TableCell()]; + cells = [ + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + new TableCell({ + children: [], + }), + ]; }); describe("#getCell", () => { @@ -32,25 +41,25 @@ describe("TableColumn", () => { }); }); - describe("#mergeCells", () => { - it("should add vMerge to correct cells", () => { - const tableColumn = new TableColumn(cells); - tableColumn.mergeCells(0, 2); + // describe("#mergeCells", () => { + // it("should add vMerge to correct cells", () => { + // const tableColumn = new TableColumn(cells); + // tableColumn.mergeCells(0, 2); - const tree = new Formatter().format(cells[0]); - expect(tree).to.deep.equal({ - "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, { "w:p": EMPTY_OBJECT }], - }); + // const tree = new Formatter().format(cells[0]); + // expect(tree).to.deep.equal({ + // "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, { "w:p": EMPTY_OBJECT }], + // }); - const tree2 = new Formatter().format(cells[1]); - expect(tree2).to.deep.equal({ - "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }], - }); + // const tree2 = new Formatter().format(cells[1]); + // expect(tree2).to.deep.equal({ + // "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }], + // }); - const tree3 = new Formatter().format(cells[2]); - expect(tree3).to.deep.equal({ - "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }], - }); - }); - }); + // const tree3 = new Formatter().format(cells[2]); + // expect(tree3).to.deep.equal({ + // "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }], + // }); + // }); + // }); }); diff --git a/src/file/table/table-column.ts b/src/file/table/table-column.ts index 5752bde472..fc8c2cc240 100644 --- a/src/file/table/table-column.ts +++ b/src/file/table/table-column.ts @@ -1,4 +1,4 @@ -import { TableCell, VMergeType } from "./table-cell"; +import { TableCell } from "./table-cell"; export class TableColumn { constructor(private readonly cells: TableCell[]) {} @@ -13,13 +13,13 @@ export class TableColumn { return cell; } - public mergeCells(startIndex: number, endIndex: number): TableCell { - this.cells[startIndex].addVerticalMerge(VMergeType.RESTART); + // public mergeCells(startIndex: number, endIndex: number): TableCell { + // this.cells[startIndex].addVerticalMerge(VMergeType.RESTART); - for (let i = startIndex + 1; i <= endIndex; i++) { - this.cells[i].addVerticalMerge(VMergeType.CONTINUE); - } + // for (let i = startIndex + 1; i <= endIndex; i++) { + // this.cells[i].addVerticalMerge(VMergeType.CONTINUE); + // } - return this.cells[startIndex]; - } + // return this.cells[startIndex]; + // } } diff --git a/src/file/table/table-row/table-row.spec.ts b/src/file/table/table-row/table-row.spec.ts index 3e9a479949..3c732c6217 100644 --- a/src/file/table/table-row/table-row.spec.ts +++ b/src/file/table/table-row/table-row.spec.ts @@ -10,7 +10,9 @@ import { TableRow } from "./table-row"; describe("TableRow", () => { describe("#constructor", () => { it("should create with no cells", () => { - const tableRow = new TableRow([]); + const tableRow = new TableRow({ + children: [], + }); const tree = new Formatter().format(tableRow); expect(tree).to.deep.equal({ "w:tr": EMPTY_OBJECT, @@ -18,7 +20,13 @@ describe("TableRow", () => { }); it("should create with one cell", () => { - const tableRow = new TableRow([new TableCell()]); + const tableRow = new TableRow({ + children: [ + new TableCell({ + children: [], + }), + ], + }); const tree = new Formatter().format(tableRow); expect(tree).to.deep.equal({ "w:tr": [ @@ -32,46 +40,15 @@ describe("TableRow", () => { ], }); }); - }); - describe("#getCell", () => { - it("should get the cell", () => { - const cell = new TableCell(); - const tableRow = new TableRow([cell]); - - expect(tableRow.getCell(0)).to.equal(cell); - }); - - it("should throw an error if index is out of bounds", () => { - const cell = new TableCell(); - const tableRow = new TableRow([cell]); - - expect(() => tableRow.getCell(1)).to.throw(); - }); - }); - - describe("#addGridSpan", () => { - it("should merge the cell", () => { - const tableRow = new TableRow([new TableCell(), new TableCell()]); - - tableRow.addGridSpan(0, 2); - expect(() => tableRow.getCell(1)).to.throw(); - }); - }); - - describe("#mergeCells", () => { - it("should merge the cell", () => { - const tableRow = new TableRow([new TableCell(), new TableCell()]); - - tableRow.mergeCells(0, 1); - expect(() => tableRow.getCell(1)).to.throw(); - }); - }); - - describe("#setHeight", () => { it("should set row height", () => { - const tableRow = new TableRow([]); - tableRow.setHeight(100, HeightRule.EXACT); + const tableRow = new TableRow({ + children: [], + height: { + height: 100, + rule: HeightRule.EXACT, + }, + }); const tree = new Formatter().format(tableRow); expect(tree).to.deep.equal({ "w:tr": [ @@ -91,4 +68,22 @@ describe("TableRow", () => { }); }); }); + + // describe("#mergeCells", () => { + // it("should merge the cell", () => { + // const tableRow = new TableRow({ + // children: [ + // new TableCell({ + // children: [], + // }), + // new TableCell({ + // children: [], + // }), + // ], + // }); + + // tableRow.mergeCells(0, 1); + // expect(() => tableRow.getCell(1)).to.throw(); + // }); + // }); }); diff --git a/src/file/table/table-row/table-row.ts b/src/file/table/table-row/table-row.ts index f811392348..df47bf70bf 100644 --- a/src/file/table/table-row/table-row.ts +++ b/src/file/table/table-row/table-row.ts @@ -3,56 +3,57 @@ import { XmlComponent } from "file/xml-components"; import { TableCell } from "../table-cell"; import { TableRowProperties } from "./table-row-properties"; +export interface ITableRowOptions { + readonly cantSplit?: boolean; + readonly tableHeader?: boolean; + readonly height?: { + readonly height: number; + readonly rule: HeightRule; + }; + readonly children: TableCell[]; +} + export class TableRow extends XmlComponent { private readonly properties: TableRowProperties; - constructor(private readonly cells: TableCell[]) { + constructor(private readonly options: ITableRowOptions) { super("w:tr"); this.properties = new TableRowProperties(); this.root.push(this.properties); - cells.forEach((c) => this.root.push(c)); - } - public getCell(index: number): TableCell { - const cell = this.cells[index]; - - if (!cell) { - throw Error("Index out of bounds when trying to get cell on row"); + for (const child of options.children) { + this.root.push(child); } - return cell; + if (options.cantSplit) { + this.properties.setCantSplit(); + } + + if (options.tableHeader) { + this.properties.setTableHeader(); + } + + if (options.height) { + this.properties.setHeight(options.height.height, options.height.rule); + } } - public addGridSpan(index: number, cellSpan: number): TableCell { - const remainCell = this.cells[index]; - remainCell.addGridSpan(cellSpan); - this.cells.splice(index + 1, cellSpan - 1); - this.root.splice(index + 2, cellSpan - 1); - - return remainCell; + public get CellCount(): number { + return this.options.children.length; } - public mergeCells(startIndex: number, endIndex: number): TableCell { - const cellSpan = endIndex - startIndex + 1; + // public mergeCells(startIndex: number, endIndex: number): TableCell { + // const cellSpan = endIndex - startIndex + 1; - return this.addGridSpan(startIndex, cellSpan); - } + // return this.addGridSpan(startIndex, cellSpan); + // } - public setCantSplit(): TableRow { - this.properties.setCantSplit(); + // private addGridSpan(index: number, cellSpan: number): TableCell { + // const remainCell = this.options.children[index]; + // remainCell.addGridSpan(cellSpan); + // this.options.children.splice(index + 1, cellSpan - 1); + // this.root.splice(index + 2, cellSpan - 1); - return this; - } - - public setTableHeader(): TableRow { - this.properties.setTableHeader(); - - return this; - } - - public setHeight(height: number, rule: HeightRule): TableRow { - this.properties.setHeight(height, rule); - - return this; - } + // return remainCell; + // } } diff --git a/src/file/table/table.spec.ts b/src/file/table/table.spec.ts index 7c93c5fc8e..efbf2ebb24 100644 --- a/src/file/table/table.spec.ts +++ b/src/file/table/table.spec.ts @@ -9,7 +9,9 @@ import { Table } from "./table"; import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties"; import { EMPTY_OBJECT } from "file/xml-components"; +import { TableCell } from "./table-cell"; import { TableLayoutType } from "./table-properties/table-layout"; +import { TableRow } from "./table-row"; const DEFAULT_TABLE_PROPERTIES = { "w:tblCellMar": [ @@ -118,8 +120,38 @@ describe("Table", () => { describe("#constructor", () => { it("creates a table with the correct number of rows and columns", () => { const table = new Table({ - rows: 3, - columns: 2, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], }); const tree = new Formatter().format(table); const cell = { "w:tc": [{ "w:p": EMPTY_OBJECT }] }; @@ -138,8 +170,15 @@ describe("Table", () => { it("sets the table to fixed width layout", () => { const table = new Table({ - rows: 1, - columns: 1, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], layout: TableLayoutType.FIXED, }); const tree = new Formatter().format(table); @@ -153,128 +192,19 @@ describe("Table", () => { }); }); - describe("#getRow and Row#getCell", () => { - const table = new Table({ - rows: 2, - columns: 2, - }); - - it("should return the correct row", () => { - table - .getRow(0) - .getCell(0) - .add(new Paragraph("A1")); - table - .getRow(0) - .getCell(1) - .add(new Paragraph("B1")); - table - .getRow(1) - .getCell(0) - .add(new Paragraph("A2")); - table - .getRow(1) - .getCell(1) - .add(new Paragraph("B2")); - const tree = new Formatter().format(table); - const cell = (c) => ({ - "w:tc": [ - { - "w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, c] }] }], - }, - ], - }); - expect(tree).to.deep.equal({ - "w:tbl": [ - { "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] }, - { - "w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }, { "w:gridCol": { _attr: { "w:w": 100 } } }], - }, - { "w:tr": [cell("A1"), cell("B1")] }, - { "w:tr": [cell("A2"), cell("B2")] }, - ], - }); - }); - - it("throws an exception if index is out of bounds", () => { - expect(() => table.getCell(9, 9)).to.throw(); - }); - }); - - describe("#getColumn", () => { - const table = new Table({ - rows: 2, - columns: 2, - }); - - it("should get correct cell", () => { - const column = table.getColumn(0); - - expect(column.getCell(0)).to.equal(table.getCell(0, 0)); - expect(column.getCell(1)).to.equal(table.getCell(1, 0)); - }); - }); - - describe("#getCell", () => { - it("should returns the correct cell", () => { - const table = new Table({ - rows: 2, - columns: 2, - }); - table.getCell(0, 0).add(new Paragraph("A1")); - table.getCell(0, 1).add(new Paragraph("B1")); - table.getCell(1, 0).add(new Paragraph("A2")); - table.getCell(1, 1).add(new Paragraph("B2")); - const tree = new Formatter().format(table); - const cell = (c) => ({ - "w:tc": [ - { - "w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, c] }] }], - }, - ], - }); - expect(tree).to.deep.equal({ - "w:tbl": [ - { "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] }, - { - "w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }, { "w:gridCol": { _attr: { "w:w": 100 } } }], - }, - { "w:tr": [cell("A1"), cell("B1")] }, - { "w:tr": [cell("A2"), cell("B2")] }, - ], - }); - }); - }); - - // describe("#setWidth", () => { - // it("should set the preferred width on the table", () => { - // const table = new Table({rows: 1,columns: 1,}).setWidth(1000, WidthType.PERCENTAGE); - // const tree = new Formatter().format(table); - // expect(tree) - // .to.have.property("w:tbl") - // .which.is.an("array") - // .with.has.length.at.least(1); - // expect(tree["w:tbl"][0]).to.deep.equal({ - // "w:tblPr": [DEFAULT_TABLE_PROPERTIES, { "w:tblW": { _attr: { "w:type": "pct", "w:w": "1000%" } } }], - // }); - // }); - - // it("sets the preferred width on the table with a default of AUTO", () => { - // const table = new Table({rows: 1,columns: 1,}).setWidth(1000); - // const tree = new Formatter().format(table); - - // expect(tree["w:tbl"][0]).to.deep.equal({ - // "w:tblPr": [DEFAULT_TABLE_PROPERTIES, { "w:tblW": { _attr: { "w:type": "auto", "w:w": 1000 } } }], - // }); - // }); - // }); - describe("Cell", () => { describe("#prepForXml", () => { it("inserts a paragraph at the end of the cell if it is empty", () => { const table = new Table({ - rows: 1, - columns: 1, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], }); const tree = new Formatter().format(table); expect(tree) @@ -290,64 +220,92 @@ describe("Table", () => { }); }); - it("inserts a paragraph at the end of the cell even if it has a child table", () => { - const parentTable = new Table({ - rows: 1, - columns: 1, - }); - parentTable.getCell(0, 0).add( - new Table({ - rows: 1, - columns: 1, - }), - ); - const tree = new Formatter().format(parentTable); - 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); - const cell = row["w:tr"].find((x) => x["w:tc"]); - expect(cell).not.to.be.undefined; - expect(cell["w:tc"][cell["w:tc"].length - 1]).to.deep.equal({ - "w:p": EMPTY_OBJECT, - }); - }); + // it("inserts a paragraph at the end of the cell even if it has a child table", () => { + // const table = new Table({ + // rows: [ + // new TableRow({ + // children: [ + // new TableCell({ + // children: [new Paragraph("hello")], + // }), + // ], + // }), + // ], + // }); + // table.getCell(0, 0).add( + // new Table({ + // rows: [ + // new TableRow({ + // children: [ + // new TableCell({ + // children: [new Paragraph("hello")], + // }), + // ], + // }), + // ], + // }), + // ); + // 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); + // const cell = row["w:tr"].find((x) => x["w:tc"]); + // expect(cell).not.to.be.undefined; + // expect(cell["w:tc"][cell["w:tc"].length - 1]).to.deep.equal({ + // "w:p": EMPTY_OBJECT, + // }); + // }); - it("does not insert a paragraph if it already ends with one", () => { - const parentTable = new Table({ - rows: 1, - columns: 1, - }); - parentTable.getCell(0, 0).add(new Paragraph("Hello")); - const tree = new Formatter().format(parentTable); - 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" } }, "Hello"] }] }], - }, - ], - }); - }); + // it("does not insert a paragraph if it already ends with one", () => { + // const table = new Table({ + // rows: [ + // new TableRow({ + // children: [ + // new TableCell({ + // children: [new Paragraph("hello")], + // }), + // ], + // }), + // ], + // }); + // table.getCell(0, 0).add(new Paragraph("Hello")); + // 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" } }, "Hello"] }] }], + // }, + // ], + // }); + // }); }); }); describe("#float", () => { it("sets the table float properties", () => { const table = new Table({ - rows: 1, - columns: 1, + rows: [ + new TableRow({ + children: [ + new TableCell({ + children: [new Paragraph("hello")], + }), + ], + }), + ], float: { horizontalAnchor: TableAnchorType.MARGIN, verticalAnchor: TableAnchorType.PAGE, diff --git a/src/file/table/table.ts b/src/file/table/table.ts index c56bc4d62c..ea8e64d72c 100644 --- a/src/file/table/table.ts +++ b/src/file/table/table.ts @@ -1,12 +1,11 @@ // http://officeopenxml.com/WPtableGrid.php import { XmlComponent } from "file/xml-components"; - import { TableGrid } from "./grid"; -import { TableCell, WidthType } from "./table-cell"; -import { TableColumn } from "./table-column"; +import { WidthType } from "./table-cell"; import { ITableFloatOptions, TableProperties } from "./table-properties"; import { TableLayoutType } from "./table-properties/table-layout"; import { TableRow } from "./table-row"; + /* 0-width columns don't get rendered correctly, so we need to give them some value. A reasonable default would be @@ -18,8 +17,7 @@ import { TableRow } from "./table-row"; algorithm will expand columns to fit its content */ export interface ITableOptions { - readonly rows: number; - readonly columns: number; + readonly rows: TableRow[]; readonly width?: number; readonly widthUnitType?: WidthType; readonly columnWidths?: number[]; @@ -36,14 +34,12 @@ export interface ITableOptions { export class Table extends XmlComponent { private readonly properties: TableProperties; - private readonly rows: TableRow[]; constructor({ rows, - columns, width = 100, widthUnitType = WidthType.AUTO, - columnWidths = Array(columns).fill(100), + columnWidths = Array(Math.max(...rows.map((row) => row.CellCount))).fill(100), margins: { marginUnitType, top, bottom, right, left } = { marginUnitType: WidthType.AUTO, top: 0, bottom: 0, right: 0, left: 0 }, float, layout, @@ -57,21 +53,12 @@ export class Table extends XmlComponent { this.properties.CellMargin.addTopMargin(top || 0, marginUnitType); this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType); this.properties.CellMargin.addRightMargin(right || 0, marginUnitType); - const grid = new TableGrid(columnWidths); - this.root.push(grid); + this.root.push(new TableGrid(columnWidths)); - this.rows = Array(rows) - .fill(0) - .map(() => { - const cells = Array(columns) - .fill(0) - .map(() => new TableCell()); - const row = new TableRow(cells); - return row; - }); - - this.rows.forEach((x) => this.root.push(x)); + for (const row of rows) { + this.root.push(row); + } if (float) { this.properties.setTableFloatProperties(float); @@ -81,24 +68,4 @@ export class Table extends XmlComponent { this.properties.setLayout(layout); } } - - public getRow(index: number): TableRow { - const row = this.rows[index]; - - if (!row) { - throw Error("Index out of bounds when trying to get row on table"); - } - - return row; - } - - public getColumn(index: number): TableColumn { - // This is a convinence method for people who like to work with columns - const cells = this.rows.map((row) => row.getCell(index)); - return new TableColumn(cells); - } - - public getCell(row: number, col: number): TableCell { - return this.getRow(row).getCell(col); - } }