Merge branch 'master' into add-table-option-styleId

# Conflicts:
#	src/file/table/table.ts
This commit is contained in:
Dolan
2021-03-07 21:40:42 +00:00
319 changed files with 20572 additions and 2876 deletions

View File

@ -1,3 +1,5 @@
export * from "./table-properties";
export * from "./table-float-properties";
export * from "./table-layout";
export * from "./table-borders";
export * from "./table-overlap";

View File

@ -0,0 +1,622 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { BorderStyle } from "file/styles";
import { TableBorders } from "./table-borders";
describe("TableBorders", () => {
describe("#constructor", () => {
describe("default borders", () => {
it("should add a table cell top border using default width type", () => {
const tableBorders = new TableBorders({});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
],
});
});
});
describe("top border", () => {
it("should add a table cell top border", () => {
const tableBorders = new TableBorders({
top: {
style: BorderStyle.DOUBLE,
size: 1,
color: "red",
},
});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "red",
"w:space": 0,
"w:sz": 1,
"w:val": "double",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
],
});
});
});
describe("left border", () => {
it("should add a table cell left border", () => {
const tableBorders = new TableBorders({
left: {
style: BorderStyle.DOUBLE,
size: 1,
color: "red",
},
});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:left": {
_attr: {
"w:color": "red",
"w:space": 0,
"w:sz": 1,
"w:val": "double",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
],
});
});
});
describe("bottom border", () => {
it("should add a table cell bottom border", () => {
const tableBorders = new TableBorders({
bottom: {
style: BorderStyle.DOUBLE,
size: 1,
color: "red",
},
});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "red",
"w:space": 0,
"w:sz": 1,
"w:val": "double",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
],
});
});
});
describe("right border", () => {
it("should add a table cell right border", () => {
const tableBorders = new TableBorders({
right: {
style: BorderStyle.DOUBLE,
size: 1,
color: "red",
},
});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:right": {
_attr: {
"w:color": "red",
"w:space": 0,
"w:sz": 1,
"w:val": "double",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
],
});
});
});
describe("inside horizontal border", () => {
it("should add a table cell inside horizontal border", () => {
const tableBorders = new TableBorders({
insideHorizontal: {
style: BorderStyle.DOUBLE,
size: 1,
color: "red",
},
});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "red",
"w:space": 0,
"w:sz": 1,
"w:val": "double",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
],
});
});
});
describe("inside vertical border", () => {
it("should add a table cell inside horizontal border", () => {
const tableBorders = new TableBorders({
insideVertical: {
style: BorderStyle.DOUBLE,
size: 1,
color: "red",
},
});
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 4,
"w:val": "single",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "red",
"w:space": 0,
"w:sz": 1,
"w:val": "double",
},
},
},
],
});
});
});
describe("TableBorders.NONE convenience object", () => {
it("should add no borders", () => {
const tableBorders = new TableBorders(TableBorders.NONE);
const tree = new Formatter().format(tableBorders);
expect(tree).to.deep.equal({
"w:tblBorders": [
{
"w:top": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 0,
"w:val": "none",
},
},
},
{
"w:left": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 0,
"w:val": "none",
},
},
},
{
"w:bottom": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 0,
"w:val": "none",
},
},
},
{
"w:right": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 0,
"w:val": "none",
},
},
},
{
"w:insideH": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 0,
"w:val": "none",
},
},
},
{
"w:insideV": {
_attr: {
"w:color": "auto",
"w:space": 0,
"w:sz": 0,
"w:val": "none",
},
},
},
],
});
});
});
});
});

View File

