Make table internals declarative
This commit is contained in:
@ -8,22 +8,31 @@ import { TableCellMargin } from "./table-cell-margin";
|
||||
describe("TableCellMargin", () => {
|
||||
describe("#constructor", () => {
|
||||
it("should throw an error if theres no child elements", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
const cellMargin = new TableCellMargin({});
|
||||
expect(() => new Formatter().format(cellMargin)).to.throw();
|
||||
});
|
||||
});
|
||||
|
||||
describe("#addTopMargin", () => {
|
||||
it("should add a table cell top margin", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addTopMargin(1234, WidthType.DXA);
|
||||
const cellMargin = new TableCellMargin({
|
||||
top: {
|
||||
value: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
|
||||
it("should add a table cell top margin using default width type", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addTopMargin(1234);
|
||||
const cellMargin = new TableCellMargin({
|
||||
top: {
|
||||
value: 1234,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
@ -31,15 +40,22 @@ describe("TableCellMargin", () => {
|
||||
|
||||
describe("#addLeftMargin", () => {
|
||||
it("should add a table cell left margin", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addLeftMargin(1234, WidthType.DXA);
|
||||
const cellMargin = new TableCellMargin({
|
||||
left: {
|
||||
value: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
|
||||
it("should add a table cell left margin using default width type", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addLeftMargin(1234);
|
||||
const cellMargin = new TableCellMargin({
|
||||
left: {
|
||||
value: 1234,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
@ -47,15 +63,24 @@ describe("TableCellMargin", () => {
|
||||
|
||||
describe("#addBottomMargin", () => {
|
||||
it("should add a table cell bottom margin", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addBottomMargin(1234, WidthType.DXA);
|
||||
const cellMargin = new TableCellMargin({
|
||||
bottom: {
|
||||
value: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
|
||||
it("should add a table cell bottom margin using default width type", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addBottomMargin(1234);
|
||||
const cellMargin = new TableCellMargin({
|
||||
bottom: {
|
||||
value: 1234,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
@ -63,15 +88,24 @@ describe("TableCellMargin", () => {
|
||||
|
||||
describe("#addRightMargin", () => {
|
||||
it("should add a table cell right margin", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addRightMargin(1234, WidthType.DXA);
|
||||
const cellMargin = new TableCellMargin({
|
||||
right: {
|
||||
value: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
|
||||
it("should add a table cell right margin using default width type", () => {
|
||||
const cellMargin = new TableCellMargin();
|
||||
cellMargin.addRightMargin(1234);
|
||||
const cellMargin = new TableCellMargin({
|
||||
right: {
|
||||
value: 1234,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(cellMargin);
|
||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||
});
|
||||
|
@ -6,7 +6,23 @@ class TableCellMarginAttributes extends XmlAttributeComponent<{ readonly type: W
|
||||
protected readonly xmlKeys = { value: "w:w", type: "w:type" };
|
||||
}
|
||||
|
||||
interface IBaseTableCellMarginOptions {
|
||||
readonly value: number;
|
||||
readonly type?: WidthType;
|
||||
}
|
||||
|
||||
class BaseTableCellMargin extends XmlComponent {
|
||||
constructor(rootKey: string, options: IBaseTableCellMarginOptions) {
|
||||
super(rootKey);
|
||||
|
||||
this.root.push(
|
||||
new TableCellMarginAttributes({
|
||||
type: options.type ?? WidthType.DXA,
|
||||
value: options.value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
public setProperties(value: number, type: WidthType = WidthType.DXA): void {
|
||||
this.root.push(
|
||||
new TableCellMarginAttributes({
|
||||
@ -17,36 +33,31 @@ class BaseTableCellMargin extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ITableCellMarginOptions {
|
||||
readonly top?: IBaseTableCellMarginOptions;
|
||||
readonly bottom?: IBaseTableCellMarginOptions;
|
||||
readonly left?: IBaseTableCellMarginOptions;
|
||||
readonly right?: IBaseTableCellMarginOptions;
|
||||
}
|
||||
|
||||
export class TableCellMargin extends IgnoreIfEmptyXmlComponent {
|
||||
constructor() {
|
||||
constructor(options: ITableCellMarginOptions) {
|
||||
super("w:tblCellMar");
|
||||
|
||||
if (options.bottom) {
|
||||
this.root.push(new BaseTableCellMargin("w:bottom", options.bottom));
|
||||
}
|
||||
|
||||
public addTopMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const top = new BaseTableCellMargin("w:top");
|
||||
|
||||
top.setProperties(value, type);
|
||||
this.root.push(top);
|
||||
if (options.top) {
|
||||
this.root.push(new BaseTableCellMargin("w:top", options.top));
|
||||
}
|
||||
|
||||
public addLeftMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const left = new BaseTableCellMargin("w:left");
|
||||
|
||||
left.setProperties(value, type);
|
||||
this.root.push(left);
|
||||
if (options.left) {
|
||||
this.root.push(new BaseTableCellMargin("w:left", options.left));
|
||||
}
|
||||
|
||||
public addBottomMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const bottom = new BaseTableCellMargin("w:bottom");
|
||||
|
||||
bottom.setProperties(value, type);
|
||||
this.root.push(bottom);
|
||||
}
|
||||
|
||||
public addRightMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const right = new BaseTableCellMargin("w:right");
|
||||
|
||||
right.setProperties(value, type);
|
||||
this.root.push(right);
|
||||
if (options.right) {
|
||||
this.root.push(new BaseTableCellMargin("w:right", options.right));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import { TableProperties } from "./table-properties";
|
||||
describe("TableProperties", () => {
|
||||
describe("#constructor", () => {
|
||||
it("creates an initially empty property object", () => {
|
||||
const tp = new TableProperties();
|
||||
const tp = new TableProperties({});
|
||||
// The TableProperties is ignorable if there are no attributes,
|
||||
// which results in prepForXml returning undefined, which causes
|
||||
// the formatter to throw an error if that is the only object it
|
||||
@ -22,7 +22,12 @@ describe("TableProperties", () => {
|
||||
|
||||
describe("#setWidth", () => {
|
||||
it("should add a table width property", () => {
|
||||
const tp = new TableProperties().setWidth(1234, WidthType.DXA);
|
||||
const tp = new TableProperties({
|
||||
width: {
|
||||
size: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblW": { _attr: { "w:type": "dxa", "w:w": 1234 } } }],
|
||||
@ -30,7 +35,12 @@ describe("TableProperties", () => {
|
||||
});
|
||||
|
||||
it("should add a table width property with default of AUTO", () => {
|
||||
const tp = new TableProperties().setWidth(1234);
|
||||
const tp = new TableProperties({
|
||||
width: {
|
||||
size: 1234,
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblW": { _attr: { "w:type": "auto", "w:w": 1234 } } }],
|
||||
@ -40,8 +50,10 @@ describe("TableProperties", () => {
|
||||
|
||||
describe("#setLayout", () => {
|
||||
it("sets the table to fixed width layout", () => {
|
||||
const tp = new TableProperties();
|
||||
tp.setLayout(TableLayoutType.FIXED);
|
||||
const tp = new TableProperties({
|
||||
layout: TableLayoutType.FIXED,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblLayout": { _attr: { "w:type": "fixed" } } }],
|
||||
@ -51,8 +63,15 @@ describe("TableProperties", () => {
|
||||
|
||||
describe("#cellMargin", () => {
|
||||
it("adds a table cell top margin", () => {
|
||||
const tp = new TableProperties();
|
||||
tp.CellMargin.addTopMargin(1234, WidthType.DXA);
|
||||
const tp = new TableProperties({
|
||||
cellMargin: {
|
||||
top: {
|
||||
value: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }],
|
||||
@ -60,8 +79,15 @@ describe("TableProperties", () => {
|
||||
});
|
||||
|
||||
it("adds a table cell left margin", () => {
|
||||
const tp = new TableProperties();
|
||||
tp.CellMargin.addLeftMargin(1234, WidthType.DXA);
|
||||
const tp = new TableProperties({
|
||||
cellMargin: {
|
||||
left: {
|
||||
value: 1234,
|
||||
type: WidthType.DXA,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] }],
|
||||
@ -71,12 +97,14 @@ describe("TableProperties", () => {
|
||||
|
||||
describe("#setShading", () => {
|
||||
it("sets the shading of the table", () => {
|
||||
const tp = new TableProperties();
|
||||
tp.setShading({
|
||||
const tp = new TableProperties({
|
||||
shading: {
|
||||
fill: "b79c2f",
|
||||
val: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||
color: "auto",
|
||||
},
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [
|
||||
@ -95,9 +123,10 @@ describe("TableProperties", () => {
|
||||
});
|
||||
|
||||
describe("#setAlignment", () => {
|
||||
it("sets the shading of the table", () => {
|
||||
const tp = new TableProperties();
|
||||
tp.setAlignment(AlignmentType.CENTER);
|
||||
it("sets the alignment of the table", () => {
|
||||
const tp = new TableProperties({
|
||||
alignment: AlignmentType.CENTER,
|
||||
});
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [
|
||||
|
@ -5,51 +5,52 @@ import { Alignment, AlignmentType } from "../../paragraph";
|
||||
import { ITableShadingAttributesProperties, TableShading } from "../shading";
|
||||
import { WidthType } from "../table-cell";
|
||||
import { ITableBordersOptions, TableBorders } from "./table-borders";
|
||||
import { TableCellMargin } from "./table-cell-margin";
|
||||
import { ITableCellMarginOptions, TableCellMargin } from "./table-cell-margin";
|
||||
import { ITableFloatOptions, TableFloatProperties } from "./table-float-properties";
|
||||
import { TableLayout, TableLayoutType } from "./table-layout";
|
||||
import { PreferredTableWidth } from "./table-width";
|
||||
|
||||
export class TableProperties extends IgnoreIfEmptyXmlComponent {
|
||||
private readonly cellMargin: TableCellMargin;
|
||||
export interface ITablePropertiesOptions {
|
||||
readonly width?: {
|
||||
readonly size: number;
|
||||
readonly type?: WidthType;
|
||||
};
|
||||
readonly layout?: TableLayoutType;
|
||||
readonly borders?: ITableBordersOptions;
|
||||
readonly float?: ITableFloatOptions;
|
||||
readonly shading?: ITableShadingAttributesProperties;
|
||||
readonly alignment?: AlignmentType;
|
||||
readonly cellMargin?: ITableCellMarginOptions;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
export class TableProperties extends IgnoreIfEmptyXmlComponent {
|
||||
constructor(options: ITablePropertiesOptions) {
|
||||
super("w:tblPr");
|
||||
|
||||
this.cellMargin = new TableCellMargin();
|
||||
this.root.push(this.cellMargin);
|
||||
this.root.push(new TableCellMargin(options.cellMargin || {}));
|
||||
|
||||
if (options.borders) {
|
||||
this.root.push(new TableBorders(options.borders));
|
||||
}
|
||||
|
||||
public setWidth(width: number, type: WidthType = WidthType.AUTO): TableProperties {
|
||||
this.root.push(new PreferredTableWidth(type, width));
|
||||
return this;
|
||||
if (options.width) {
|
||||
this.root.push(new PreferredTableWidth(options.width.type, options.width.size));
|
||||
}
|
||||
|
||||
public setLayout(type: TableLayoutType): void {
|
||||
this.root.push(new TableLayout(type));
|
||||
if (options.float) {
|
||||
this.root.push(new TableFloatProperties(options.float));
|
||||
}
|
||||
|
||||
public setBorder(borderOptions: ITableBordersOptions): TableProperties {
|
||||
this.root.push(new TableBorders(borderOptions));
|
||||
return this;
|
||||
if (options.layout) {
|
||||
this.root.push(new TableLayout(options.layout));
|
||||
}
|
||||
|
||||
public get CellMargin(): TableCellMargin {
|
||||
return this.cellMargin;
|
||||
if (options.alignment) {
|
||||
this.root.push(new Alignment(options.alignment));
|
||||
}
|
||||
|
||||
public setTableFloatProperties(tableFloatOptions: ITableFloatOptions): TableProperties {
|
||||
this.root.push(new TableFloatProperties(tableFloatOptions));
|
||||
return this;
|
||||
}
|
||||
|
||||
public setShading(attrs: ITableShadingAttributesProperties): TableProperties {
|
||||
this.root.push(new TableShading(attrs));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public setAlignment(type: AlignmentType): void {
|
||||
this.root.push(new Alignment(type));
|
||||
if (options.shading) {
|
||||
this.root.push(new TableShading(options.shading));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ class TableWidthAttributes extends XmlAttributeComponent<ITableWidth> {
|
||||
}
|
||||
|
||||
export class PreferredTableWidth extends XmlComponent {
|
||||
constructor(type: WidthType, w: number) {
|
||||
constructor(type: WidthType = WidthType.AUTO, w: number) {
|
||||
super("w:tblW");
|
||||
const width: number | string = type === WidthType.PERCENTAGE ? `${w}%` : w;
|
||||
this.root.push(new TableWidthAttributes({ type: type, w: width }));
|
||||
|
@ -39,8 +39,6 @@ export interface ITableOptions {
|
||||
}
|
||||
|
||||
export class Table extends XmlComponent {
|
||||
private readonly properties: TableProperties;
|
||||
|
||||
constructor({
|
||||
rows,
|
||||
width,
|
||||
@ -52,25 +50,34 @@ export class Table extends XmlComponent {
|
||||
alignment,
|
||||
}: ITableOptions) {
|
||||
super("w:tbl");
|
||||
this.properties = new TableProperties();
|
||||
this.root.push(this.properties);
|
||||
|
||||
if (borders) {
|
||||
this.properties.setBorder(borders);
|
||||
} else {
|
||||
this.properties.setBorder({});
|
||||
}
|
||||
|
||||
if (width) {
|
||||
this.properties.setWidth(width.size, width.type);
|
||||
} else {
|
||||
this.properties.setWidth(100);
|
||||
}
|
||||
|
||||
this.properties.CellMargin.addBottomMargin(bottom || 0, marginUnitType);
|
||||
this.properties.CellMargin.addTopMargin(top || 0, marginUnitType);
|
||||
this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType);
|
||||
this.properties.CellMargin.addRightMargin(right || 0, marginUnitType);
|
||||
this.root.push(
|
||||
new TableProperties({
|
||||
borders: borders ?? {},
|
||||
width: width ?? { size: 100 },
|
||||
float,
|
||||
layout,
|
||||
alignment,
|
||||
cellMargin: {
|
||||
bottom: {
|
||||
value: bottom || 0,
|
||||
type: marginUnitType,
|
||||
},
|
||||
top: {
|
||||
value: top || 0,
|
||||
type: marginUnitType,
|
||||
},
|
||||
left: {
|
||||
value: left || 0,
|
||||
type: marginUnitType,
|
||||
},
|
||||
right: {
|
||||
value: right || 0,
|
||||
type: marginUnitType,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
this.root.push(new TableGrid(columnWidths));
|
||||
|
||||
@ -101,17 +108,5 @@ export class Table extends XmlComponent {
|
||||
columnIndex += cell.options.columnSpan || 1;
|
||||
});
|
||||
});
|
||||
|
||||
if (float) {
|
||||
this.properties.setTableFloatProperties(float);
|
||||
}
|
||||
|
||||
if (layout) {
|
||||
this.properties.setLayout(layout);
|
||||
}
|
||||
|
||||
if (alignment) {
|
||||
this.properties.setAlignment(alignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user