Declarative tables

This commit is contained in:
Dolan
2019-09-13 00:51:20 +01:00
parent 59fc1ed632
commit 418adca9f3
21 changed files with 978 additions and 536 deletions

View File

@ -1,7 +1,7 @@
// Setting styles with JavaScript configuration // Setting styles with JavaScript configuration
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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(); 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 image = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
const table = new Table({ const table = new Table({
rows: 4, rows: [
columns: 4, 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 image1 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif")); const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));

View File

@ -1,23 +1,102 @@
// Add custom borders to table cell // Add custom borders to table cell
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const table = new Table({ const table = new Table({
rows: 4, rows: [
columns: 4, 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] }); 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) => { Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer); fs.writeFileSync("My Document.docx", buffer);

View File

@ -1,24 +1,85 @@
// Add image to table cell // Add image to table cell
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
const table = new Table({ const table = new Table({
rows: 4, rows: [
columns: 4, 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({ doc.addSection({
children: [table], 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) => { Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer); fs.writeFileSync("My Document.docx", buffer);
}); });

View File

@ -1,27 +1,47 @@
// Example of how you would create a table and add data to it // 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 from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const table = new Table({ const table = new Table({
rows: 2, rows: [
columns: 2, new TableRow({
}); children: [
new TableCell({
table children: [new Paragraph({}), new Paragraph({})],
.getCell(1, 1) verticalAlign: VerticalAlign.CENTER,
.add(new Paragraph("This text should be in the middle of the cell")) }),
.setVerticalAlign(VerticalAlign.CENTER); new TableCell({
children: [new Paragraph({}), new Paragraph({})],
table.getCell(1, 0).add( verticalAlign: VerticalAlign.CENTER,
}),
],
}),
new TableRow({
children: [
new TableCell({
children: [
new Paragraph({ new Paragraph({
text: 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", "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, heading: HeadingLevel.HEADING_1,
}), }),
); ],
}),
new TableCell({
children: [
new Paragraph({
text: "This text should be in the middle of the cell",
}),
],
verticalAlign: VerticalAlign.CENTER,
}),
],
}),
],
});
doc.addSection({ doc.addSection({
children: [table], children: [table],

View File

@ -1,40 +1,118 @@
// Example of how you would merge cells together // Example of how you would merge cells together
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const table = new Table({ const table = new Table({
rows: 2, rows: [
columns: 2, 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({ const table2 = new Table({
rows: 2, rows: [
columns: 3, 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, width: 100,
widthUnitType: WidthType.AUTO, widthUnitType: WidthType.AUTO,
columnWidths: [1000, 1000, 1000], 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({ const table3 = new Table({
rows: 2, rows: [
columns: 4, 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, width: 7000,
widthUnitType: WidthType.DXA, widthUnitType: WidthType.DXA,
margins: { 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({ const table4 = new Table({
rows: 2, rows: [
columns: 2, new TableRow({
children: [
new TableCell({
children: [],
}),
new TableCell({
children: [],
}),
],
}),
new TableRow({
children: [
new TableCell({
children: [],
}),
new TableCell({
children: [],
}),
],
}),
],
width: 100, width: 100,
widthUnitType: WidthType.PERCENTAGE, widthUnitType: WidthType.PERCENTAGE,
}); });

View File

@ -9,15 +9,35 @@ import {
RelativeVerticalPosition, RelativeVerticalPosition,
Table, Table,
TableAnchorType, TableAnchorType,
TableCell,
TableLayoutType, TableLayoutType,
TableRow,
WidthType, WidthType,
} from "../build"; } from "../build";
const doc = new Document(); const doc = new Document();
const table = new Table({ const table = new Table({
rows: 2, rows: [
columns: 2, new TableRow({
children: [
new TableCell({
children: [new Paragraph("Hello")],
columnSpan: 2,
}),
],
}),
new TableRow({
children: [
new TableCell({
children: [],
}),
new TableCell({
children: [],
}),
],
}),
],
float: { float: {
horizontalAnchor: TableAnchorType.MARGIN, horizontalAnchor: TableAnchorType.MARGIN,
verticalAnchor: TableAnchorType.MARGIN, verticalAnchor: TableAnchorType.MARGIN,
@ -29,9 +49,6 @@ const table = new Table({
layout: TableLayoutType.FIXED, layout: TableLayoutType.FIXED,
}); });
table.getCell(0, 0).add(new Paragraph("Hello"));
table.getRow(0).mergeCells(0, 1);
doc.addSection({ doc.addSection({
children: [table], children: [table],
}); });

View File

@ -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 from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg")); const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
const table = new Table({ const table = new Table({
rows: 2, rows: [
columns: 2, 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 // Adding same table in the body and in the header
doc.addSection({ doc.addSection({

View File

@ -1,17 +1,35 @@
// Example of how you would create a table and add data to it // 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 from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const table = new Table({ const table = new Table({
rows: 4, rows: [
columns: 4, 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({ doc.addSection({
children: [table], children: [table],
}); });

View File

@ -1,50 +1,122 @@
// Multiple cells merging in the same table // Multiple cells merging in the same table
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const table = new Table({ const table = new Table({
rows: 13, rows: [
columns: 6, 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({ doc.addSection({
children: [table], children: [table],
}); });

View File

@ -1,16 +1,79 @@
// Add image to table cell // Add image to table cell
// Import from 'docx' rather than '../build' if you install from npm // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs"; 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 doc = new Document();
const table = new Table({ const table = new Table({
rows: 4, rows: [
columns: 4, 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); table.getColumn(3).mergeCells(1, 2);
doc.addSection({ doc.addSection({

View File

@ -6,7 +6,7 @@ import { Formatter } from "export/formatter";
import { File } from "./file"; import { File } from "./file";
import { Footer, Header } from "./header"; import { Footer, Header } from "./header";
import { Paragraph } from "./paragraph"; import { Paragraph } from "./paragraph";
import { Table } from "./table"; import { Table, TableCell, TableRow } from "./table";
import { TableOfContents } from "./table-of-contents"; import { TableOfContents } from "./table-of-contents";
describe("File", () => { describe("File", () => {
@ -108,8 +108,15 @@ describe("File", () => {
file.addSection({ file.addSection({
children: [ children: [
new Table({ new Table({
rows: 1, rows: [
columns: 1, new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
}), }),
], ],
}); });

View File

@ -4,7 +4,7 @@ import * as sinon from "sinon";
import { FooterWrapper } from "./footer-wrapper"; import { FooterWrapper } from "./footer-wrapper";
import { Media } from "./media"; import { Media } from "./media";
import { Paragraph } from "./paragraph"; import { Paragraph } from "./paragraph";
import { Table } from "./table"; import { Table, TableCell, TableRow } from "./table";
describe("FooterWrapper", () => { describe("FooterWrapper", () => {
describe("#add", () => { describe("#add", () => {
@ -21,8 +21,15 @@ describe("FooterWrapper", () => {
const spy = sinon.spy(file.Footer, "add"); const spy = sinon.spy(file.Footer, "add");
file.add( file.add(
new Table({ new Table({
rows: 1, rows: [
columns: 1, new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
}), }),
); );

View File

@ -4,7 +4,7 @@ import * as sinon from "sinon";
import { HeaderWrapper } from "./header-wrapper"; import { HeaderWrapper } from "./header-wrapper";
import { Media } from "./media"; import { Media } from "./media";
import { Paragraph } from "./paragraph"; import { Paragraph } from "./paragraph";
import { Table } from "./table"; import { Table, TableCell, TableRow } from "./table";
describe("HeaderWrapper", () => { describe("HeaderWrapper", () => {
describe("#add", () => { describe("#add", () => {
@ -21,8 +21,15 @@ describe("HeaderWrapper", () => {
const spy = sinon.spy(wrapper.Header, "add"); const spy = sinon.spy(wrapper.Header, "add");
wrapper.add( wrapper.add(
new Table({ new Table({
rows: 1, rows: [
columns: 1, new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
}), }),
); );

View File

@ -2,9 +2,11 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export class TableGrid extends XmlComponent { export class TableGrid extends XmlComponent {
constructor(cols: number[]) { constructor(widths: number[]) {
super("w:tblGrid"); super("w:tblGrid");
cols.forEach((col) => this.root.push(new GridCol(col))); for (const width of widths) {
this.root.push(new GridCol(width));
}
} }
} }

View File

@ -1,77 +1,107 @@
// http://officeopenxml.com/WPtableGrid.php // http://officeopenxml.com/WPtableGrid.php
import { Paragraph } from "file/paragraph"; import { Paragraph } from "file/paragraph";
import { BorderStyle } from "file/styles";
import { IXmlableObject, XmlComponent } from "file/xml-components"; import { IXmlableObject, XmlComponent } from "file/xml-components";
import { ITableShadingAttributesProperties } from "../shading"; import { ITableShadingAttributesProperties } from "../shading";
import { Table } from "../table"; import { Table } from "../table";
import { ITableCellMarginOptions } from "./cell-margin/table-cell-margins"; 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"; import { TableCellProperties } from "./table-cell-properties";
export interface ITableCellOptions { export interface ITableCellOptions {
readonly shading?: ITableShadingAttributesProperties; 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<Paragraph | Table>;
} }
export class TableCell extends XmlComponent { export class TableCell extends XmlComponent {
private readonly properties: TableCellProperties; private readonly properties: TableCellProperties;
constructor() { constructor(readonly options: ITableCellOptions) {
super("w:tc"); super("w:tc");
this.properties = new TableCellProperties(); this.properties = new TableCellProperties();
this.root.push(this.properties); this.root.push(this.properties);
for (const child of options.children) {
this.root.push(child);
} }
public add(item: Paragraph | Table): TableCell { if (options.verticalAlign) {
this.root.push(item); this.properties.setVerticalAlign(options.verticalAlign);
}
return this; 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 { public prepForXml(): IXmlableObject | undefined {
// Cells must end with a paragraph // Cells must end with a paragraph
if (!(this.root[this.root.length - 1] instanceof Paragraph)) { if (!(this.root[this.root.length - 1] instanceof Paragraph)) {
const para = new Paragraph({}); this.root.push(new Paragraph({}));
this.add(para);
} }
return super.prepForXml(); 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;
}
} }

View File

@ -1,16 +1,25 @@
import { expect } from "chai"; 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 { TableCell } from "./table-cell";
import { TableColumn } from "./table-column"; import { TableColumn } from "./table-column";
import { EMPTY_OBJECT } from "file/xml-components";
describe("TableColumn", () => { describe("TableColumn", () => {
let cells: TableCell[]; let cells: TableCell[];
beforeEach(() => { beforeEach(() => {
cells = [new TableCell(), new TableCell(), new TableCell()]; cells = [
new TableCell({
children: [],
}),
new TableCell({
children: [],
}),
new TableCell({
children: [],
}),
];
}); });
describe("#getCell", () => { describe("#getCell", () => {
@ -32,25 +41,25 @@ describe("TableColumn", () => {
}); });
}); });
describe("#mergeCells", () => { // describe("#mergeCells", () => {
it("should add vMerge to correct cells", () => { // it("should add vMerge to correct cells", () => {
const tableColumn = new TableColumn(cells); // const tableColumn = new TableColumn(cells);
tableColumn.mergeCells(0, 2); // tableColumn.mergeCells(0, 2);
const tree = new Formatter().format(cells[0]); // const tree = new Formatter().format(cells[0]);
expect(tree).to.deep.equal({ // expect(tree).to.deep.equal({
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, { "w:p": EMPTY_OBJECT }], // "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, { "w:p": EMPTY_OBJECT }],
}); // });
const tree2 = new Formatter().format(cells[1]); // const tree2 = new Formatter().format(cells[1]);
expect(tree2).to.deep.equal({ // expect(tree2).to.deep.equal({
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }], // "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }],
}); // });
const tree3 = new Formatter().format(cells[2]); // const tree3 = new Formatter().format(cells[2]);
expect(tree3).to.deep.equal({ // expect(tree3).to.deep.equal({
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }], // "w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }],
}); // });
}); // });
}); // });
}); });

View File

@ -1,4 +1,4 @@
import { TableCell, VMergeType } from "./table-cell"; import { TableCell } from "./table-cell";
export class TableColumn { export class TableColumn {
constructor(private readonly cells: TableCell[]) {} constructor(private readonly cells: TableCell[]) {}
@ -13,13 +13,13 @@ export class TableColumn {
return cell; return cell;
} }
public mergeCells(startIndex: number, endIndex: number): TableCell { // public mergeCells(startIndex: number, endIndex: number): TableCell {
this.cells[startIndex].addVerticalMerge(VMergeType.RESTART); // this.cells[startIndex].addVerticalMerge(VMergeType.RESTART);
for (let i = startIndex + 1; i <= endIndex; i++) { // for (let i = startIndex + 1; i <= endIndex; i++) {
this.cells[i].addVerticalMerge(VMergeType.CONTINUE); // this.cells[i].addVerticalMerge(VMergeType.CONTINUE);
} // }
return this.cells[startIndex]; // return this.cells[startIndex];
} // }
} }

View File

@ -10,7 +10,9 @@ import { TableRow } from "./table-row";
describe("TableRow", () => { describe("TableRow", () => {
describe("#constructor", () => { describe("#constructor", () => {
it("should create with no cells", () => { it("should create with no cells", () => {
const tableRow = new TableRow([]); const tableRow = new TableRow({
children: [],
});
const tree = new Formatter().format(tableRow); const tree = new Formatter().format(tableRow);
expect(tree).to.deep.equal({ expect(tree).to.deep.equal({
"w:tr": EMPTY_OBJECT, "w:tr": EMPTY_OBJECT,
@ -18,7 +20,13 @@ describe("TableRow", () => {
}); });
it("should create with one cell", () => { 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); const tree = new Formatter().format(tableRow);
expect(tree).to.deep.equal({ expect(tree).to.deep.equal({
"w:tr": [ "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", () => { it("should set row height", () => {
const tableRow = new TableRow([]); const tableRow = new TableRow({
tableRow.setHeight(100, HeightRule.EXACT); children: [],
height: {
height: 100,
rule: HeightRule.EXACT,
},
});
const tree = new Formatter().format(tableRow); const tree = new Formatter().format(tableRow);
expect(tree).to.deep.equal({ expect(tree).to.deep.equal({
"w:tr": [ "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();
// });
// });
}); });

View File

@ -3,56 +3,57 @@ import { XmlComponent } from "file/xml-components";
import { TableCell } from "../table-cell"; import { TableCell } from "../table-cell";
import { TableRowProperties } from "./table-row-properties"; 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 { export class TableRow extends XmlComponent {
private readonly properties: TableRowProperties; private readonly properties: TableRowProperties;
constructor(private readonly cells: TableCell[]) { constructor(private readonly options: ITableRowOptions) {
super("w:tr"); super("w:tr");
this.properties = new TableRowProperties(); this.properties = new TableRowProperties();
this.root.push(this.properties); this.root.push(this.properties);
cells.forEach((c) => this.root.push(c));
for (const child of options.children) {
this.root.push(child);
} }
public getCell(index: number): TableCell { if (options.cantSplit) {
const cell = this.cells[index];
if (!cell) {
throw Error("Index out of bounds when trying to get cell on row");
}
return cell;
}
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 mergeCells(startIndex: number, endIndex: number): TableCell {
const cellSpan = endIndex - startIndex + 1;
return this.addGridSpan(startIndex, cellSpan);
}
public setCantSplit(): TableRow {
this.properties.setCantSplit(); this.properties.setCantSplit();
return this;
} }
public setTableHeader(): TableRow { if (options.tableHeader) {
this.properties.setTableHeader(); this.properties.setTableHeader();
return this;
} }
public setHeight(height: number, rule: HeightRule): TableRow { if (options.height) {
this.properties.setHeight(height, rule); this.properties.setHeight(options.height.height, options.height.rule);
return this;
} }
}
public get CellCount(): number {
return this.options.children.length;
}
// public mergeCells(startIndex: number, endIndex: number): TableCell {
// const cellSpan = endIndex - startIndex + 1;
// return this.addGridSpan(startIndex, cellSpan);
// }
// 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 remainCell;
// }
} }

View File

@ -9,7 +9,9 @@ import { Table } from "./table";
import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties"; import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties";
import { EMPTY_OBJECT } from "file/xml-components"; import { EMPTY_OBJECT } from "file/xml-components";
import { TableCell } from "./table-cell";
import { TableLayoutType } from "./table-properties/table-layout"; import { TableLayoutType } from "./table-properties/table-layout";
import { TableRow } from "./table-row";
const DEFAULT_TABLE_PROPERTIES = { const DEFAULT_TABLE_PROPERTIES = {
"w:tblCellMar": [ "w:tblCellMar": [
@ -118,8 +120,38 @@ describe("Table", () => {
describe("#constructor", () => { describe("#constructor", () => {
it("creates a table with the correct number of rows and columns", () => { it("creates a table with the correct number of rows and columns", () => {
const table = new Table({ const table = new Table({
rows: 3, rows: [
columns: 2, 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 tree = new Formatter().format(table);
const cell = { "w:tc": [{ "w:p": EMPTY_OBJECT }] }; const cell = { "w:tc": [{ "w:p": EMPTY_OBJECT }] };
@ -138,8 +170,15 @@ describe("Table", () => {
it("sets the table to fixed width layout", () => { it("sets the table to fixed width layout", () => {
const table = new Table({ const table = new Table({
rows: 1, rows: [
columns: 1, new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
layout: TableLayoutType.FIXED, layout: TableLayoutType.FIXED,
}); });
const tree = new Formatter().format(table); 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("Cell", () => {
describe("#prepForXml", () => { describe("#prepForXml", () => {
it("inserts a paragraph at the end of the cell if it is empty", () => { it("inserts a paragraph at the end of the cell if it is empty", () => {
const table = new Table({ const table = new Table({
rows: 1, rows: [
columns: 1, new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
}); });
const tree = new Formatter().format(table); const tree = new Formatter().format(table);
expect(tree) 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", () => { // it("inserts a paragraph at the end of the cell even if it has a child table", () => {
const parentTable = new Table({ // const table = new Table({
rows: 1, // rows: [
columns: 1, // new TableRow({
}); // children: [
parentTable.getCell(0, 0).add( // new TableCell({
new Table({ // children: [new Paragraph("hello")],
rows: 1, // }),
columns: 1, // ],
}), // }),
); // ],
const tree = new Formatter().format(parentTable); // });
expect(tree) // table.getCell(0, 0).add(
.to.have.property("w:tbl") // new Table({
.which.is.an("array"); // rows: [
const row = tree["w:tbl"].find((x) => x["w:tr"]); // new TableRow({
expect(row).not.to.be.undefined; // children: [
expect(row["w:tr"]) // new TableCell({
.to.be.an("array") // children: [new Paragraph("hello")],
.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, // }),
}); // );
}); // 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", () => { // it("does not insert a paragraph if it already ends with one", () => {
const parentTable = new Table({ // const table = new Table({
rows: 1, // rows: [
columns: 1, // new TableRow({
}); // children: [
parentTable.getCell(0, 0).add(new Paragraph("Hello")); // new TableCell({
const tree = new Formatter().format(parentTable); // children: [new Paragraph("hello")],
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"]) // table.getCell(0, 0).add(new Paragraph("Hello"));
.to.be.an("array") // const tree = new Formatter().format(table);
.which.has.length.at.least(1); // expect(tree)
expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({ // .to.have.property("w:tbl")
"w:tc": [ // .which.is.an("array");
{ // const row = tree["w:tbl"].find((x) => x["w:tr"]);
"w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "Hello"] }] }], // 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", () => { describe("#float", () => {
it("sets the table float properties", () => { it("sets the table float properties", () => {
const table = new Table({ const table = new Table({
rows: 1, rows: [
columns: 1, new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
float: { float: {
horizontalAnchor: TableAnchorType.MARGIN, horizontalAnchor: TableAnchorType.MARGIN,
verticalAnchor: TableAnchorType.PAGE, verticalAnchor: TableAnchorType.PAGE,

View File

@ -1,12 +1,11 @@
// http://officeopenxml.com/WPtableGrid.php // http://officeopenxml.com/WPtableGrid.php
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { TableGrid } from "./grid"; import { TableGrid } from "./grid";
import { TableCell, WidthType } from "./table-cell"; import { WidthType } from "./table-cell";
import { TableColumn } from "./table-column";
import { ITableFloatOptions, TableProperties } from "./table-properties"; import { ITableFloatOptions, TableProperties } from "./table-properties";
import { TableLayoutType } from "./table-properties/table-layout"; import { TableLayoutType } from "./table-properties/table-layout";
import { TableRow } from "./table-row"; import { TableRow } from "./table-row";
/* /*
0-width columns don't get rendered correctly, so we need 0-width columns don't get rendered correctly, so we need
to give them some value. A reasonable default would be 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 algorithm will expand columns to fit its content
*/ */
export interface ITableOptions { export interface ITableOptions {
readonly rows: number; readonly rows: TableRow[];
readonly columns: number;
readonly width?: number; readonly width?: number;
readonly widthUnitType?: WidthType; readonly widthUnitType?: WidthType;
readonly columnWidths?: number[]; readonly columnWidths?: number[];
@ -36,14 +34,12 @@ export interface ITableOptions {
export class Table extends XmlComponent { export class Table extends XmlComponent {
private readonly properties: TableProperties; private readonly properties: TableProperties;
private readonly rows: TableRow[];
constructor({ constructor({
rows, rows,
columns,
width = 100, width = 100,
widthUnitType = WidthType.AUTO, widthUnitType = WidthType.AUTO,
columnWidths = Array<number>(columns).fill(100), columnWidths = Array<number>(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 }, margins: { marginUnitType, top, bottom, right, left } = { marginUnitType: WidthType.AUTO, top: 0, bottom: 0, right: 0, left: 0 },
float, float,
layout, layout,
@ -57,21 +53,12 @@ export class Table extends XmlComponent {
this.properties.CellMargin.addTopMargin(top || 0, marginUnitType); this.properties.CellMargin.addTopMargin(top || 0, marginUnitType);
this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType); this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType);
this.properties.CellMargin.addRightMargin(right || 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) for (const row of rows) {
.fill(0) this.root.push(row);
.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));
if (float) { if (float) {
this.properties.setTableFloatProperties(float); this.properties.setTableFloatProperties(float);
@ -81,24 +68,4 @@ export class Table extends XmlComponent {
this.properties.setLayout(layout); 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);
}
} }