@ -1,14 +1,128 @@
// http://officeopenxml.com/WPtableBorders.php
import { BorderStyle } from "file/styles";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export interface ITableBordersOptions {
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 insideHorizontal?: {
readonly style: BorderStyle;
readonly size: number;
readonly color: string;
};
readonly insideVertical?: {
readonly style: BorderStyle;
readonly size: number;
readonly color: string;
};
}
export class TableBorders extends XmlComponent {
constructor() {
public static readonly NONE = {
top: {
style: BorderStyle.NONE,
size: 0,
color: "auto",
},
bottom: {
style: BorderStyle.NONE,
size: 0,
color: "auto",
},
left: {
style: BorderStyle.NONE,
size: 0,
color: "auto",
},
right: {
style: BorderStyle.NONE,
size: 0,
color: "auto",
},
insideHorizontal: {
style: BorderStyle.NONE,
size: 0,
color: "auto",
},
insideVertical: {
style: BorderStyle.NONE,
size: 0,
color: "auto",
},
};
constructor(options: ITableBordersOptions) {
super("w:tblBorders");
this.root.push(new TableBordersElement("w:top", "single", 4, 0, "auto"));
this.root.push(new TableBordersElement("w:left", "single", 4, 0, "auto"));
this.root.push(new TableBordersElement("w:bottom", "single", 4, 0, "auto"));
this.root.push(new TableBordersElement("w:right", "single", 4, 0, "auto"));
this.root.push(new TableBordersElement("w:insideH", "single", 4, 0, "auto"));
this.root.push(new TableBordersElement("w:insideV", "single", 4, 0, "auto"));
if (options.top) {
this.root.push(new TableBordersElement("w:top", options.top.style, options.top.size, 0, options.top.color));
} else {
this.root.push(new TableBordersElement("w:top", BorderStyle.SINGLE, 4, 0, "auto"));
}
if (options.left) {
this.root.push(new TableBordersElement("w:left", options.left.style, options.left.size, 0, options.left.color));
} else {
this.root.push(new TableBordersElement("w:left", BorderStyle.SINGLE, 4, 0, "auto"));
}
if (options.bottom) {
this.root.push(new TableBordersElement("w:bottom", options.bottom.style, options.bottom.size, 0, options.bottom.color));
} else {
this.root.push(new TableBordersElement("w:bottom", BorderStyle.SINGLE, 4, 0, "auto"));
}
if (options.right) {
this.root.push(new TableBordersElement("w:right", options.right.style, options.right.size, 0, options.right.color));
} else {
this.root.push(new TableBordersElement("w:right", BorderStyle.SINGLE, 4, 0, "auto"));
}
if (options.insideHorizontal) {
this.root.push(
new TableBordersElement(
"w:insideH",
options.insideHorizontal.style,
options.insideHorizontal.size,
0,
options.insideHorizontal.color,
),
);
} else {
this.root.push(new TableBordersElement("w:insideH", BorderStyle.SINGLE, 4, 0, "auto"));
}
if (options.insideVertical) {
this.root.push(
new TableBordersElement(
"w:insideV",
options.insideVertical.style,
options.insideVertical.size,
0,
options.insideVertical.color,
),
);
} else {
this.root.push(new TableBordersElement("w:insideV", BorderStyle.SINGLE, 4, 0, "auto"));
}
}
}

View File

@ -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 } } }] });
});

View File

@ -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));
}
}
}

View File

@ -3,11 +3,12 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType, TableFloatProperties } from "./table-float-properties";
import { OverlapType } from "./table-overlap";
describe("Table Float Properties", () => {
describe("#constructor", () => {
it("should construct a TableFloatProperties with all options", () => {
const tfp = new TableFloatProperties({
const properties = new TableFloatProperties({
horizontalAnchor: TableAnchorType.MARGIN,
verticalAnchor: TableAnchorType.PAGE,
absoluteHorizontalPosition: 10,
@ -19,8 +20,32 @@ describe("Table Float Properties", () => {
leftFromText: 50,
rightFromText: 60,
});
const tree = new Formatter().format(tfp);
expect(tree).to.be.deep.equal(DEFAULT_TFP);
const tree = new Formatter().format(properties);
expect(tree).to.deep.equal(DEFAULT_TFP);
});
it("should add overlap", () => {
const properties = new TableFloatProperties({
overlap: OverlapType.NEVER,
});
const tree = new Formatter().format(properties);
expect(tree).to.deep.equal({
"w:tblpPr": [
{
_attr: {
overlap: "never",
},
},
{
"w:tblOverlap": {
_attr: {
"w:val": "never",
},
},
},
],
});
});
});
});

View File

@ -1,5 +1,7 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { OverlapType, TableOverlap } from "./table-overlap";
export enum TableAnchorType {
MARGIN = "margin",
PAGE = "page",
@ -109,6 +111,7 @@ export interface ITableFloatOptions {
* to the right of the table. The value is in twentieths of a point. If omitted, the value is assumed to be zero.
*/
readonly rightFromText?: number;
readonly overlap?: OverlapType;
}
export class TableFloatOptionsAttributes extends XmlAttributeComponent<ITableFloatOptions> {
@ -130,5 +133,9 @@ export class TableFloatProperties extends XmlComponent {
constructor(options: ITableFloatOptions) {
super("w:tblpPr");
this.root.push(new TableFloatOptionsAttributes(options));
if (options.overlap) {
this.root.push(new TableOverlap(options.overlap));
}
}
}

View File

@ -0,0 +1,22 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { OverlapType, TableOverlap } from "./table-overlap";
describe("TableOverlap", () => {
describe("#constructor", () => {
it("sets the width attribute to the value given", () => {
const tableOverlap = new TableOverlap(OverlapType.OVERLAP);
const tree = new Formatter().format(tableOverlap);
expect(tree).to.deep.equal({
"w:tblOverlap": {
_attr: {
"w:val": "overlap",
},
},
});
});
});
});

View File

@ -0,0 +1,17 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
export enum OverlapType {
NEVER = "never",
OVERLAP = "overlap",
}
class TableOverlapAttributes extends XmlAttributeComponent<{ readonly val: OverlapType }> {
protected readonly xmlKeys = { val: "w:val" };
}
export class TableOverlap extends XmlComponent {
constructor(type: OverlapType) {
super("w:tblOverlap");
this.root.push(new TableOverlapAttributes({ val: type }));
}
}

View File

@ -2,6 +2,7 @@ import { expect } from "chai";
import { Formatter } from "export/formatter";
import { AlignmentType } from "../../paragraph";
import { ShadingType } from "../shading";
import { WidthType } from "../table-cell";
import { TableLayoutType } from "./table-layout";
@ -10,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
@ -31,7 +32,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 } } }],
@ -39,7 +45,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 } } }],
@ -49,8 +60,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" } } }],
@ -60,8 +73,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 } } }] }],
@ -69,8 +89,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 } } }] }],
@ -80,12 +107,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": [
@ -102,4 +131,40 @@ describe("TableProperties", () => {
});
});
});
describe("#setAlignment", () => {
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": [
{
"w:jc": {
_attr: {
"w:val": "center",
},
},
},
],
});
});
});
describe("#Set Virtual Right to Left", () => {
it("sets the alignment of the table", () => {
const tp = new TableProperties({
visuallyRightToLeft: true,
});
const tree = new Formatter().format(tp);
expect(tree).to.deep.equal({
"w:tblPr": [
{
"w:bidiVisual": {},
},
],
});
});
});
});

