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

@ -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,