diff --git a/src/file/table/table-properties/table-cell-margin.spec.ts b/src/file/table/table-properties/table-cell-margin.spec.ts index 2a89db7a4a..814888adc0 100644 --- a/src/file/table/table-properties/table-cell-margin.spec.ts +++ b/src/file/table/table-properties/table-cell-margin.spec.ts @@ -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 } } }] }); }); diff --git a/src/file/table/table-properties/table-cell-margin.ts b/src/file/table/table-properties/table-cell-margin.ts index ebebb87bc3..6889b6f580 100644 --- a/src/file/table/table-properties/table-cell-margin.ts +++ b/src/file/table/table-properties/table-cell-margin.ts @@ -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"); - } - public addTopMargin(value: number, type: WidthType = WidthType.DXA): void { - const top = new BaseTableCellMargin("w:top"); + if (options.bottom) { + this.root.push(new BaseTableCellMargin("w:bottom", options.bottom)); + } - 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"); + if (options.left) { + this.root.push(new BaseTableCellMargin("w:left", options.left)); + } - left.setProperties(value, type); - this.root.push(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)); + } } } diff --git a/src/file/table/table-properties/table-properties.spec.ts b/src/file/table/table-properties/table-properties.spec.ts index 1c10e09b6a..b06aadbe4b 100644 --- a/src/file/table/table-properties/table-properties.spec.ts +++ b/src/file/table/table-properties/table-properties.spec.ts @@ -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({ - fill: "b79c2f", - val: ShadingType.REVERSE_DIAGONAL_STRIPE, - color: "auto", + 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": [ diff --git a/src/file/table/table-properties/table-properties.ts b/src/file/table/table-properties/table-properties.ts index 8a7d000d5b..7682c29cb0 100644 --- a/src/file/table/table-properties/table-properties.ts +++ b/src/file/table/table-properties/table-properties.ts @@ -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 || {})); - public setWidth(width: number, type: WidthType = WidthType.AUTO): TableProperties { - this.root.push(new PreferredTableWidth(type, width)); - return this; - } + if (options.borders) { + this.root.push(new TableBorders(options.borders)); + } - public setLayout(type: TableLayoutType): void { - this.root.push(new TableLayout(type)); - } + if (options.width) { + this.root.push(new PreferredTableWidth(options.width.type, options.width.size)); + } - public setBorder(borderOptions: ITableBordersOptions): TableProperties { - this.root.push(new TableBorders(borderOptions)); - return this; - } + if (options.float) { + this.root.push(new TableFloatProperties(options.float)); + } - public get CellMargin(): TableCellMargin { - return this.cellMargin; - } + if (options.layout) { + this.root.push(new TableLayout(options.layout)); + } - public setTableFloatProperties(tableFloatOptions: ITableFloatOptions): TableProperties { - this.root.push(new TableFloatProperties(tableFloatOptions)); - return this; - } + if (options.alignment) { + this.root.push(new Alignment(options.alignment)); + } - 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)); + } } } diff --git a/src/file/table/table-properties/table-width.ts b/src/file/table/table-properties/table-width.ts index a463e958df..44468c744d 100644 --- a/src/file/table/table-properties/table-width.ts +++ b/src/file/table/table-properties/table-width.ts @@ -13,7 +13,7 @@ class TableWidthAttributes extends XmlAttributeComponent { } 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 })); diff --git a/src/file/table/table.ts b/src/file/table/table.ts index 69b3c0f775..74928f5c18 100644 --- a/src/file/table/table.ts +++ b/src/file/table/table.ts @@ -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); - } } }