View File

@ -1,55 +1,68 @@
// http://officeopenxml.com/WPtableProperties.php
import { IgnoreIfEmptyXmlComponent } from "file/xml-components";
import { Alignment, AlignmentType } from "../../paragraph";
import { ITableShadingAttributesProperties, TableShading } from "../shading";
import { WidthType } from "../table-cell";
import { TableBorders } from "./table-borders";
import { TableCellMargin } from "./table-cell-margin";
import { ITableBordersOptions, TableBorders } from "./table-borders";
import { ITableCellMarginOptions, TableCellMargin } from "./table-cell-margin";
import { ITableFloatOptions, TableFloatProperties } from "./table-float-properties";
import { TableLayout, TableLayoutType } from "./table-layout";
import { TableStyle } from "./table-style";
import { PreferredTableWidth } from "./table-width";
import { VisuallyRightToLeft } from "./visually-right-to-left";
export interface ITablePropertiesOptions {
readonly width?: {
readonly size: number;
readonly type?: WidthType;
};
readonly layout?: TableLayoutType;
readonly borders?: ITableBordersOptions;
readonly float?: ITableFloatOptions;
readonly shading?: ITableShadingAttributesProperties;
readonly style?: string;
readonly alignment?: AlignmentType;
readonly cellMargin?: ITableCellMarginOptions;
readonly visuallyRightToLeft?: boolean;
}
export class TableProperties extends IgnoreIfEmptyXmlComponent {
private readonly cellMargin: TableCellMargin;
constructor() {
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(): TableProperties {
this.root.push(new TableBorders());
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));
if (options.shading) {
this.root.push(new TableShading(options.shading));
}
return this;
}
if (options.visuallyRightToLeft) {
this.root.push(new VisuallyRightToLeft());
}
public setStyle(styleId: string): TableProperties {
this.root.push(new TableStyle(styleId));
return this;
if (options.style) {
this.root.push(new TableStyle(options.style));
}
}
}

View File

@ -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 }));

View File

@ -0,0 +1,14 @@
import { expect } from "chai";
import { Formatter } from "export/formatter";
import { VisuallyRightToLeft } from "./visually-right-to-left";
describe("VisuallyRightToLeft", () => {
it("should create", () => {
const visuallyRightToLeft = new VisuallyRightToLeft();
const tree = new Formatter().format(visuallyRightToLeft);
expect(tree).to.deep.equal({
"w:bidiVisual": {},
});
});
});

View File

@ -0,0 +1,8 @@
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_bidiVisual_topic_ID0EOXIQ.html
import { XmlComponent } from "file/xml-components";
export class VisuallyRightToLeft extends XmlComponent {
constructor() {
super("w:bidiVisual");
}
}