Files
docx-js/src/file/table/table-cell/table-cell-components.ts
Bruce Duncan 816cb54b14 Optimize XML output by properly constructing objects to send to the xml library so that it can produce proper empty elements.
Rework the way attributes are stored in ImportedXmlComponent to match elsewhere (required allowing for a null xmlKeys in the XmlAttributeComponent interface).
Rework the way paragraphs get added to the end of table cells if needed.
The goal in both reworks is to not mess around with the objects output from `prepForXml` if we can avoid it.
Made the output of RunProperties, ParagraphProperties, TableCellProperties, TableRowProperties, and TableProperties all optional based on whether they contain any attributes or children.  Changed code in PageBorders, TableCellMargin, and TableCellBorders that implemented this same thing by overriding `prepForXml` so that it uses the new XmlComponent subclass instead.
Removed commented out code that attempted to fix-up XML output and make proper empty elements.
Fixed all affected tests.
Turn off `no-null-keyword` in the linter as we need to use null to signal to the `xml` library to create an empty element with no attributes (`undefined` will not work in its place).

Fixes #306
2019-04-09 05:27:18 -04:00

191 lines
4.8 KiB
TypeScript

import { BorderStyle } from "file/styles";
import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent, XmlComponent } from "file/xml-components";
interface ICellBorder {
readonly style: BorderStyle;
readonly size: number;
readonly color: string;
}
class CellBorderAttributes extends XmlAttributeComponent<ICellBorder> {
protected readonly xmlKeys = { style: "w:val", size: "w:sz", color: "w:color" };
}
class BaseTableCellBorder extends XmlComponent {
public setProperties(style: BorderStyle, size: number, color: string): BaseTableCellBorder {
const attrs = new CellBorderAttributes({
style: style,
size: size,
color: color,
});
this.root.push(attrs);
return this;
}
}
export class TableCellBorders extends IgnoreIfEmptyXmlComponent {
constructor() {
super("w:tcBorders");
}
public addTopBorder(style: BorderStyle, size: number, color: string): TableCellBorders {
const top = new BaseTableCellBorder("w:top");
top.setProperties(style, size, color);
this.root.push(top);
return this;
}
public addStartBorder(style: BorderStyle, size: number, color: string): TableCellBorders {
const start = new BaseTableCellBorder("w:start");
start.setProperties(style, size, color);
this.root.push(start);
return this;
}
public addBottomBorder(style: BorderStyle, size: number, color: string): TableCellBorders {
const bottom = new BaseTableCellBorder("w:bottom");
bottom.setProperties(style, size, color);
this.root.push(bottom);
return this;
}
public addEndBorder(style: BorderStyle, size: number, color: string): TableCellBorders {
const end = new BaseTableCellBorder("w:end");
end.setProperties(style, size, color);
this.root.push(end);
return this;
}
public addLeftBorder(style: BorderStyle, size: number, color: string): TableCellBorders {
const left = new BaseTableCellBorder("w:left");
left.setProperties(style, size, color);
this.root.push(left);
return this;
}
public addRightBorder(style: BorderStyle, size: number, color: string): TableCellBorders {
const right = new BaseTableCellBorder("w:right");
right.setProperties(style, size, color);
this.root.push(right);
return this;
}
}
/**
* Attributes fot the GridSpan element.
*/
class GridSpanAttributes extends XmlAttributeComponent<{ readonly val: number }> {
protected readonly xmlKeys = { val: "w:val" };
}
/**
* GridSpan element. Should be used in a table cell. Pass the number of columns that this cell need to span.
*/
export class GridSpan extends XmlComponent {
constructor(value: number) {
super("w:gridSpan");
this.root.push(
new GridSpanAttributes({
val: value,
}),
);
}
}
/**
* Vertical merge types.
*/
export enum VMergeType {
/**
* Cell that is merged with upper one.
*/
CONTINUE = "continue",
/**
* Cell that is starting the vertical merge.
*/
RESTART = "restart",
}
class VMergeAttributes extends XmlAttributeComponent<{ readonly val: VMergeType }> {
protected readonly xmlKeys = { val: "w:val" };
}
/**
* Vertical merge element. Should be used in a table cell.
*/
export class VMerge extends XmlComponent {
constructor(value: VMergeType) {
super("w:vMerge");
this.root.push(
new VMergeAttributes({
val: value,
}),
);
}
}
export enum VerticalAlign {
BOTTOM = "bottom",
CENTER = "center",
TOP = "top",
}
class VAlignAttributes extends XmlAttributeComponent<{ readonly val: VerticalAlign }> {
protected readonly xmlKeys = { val: "w:val" };
}
/**
* Vertical align element.
*/
export class VAlign extends XmlComponent {
constructor(value: VerticalAlign) {
super("w:vAlign");
this.root.push(
new VAlignAttributes({
val: value,
}),
);
}
}
export enum WidthType {
/** Auto. */
AUTO = "auto",
/** Value is in twentieths of a point */
DXA = "dxa",
/** No (empty) value. */
NIL = "nil",
/** Value is in percentage. */
PERCENTAGE = "pct",
}
class TableCellWidthAttributes extends XmlAttributeComponent<{ readonly type: WidthType; readonly width: string | number }> {
protected readonly xmlKeys = { width: "w:w", type: "w:type" };
}
/**
* Table cell width element.
*/
export class TableCellWidth extends XmlComponent {
constructor(value: string | number, type: WidthType) {
super("w:tcW");
this.root.push(
new TableCellWidthAttributes({
width: value,
type: type,
}),
);
}
}