diff --git a/src/file/document/body/section-properties/properties/column.ts b/src/file/document/body/section-properties/properties/column.ts
index b0b12d9c8e..b90606f436 100644
--- a/src/file/document/body/section-properties/properties/column.ts
+++ b/src/file/document/body/section-properties/properties/column.ts
@@ -1,25 +1,23 @@
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
-export interface IColumnAttributes {
- readonly width: number | string;
- readonly space?: number | string;
-}
+//
+//
+//
+//
-export class ColumnAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = {
- width: "w:w",
- space: "w:space",
- };
-}
+type IColumnAttributes = {
+ readonly width: number | PositiveUniversalMeasure;
+ readonly space?: number | PositiveUniversalMeasure;
+};
export class Column extends XmlComponent {
public constructor({ width, space }: IColumnAttributes) {
super("w:col");
this.root.push(
- new ColumnAttributes({
- width: twipsMeasureValue(width),
- space: space === undefined ? undefined : twipsMeasureValue(space),
+ new NextAttributeComponent({
+ width: { key: "w:w", value: twipsMeasureValue(width) },
+ space: { key: "w:space", value: space === undefined ? undefined : twipsMeasureValue(space) },
}),
);
}
diff --git a/src/file/document/body/section-properties/properties/columns.ts b/src/file/document/body/section-properties/properties/columns.ts
index dc09e60462..8cf204d1a6 100644
--- a/src/file/document/body/section-properties/properties/columns.ts
+++ b/src/file/document/body/section-properties/properties/columns.ts
@@ -1,5 +1,5 @@
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { decimalNumber, twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { decimalNumber, PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
import { Column } from "./column";
@@ -12,32 +12,23 @@ import { Column } from "./column";
//
//
//
-export interface IColumnsAttributes {
- readonly space?: number | string;
+export type IColumnsAttributes = {
+ readonly space?: number | PositiveUniversalMeasure;
readonly count?: number;
readonly separate?: boolean;
readonly equalWidth?: boolean;
readonly children?: readonly Column[];
-}
-
-export class ColumnsAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = {
- space: "w:space",
- count: "w:num",
- separate: "w:sep",
- equalWidth: "w:equalWidth",
- };
-}
+};
export class Columns extends XmlComponent {
public constructor({ space, count, separate, equalWidth, children }: IColumnsAttributes) {
super("w:cols");
this.root.push(
- new ColumnsAttributes({
- space: space === undefined ? undefined : twipsMeasureValue(space),
- count: count === undefined ? undefined : decimalNumber(count),
- separate,
- equalWidth,
+ new NextAttributeComponent>({
+ space: { key: "w:space", value: space === undefined ? undefined : twipsMeasureValue(space) },
+ count: { key: "w:num", value: count === undefined ? undefined : decimalNumber(count) },
+ separate: { key: "w:sep", value: separate },
+ equalWidth: { key: "w:equalWidth", value: equalWidth },
}),
);
diff --git a/src/file/document/body/section-properties/properties/line-number.ts b/src/file/document/body/section-properties/properties/line-number.ts
index 4d0e622119..845c7b70e1 100644
--- a/src/file/document/body/section-properties/properties/line-number.ts
+++ b/src/file/document/body/section-properties/properties/line-number.ts
@@ -1,6 +1,6 @@
// http://officeopenxml.com/WPsectionLineNumbering.php
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { decimalNumber, twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { decimalNumber, PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
//
//
@@ -26,27 +26,23 @@ export interface ILineNumberAttributes {
readonly countBy?: number;
readonly start?: number;
readonly restart?: LineNumberRestartFormat;
- readonly distance?: number | string;
-}
-
-export class LineNumberAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = {
- countBy: "w:countBy",
- start: "w:start",
- restart: "w:restart",
- distance: "w:distance",
- };
+ readonly distance?: number | PositiveUniversalMeasure;
}
export class LineNumberType extends XmlComponent {
public constructor({ countBy, start, restart, distance }: ILineNumberAttributes) {
super("w:lnNumType");
this.root.push(
- new LineNumberAttributes({
- countBy: countBy === undefined ? undefined : decimalNumber(countBy),
- start: start === undefined ? undefined : decimalNumber(start),
- restart,
- distance: distance === undefined ? undefined : twipsMeasureValue(distance),
+ new NextAttributeComponent<{
+ readonly countBy?: number;
+ readonly start?: number;
+ readonly restart?: LineNumberRestartFormat;
+ readonly distance?: number | PositiveUniversalMeasure;
+ }>({
+ countBy: { key: "w:countBy", value: countBy === undefined ? undefined : decimalNumber(countBy) },
+ start: { key: "w:start", value: start === undefined ? undefined : decimalNumber(start) },
+ restart: { key: "w:restart", value: restart },
+ distance: { key: "w:distance", value: distance === undefined ? undefined : twipsMeasureValue(distance) },
}),
);
}
diff --git a/src/file/document/body/section-properties/properties/page-margin.ts b/src/file/document/body/section-properties/properties/page-margin.ts
index ed0044a417..5e905c0f73 100644
--- a/src/file/document/body/section-properties/properties/page-margin.ts
+++ b/src/file/document/body/section-properties/properties/page-margin.ts
@@ -1,5 +1,5 @@
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { signedTwipsMeasureValue, twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { PositiveUniversalMeasure, signedTwipsMeasureValue, twipsMeasureValue, UniversalMeasure } from "@util/values";
//
//
@@ -10,48 +10,36 @@ import { signedTwipsMeasureValue, twipsMeasureValue } from "@util/values";
//
//
//
-export interface IPageMarginAttributes {
- readonly top?: number | string;
- readonly right?: number | string;
- readonly bottom?: number | string;
- readonly left?: number | string;
- readonly header?: number | string;
- readonly footer?: number | string;
- readonly gutter?: number | string;
-}
-
-export class PageMarginAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = {
- top: "w:top",
- right: "w:right",
- bottom: "w:bottom",
- left: "w:left",
- header: "w:header",
- footer: "w:footer",
- gutter: "w:gutter",
- };
-}
+export type IPageMarginAttributes = {
+ readonly top?: number | UniversalMeasure;
+ readonly right?: number | PositiveUniversalMeasure;
+ readonly bottom?: number | UniversalMeasure;
+ readonly left?: number | PositiveUniversalMeasure;
+ readonly header?: number | PositiveUniversalMeasure;
+ readonly footer?: number | PositiveUniversalMeasure;
+ readonly gutter?: number | PositiveUniversalMeasure;
+};
export class PageMargin extends XmlComponent {
public constructor(
- top: number | string,
- right: number | string,
- bottom: number | string,
- left: number | string,
- header: number | string,
- footer: number | string,
- gutter: number | string,
+ top: number | UniversalMeasure,
+ right: number | PositiveUniversalMeasure,
+ bottom: number | UniversalMeasure,
+ left: number | PositiveUniversalMeasure,
+ header: number | PositiveUniversalMeasure,
+ footer: number | PositiveUniversalMeasure,
+ gutter: number | PositiveUniversalMeasure,
) {
super("w:pgMar");
this.root.push(
- new PageMarginAttributes({
- top: signedTwipsMeasureValue(top),
- right: twipsMeasureValue(right),
- bottom: signedTwipsMeasureValue(bottom),
- left: twipsMeasureValue(left),
- header: twipsMeasureValue(header),
- footer: twipsMeasureValue(footer),
- gutter: twipsMeasureValue(gutter),
+ new NextAttributeComponent({
+ top: { key: "w:top", value: signedTwipsMeasureValue(top) },
+ right: { key: "w:right", value: twipsMeasureValue(right) },
+ bottom: { key: "w:bottom", value: signedTwipsMeasureValue(bottom) },
+ left: { key: "w:left", value: twipsMeasureValue(left) },
+ header: { key: "w:header", value: twipsMeasureValue(header) },
+ footer: { key: "w:footer", value: twipsMeasureValue(footer) },
+ gutter: { key: "w:gutter", value: twipsMeasureValue(gutter) },
}),
);
}
diff --git a/src/file/document/body/section-properties/properties/page-size.ts b/src/file/document/body/section-properties/properties/page-size.ts
index c1e10c48c4..efc4ad404f 100644
--- a/src/file/document/body/section-properties/properties/page-size.ts
+++ b/src/file/document/body/section-properties/properties/page-size.ts
@@ -1,5 +1,5 @@
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
//
//
@@ -18,22 +18,14 @@ export enum PageOrientation {
//
//
//
-export interface IPageSizeAttributes {
- readonly width?: number | string;
- readonly height?: number | string;
+export type IPageSizeAttributes = {
+ readonly width?: number | PositiveUniversalMeasure;
+ readonly height?: number | PositiveUniversalMeasure;
readonly orientation?: PageOrientation;
-}
-
-export class PageSizeAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = {
- width: "w:w",
- height: "w:h",
- orientation: "w:orient",
- };
-}
+};
export class PageSize extends XmlComponent {
- public constructor(width: number | string, height: number | string, orientation: PageOrientation) {
+ public constructor(width: number | PositiveUniversalMeasure, height: number | PositiveUniversalMeasure, orientation: PageOrientation) {
super("w:pgSz");
const flip = orientation === PageOrientation.LANDSCAPE;
@@ -42,10 +34,10 @@ export class PageSize extends XmlComponent {
const heightTwips = twipsMeasureValue(height);
this.root.push(
- new PageSizeAttributes({
- width: flip ? heightTwips : widthTwips,
- height: flip ? widthTwips : heightTwips,
- orientation: orientation,
+ new NextAttributeComponent({
+ width: { key: "w:w", value: flip ? heightTwips : widthTwips },
+ height: { key: "w:h", value: flip ? widthTwips : heightTwips },
+ orientation: { key: "w:orient", value: orientation },
}),
);
}
diff --git a/src/file/document/body/section-properties/section-properties.ts b/src/file/document/body/section-properties/section-properties.ts
index 5323b77c74..fbcdcf9f88 100644
--- a/src/file/document/body/section-properties/section-properties.ts
+++ b/src/file/document/body/section-properties/section-properties.ts
@@ -5,9 +5,9 @@ import { FooterWrapper } from "@file/footer-wrapper";
import { HeaderWrapper } from "@file/header-wrapper";
import { VerticalAlign, VerticalAlignElement } from "@file/vertical-align";
import { OnOffElement, XmlComponent } from "@file/xml-components";
+import { PositiveUniversalMeasure, UniversalMeasure } from "@util/values";
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
-
import { Columns, IColumnsAttributes } from "./properties/columns";
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
import { ILineNumberAttributes, LineNumberType } from "./properties/line-number";
@@ -76,10 +76,10 @@ export interface ISectionPropertiesOptions {
//
export const sectionMarginDefaults = {
- TOP: "1in",
- RIGHT: "1in",
- BOTTOM: "1in",
- LEFT: "1in",
+ TOP: "1in" as UniversalMeasure,
+ RIGHT: "1in" as PositiveUniversalMeasure,
+ BOTTOM: "1in" as UniversalMeasure,
+ LEFT: "1in" as PositiveUniversalMeasure,
HEADER: 708,
FOOTER: 708,
GUTTER: 0,
diff --git a/src/file/paragraph/formatting/indent.ts b/src/file/paragraph/formatting/indent.ts
index daa5d2925e..059cf9c2a9 100644
--- a/src/file/paragraph/formatting/indent.ts
+++ b/src/file/paragraph/formatting/indent.ts
@@ -1,39 +1,14 @@
// http://officeopenxml.com/WPindentation.php
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { signedTwipsMeasureValue, twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { PositiveUniversalMeasure, signedTwipsMeasureValue, twipsMeasureValue, UniversalMeasure } from "@util/values";
export interface IIndentAttributesProperties {
- readonly start?: number | string;
- readonly end?: number | string;
- readonly left?: number | string;
- readonly right?: number | string;
- readonly hanging?: number | string;
- readonly firstLine?: number | string;
-}
-
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-class IndentAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = {
- start: "w:start",
- end: "w:end",
- left: "w:left",
- right: "w:right",
- hanging: "w:hanging",
- firstLine: "w:firstLine",
- };
+ readonly start?: number | UniversalMeasure;
+ readonly end?: number | UniversalMeasure;
+ readonly left?: number | UniversalMeasure;
+ readonly right?: number | UniversalMeasure;
+ readonly hanging?: number | PositiveUniversalMeasure;
+ readonly firstLine?: number | PositiveUniversalMeasure;
}
//
@@ -43,14 +18,53 @@ class IndentAttributes extends XmlAttributeComponent
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
this.root.push(
- new IndentAttributes({
- start: start === undefined ? undefined : signedTwipsMeasureValue(start),
- end: end === undefined ? undefined : signedTwipsMeasureValue(end),
- left: left === undefined ? undefined : signedTwipsMeasureValue(left),
- right: right === undefined ? undefined : signedTwipsMeasureValue(right),
- hanging: hanging === undefined ? undefined : twipsMeasureValue(hanging),
- firstLine: firstLine === undefined ? undefined : twipsMeasureValue(firstLine),
+ new NextAttributeComponent<{
+ readonly start?: number | UniversalMeasure;
+ readonly end?: number | UniversalMeasure;
+ readonly left?: number | UniversalMeasure;
+ readonly right?: number | UniversalMeasure;
+ readonly hanging?: number | PositiveUniversalMeasure;
+ readonly firstLine?: number | PositiveUniversalMeasure;
+ }>({
+ start: {
+ key: "w:start",
+ value: start === undefined ? undefined : signedTwipsMeasureValue(start),
+ },
+ end: {
+ key: "w:end",
+ value: end === undefined ? undefined : signedTwipsMeasureValue(end),
+ },
+ left: {
+ key: "w:left",
+ value: left === undefined ? undefined : signedTwipsMeasureValue(left),
+ },
+ right: {
+ key: "w:right",
+ value: right === undefined ? undefined : signedTwipsMeasureValue(right),
+ },
+ hanging: {
+ key: "w:hanging",
+ value: hanging === undefined ? undefined : twipsMeasureValue(hanging),
+ },
+ firstLine: {
+ key: "w:firstLine",
+ value: firstLine === undefined ? undefined : twipsMeasureValue(firstLine),
+ },
}),
);
}
diff --git a/src/file/paragraph/run/formatting.ts b/src/file/paragraph/run/formatting.ts
index b78e3291a7..3629dd36ee 100644
--- a/src/file/paragraph/run/formatting.ts
+++ b/src/file/paragraph/run/formatting.ts
@@ -1,8 +1,8 @@
import { Attributes, XmlComponent } from "@file/xml-components";
-import { hexColorValue, signedTwipsMeasureValue } from "@util/values";
+import { hexColorValue, signedTwipsMeasureValue, UniversalMeasure } from "@util/values";
export class CharacterSpacing extends XmlComponent {
- public constructor(value: number | string) {
+ public constructor(value: number | UniversalMeasure) {
super("w:spacing");
this.root.push(
new Attributes({
diff --git a/src/file/paragraph/run/properties.ts b/src/file/paragraph/run/properties.ts
index bb774cbc3d..41ca650995 100644
--- a/src/file/paragraph/run/properties.ts
+++ b/src/file/paragraph/run/properties.ts
@@ -9,6 +9,7 @@ import {
StringValueElement,
XmlComponent,
} from "@file/xml-components";
+import { PositiveUniversalMeasure, UniversalMeasure } from "@util/values";
import { EmphasisMark, EmphasisMarkType } from "./emphasis-mark";
import { CharacterSpacing, Color, Highlight, HighlightComplexScript } from "./formatting";
@@ -22,6 +23,16 @@ interface IFontOptions {
readonly hint?: string;
}
+export enum TextEffect {
+ BLINK_BACKGROUND = "blinkBackground",
+ LIGHTS = "lights",
+ ANTS_BLACK = "antsBlack",
+ ANTS_RED = "antsRed",
+ SHIMMER = "shimmer",
+ SPARKLE = "sparkle",
+ NONE = "none",
+}
+
export interface IRunStylePropertiesOptions {
readonly bold?: boolean;
readonly boldComplexScript?: boolean;
@@ -31,12 +42,15 @@ export interface IRunStylePropertiesOptions {
readonly color?: string;
readonly type?: UnderlineType;
};
+ readonly effect?: TextEffect;
readonly emphasisMark?: {
readonly type?: EmphasisMarkType;
};
readonly color?: string;
- readonly size?: number | string;
- readonly sizeComplexScript?: boolean | number | string;
+ readonly kern?: number | PositiveUniversalMeasure;
+ readonly position?: UniversalMeasure;
+ readonly size?: number | PositiveUniversalMeasure;
+ readonly sizeComplexScript?: boolean | number | PositiveUniversalMeasure;
readonly rightToLeft?: boolean;
readonly smallCaps?: boolean;
readonly allCaps?: boolean;
@@ -54,9 +68,11 @@ export interface IRunStylePropertiesOptions {
readonly revision?: IRunPropertiesChangeOptions;
readonly language?: ILanguageOptions;
readonly border?: IBorderOptions;
+ readonly snapToGrid?: boolean;
readonly vanish?: boolean;
readonly specVanish?: boolean;
readonly scale?: number;
+ readonly math?: boolean;
}
export interface IRunPropertiesOptions extends IRunStylePropertiesOptions {
@@ -135,6 +151,10 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
this.push(new Underline(options.underline.type, options.underline.color));
}
+ if (options.effect) {
+ this.push(new StringValueElement("w:effect", options.effect));
+ }
+
if (options.emphasisMark) {
this.push(new EmphasisMark(options.emphasisMark.type));
}
@@ -143,6 +163,14 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
this.push(new Color(options.color));
}
+ if (options.kern) {
+ this.push(new HpsMeasureElement("w:kern", options.kern));
+ }
+
+ if (options.position) {
+ this.push(new StringValueElement("w:position", options.position));
+ }
+
if (options.size !== undefined) {
this.push(new HpsMeasureElement("w:sz", options.size));
}
@@ -228,6 +256,10 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
this.push(new BorderElement("w:bdr", options.border));
}
+ if (options.snapToGrid) {
+ this.push(new OnOffElement("w:snapToGrid", options.snapToGrid));
+ }
+
if (options.vanish) {
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_vanish_topic_ID0E6W3O.html
// http://www.datypic.com/sc/ooxml/e-w_vanish-1.html
@@ -246,6 +278,10 @@ export class RunProperties extends IgnoreIfEmptyXmlComponent {
if (options.language) {
this.push(createLanguageComponent(options.language));
}
+
+ if (options.math) {
+ this.push(new OnOffElement("w:oMath", options.math));
+ }
}
public push(item: XmlComponent): void {
diff --git a/src/file/paragraph/run/run.spec.ts b/src/file/paragraph/run/run.spec.ts
index 2a207a7b87..b639e08e49 100644
--- a/src/file/paragraph/run/run.spec.ts
+++ b/src/file/paragraph/run/run.spec.ts
@@ -7,6 +7,7 @@ import { ShadingType } from "@file/shading";
import { EmphasisMarkType } from "./emphasis-mark";
import { PageNumber, Run } from "./run";
import { UnderlineType } from "./underline";
+import { TextEffect } from "./properties";
describe("Run", () => {
describe("#bold()", () => {
@@ -610,5 +611,117 @@ describe("Run", () => {
});
});
});
+
+ describe("#position", () => {
+ it("should correctly set the position", () => {
+ const run = new Run({
+ position: "2mm",
+ });
+ const tree = new Formatter().format(run);
+ expect(tree).to.deep.equal({
+ "w:r": [
+ {
+ "w:rPr": [
+ {
+ "w:position": {
+ _attr: {
+ "w:val": "2mm",
+ },
+ },
+ },
+ ],
+ },
+ ],
+ });
+ });
+ });
+
+ describe("#effect", () => {
+ it("should correctly set the effect", () => {
+ const run = new Run({
+ effect: TextEffect.ANTS_BLACK,
+ });
+ const tree = new Formatter().format(run);
+ expect(tree).to.deep.equal({
+ "w:r": [
+ {
+ "w:rPr": [
+ {
+ "w:effect": {
+ _attr: {
+ "w:val": "antsBlack",
+ },
+ },
+ },
+ ],
+ },
+ ],
+ });
+ });
+ });
+
+ describe("#math", () => {
+ it("should correctly set the math", () => {
+ const run = new Run({
+ math: true,
+ });
+ const tree = new Formatter().format(run);
+ expect(tree).to.deep.equal({
+ "w:r": [
+ {
+ "w:rPr": [
+ {
+ "w:oMath": {},
+ },
+ ],
+ },
+ ],
+ });
+ });
+ });
+
+ describe("#kern", () => {
+ it("should correctly set the kern", () => {
+ const run = new Run({
+ kern: "2mm",
+ });
+ const tree = new Formatter().format(run);
+ expect(tree).to.deep.equal({
+ "w:r": [
+ {
+ "w:rPr": [
+ {
+ "w:kern": {
+ _attr: {
+ "w:val": "2mm",
+ },
+ },
+ },
+ ],
+ },
+ ],
+ });
+ });
+ });
+
+ describe("#snapToGrid", () => {
+ it("should correctly set the snapToGrid", () => {
+ const run = new Run({
+ snapToGrid: true,
+ });
+ const tree = new Formatter().format(run);
+ expect(tree).to.deep.equal({
+ "w:r": [
+ {
+ "w:rPr": [
+ {
+ "w:snapToGrid": {},
+ },
+ ],
+ },
+ ],
+ });
+ });
+ });
});
});
diff --git a/src/file/table/grid.ts b/src/file/table/grid.ts
index 719253b8b2..14eb60c886 100644
--- a/src/file/table/grid.ts
+++ b/src/file/table/grid.ts
@@ -9,11 +9,11 @@
//
//
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { twipsMeasureValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
export class TableGrid extends XmlComponent {
- public constructor(widths: readonly number[] | readonly string[]) {
+ public constructor(widths: readonly number[] | readonly PositiveUniversalMeasure[]) {
super("w:tblGrid");
for (const width of widths) {
this.root.push(new GridCol(width));
@@ -21,15 +21,15 @@ export class TableGrid extends XmlComponent {
}
}
-class GridColAttributes extends XmlAttributeComponent<{ readonly w: number | string }> {
- protected readonly xmlKeys = { w: "w:w" };
-}
-
export class GridCol extends XmlComponent {
- public constructor(width?: number | string) {
+ public constructor(width?: number | PositiveUniversalMeasure) {
super("w:gridCol");
if (width !== undefined) {
- this.root.push(new GridColAttributes({ w: twipsMeasureValue(width) }));
+ this.root.push(
+ new NextAttributeComponent<{ readonly width: number | PositiveUniversalMeasure }>({
+ width: { key: "w:w", value: twipsMeasureValue(width) },
+ }),
+ );
}
}
}
diff --git a/src/file/table/table-properties/table-float-properties.ts b/src/file/table/table-properties/table-float-properties.ts
index fdcf696d07..e7f32dc572 100644
--- a/src/file/table/table-properties/table-float-properties.ts
+++ b/src/file/table/table-properties/table-float-properties.ts
@@ -1,5 +1,5 @@
import { StringEnumValueElement, XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { signedTwipsMeasureValue, twipsMeasureValue } from "@util/values";
+import { PositiveUniversalMeasure, signedTwipsMeasureValue, twipsMeasureValue, UniversalMeasure } from "@util/values";
export enum TableAnchorType {
MARGIN = "margin",
@@ -55,7 +55,7 @@ export interface ITableFloatOptions {
* If relativeHorizontalPosition is also specified, then the absoluteHorizontalPosition attribute is ignored.
* If the attribute is omitted, the value is assumed to be zero.
*/
- readonly absoluteHorizontalPosition?: number | string;
+ readonly absoluteHorizontalPosition?: number | UniversalMeasure;
/**
* Specifies a relative horizontal position for the table, relative to the horizontalAnchor attribute.
@@ -86,7 +86,7 @@ export interface ITableFloatOptions {
* If relativeVerticalPosition is also specified, then the absoluteVerticalPosition attribute is ignored.
* If the attribute is omitted, the value is assumed to be zero.
*/
- readonly absoluteVerticalPosition?: number | string;
+ readonly absoluteVerticalPosition?: number | UniversalMeasure;
/**
* Specifies a relative vertical position for the table, relative to the verticalAnchor attribute.
@@ -104,25 +104,25 @@ export interface ITableFloatOptions {
* Specifies the minimum distance to be maintained between the table and the top of text in the paragraph
* below the table. The value is in twentieths of a point. If omitted, the value is assumed to be zero.
*/
- readonly bottomFromText?: number | string;
+ readonly bottomFromText?: number | PositiveUniversalMeasure;
/**
* Specifies the minimum distance to be maintained between the table and the bottom edge of text in the paragraph
* above the table. The value is in twentieths of a point. If omitted, the value is assumed to be zero.
*/
- readonly topFromText?: number | string;
+ readonly topFromText?: number | PositiveUniversalMeasure;
/**
* Specifies the minimum distance to be maintained between the table and the edge of text in the paragraph
* to the left of the table. The value is in twentieths of a point. If omitted, the value is assumed to be zero.
*/
- readonly leftFromText?: number | string;
+ readonly leftFromText?: number | PositiveUniversalMeasure;
/**
* Specifies the minimum distance to be maintained between the table and the edge of text in the paragraph
* 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 | string;
+ readonly rightFromText?: number | PositiveUniversalMeasure;
readonly overlap?: OverlapType;
}
diff --git a/src/file/table/table-row/table-row-height.ts b/src/file/table/table-row/table-row-height.ts
index 12294b7f4e..4c6043bb47 100644
--- a/src/file/table/table-row/table-row-height.ts
+++ b/src/file/table/table-row/table-row-height.ts
@@ -1,5 +1,5 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { twipsMeasureValue } from "@util/values";
+import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
//
//
@@ -30,7 +30,7 @@ export class TableRowHeightAttributes extends XmlAttributeComponent<{
}
export class TableRowHeight extends XmlComponent {
- public constructor(value: number | string, rule: HeightRule) {
+ public constructor(value: number | PositiveUniversalMeasure, rule: HeightRule) {
super("w:trHeight");
this.root.push(
diff --git a/src/file/table/table-row/table-row-properties.ts b/src/file/table/table-row/table-row-properties.ts
index c4fa01ea6d..d388e917eb 100644
--- a/src/file/table/table-row/table-row-properties.ts
+++ b/src/file/table/table-row/table-row-properties.ts
@@ -28,6 +28,7 @@
//
//
import { IgnoreIfEmptyXmlComponent, OnOffElement } from "@file/xml-components";
+import { PositiveUniversalMeasure } from "@util/values";
import { HeightRule, TableRowHeight } from "./table-row-height";
@@ -35,7 +36,7 @@ export interface ITableRowPropertiesOptions {
readonly cantSplit?: boolean;
readonly tableHeader?: boolean;
readonly height?: {
- readonly value: number | string;
+ readonly value: number | PositiveUniversalMeasure;
readonly rule: HeightRule;
};
}
diff --git a/src/file/table/table-width.ts b/src/file/table/table-width.ts
index 38c941b2f1..1c2e29a0c5 100644
--- a/src/file/table/table-width.ts
+++ b/src/file/table/table-width.ts
@@ -1,6 +1,6 @@
// http://officeopenxml.com/WPtableWidth.php
-import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
-import { measurementOrPercentValue } from "@util/values";
+import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
+import { measurementOrPercentValue, Percentage, UniversalMeasure } from "@util/values";
//
//
@@ -25,14 +25,10 @@ export enum WidthType {
//
//
//
-export interface ITableWidthProperties {
- readonly size: string | number;
+export type ITableWidthProperties = {
+ readonly size: number | Percentage | UniversalMeasure;
readonly type?: WidthType;
-}
-
-class TableWidthAttributes extends XmlAttributeComponent {
- protected readonly xmlKeys = { type: "w:type", size: "w:w" };
-}
+};
export class TableWidthElement extends XmlComponent {
public constructor(name: string, { type = WidthType.AUTO, size }: ITableWidthProperties) {
@@ -42,6 +38,12 @@ export class TableWidthElement extends XmlComponent {
if (type === WidthType.PERCENTAGE && typeof size === "number") {
tableWidthValue = `${size}%`;
}
- this.root.push(new TableWidthAttributes({ type: type, size: measurementOrPercentValue(tableWidthValue) }));
+
+ this.root.push(
+ new NextAttributeComponent({
+ type: { key: "w:type", value: type },
+ size: { key: "w:w", value: measurementOrPercentValue(tableWidthValue) },
+ }),
+ );
}
}
diff --git a/src/file/xml-components/simple-elements.ts b/src/file/xml-components/simple-elements.ts
index b81901232c..6ed117b7ba 100644
--- a/src/file/xml-components/simple-elements.ts
+++ b/src/file/xml-components/simple-elements.ts
@@ -1,6 +1,6 @@
import { AttributeData, AttributePayload, Attributes, NextAttributeComponent, XmlComponent } from "@file/xml-components";
-import { hpsMeasureValue } from "@util/values";
+import { hpsMeasureValue, PositiveUniversalMeasure } from "@util/values";
// This represents element type CT_OnOff, which indicate a boolean value.
//
@@ -26,8 +26,13 @@ export class OnOffElement extends XmlComponent {
//
//
//
+
+//
+//
+//
+
export class HpsMeasureElement extends XmlComponent {
- public constructor(name: string, val: number | string) {
+ public constructor(name: string, val: number | PositiveUniversalMeasure) {
super(name);
this.root.push(new Attributes({ val: hpsMeasureValue(val) }));
}
diff --git a/src/util/values.spec.ts b/src/util/values.spec.ts
index b4b36dbe44..32df1a74b2 100644
--- a/src/util/values.spec.ts
+++ b/src/util/values.spec.ts
@@ -25,13 +25,6 @@ describe("values", () => {
expect(universalMeasureValue("5.22pc")).to.eq("5.22pc");
expect(universalMeasureValue("100 pi")).to.eq("100pi");
});
- it("should throw on invalid values", () => {
- expect(() => universalMeasureValue("100pp")).to.throw();
- expect(() => universalMeasureValue("foo")).to.throw();
- expect(() => universalMeasureValue("--in")).to.throw();
- expect(() => universalMeasureValue("NaNpc")).to.throw();
- expect(() => universalMeasureValue("50")).to.throw();
- });
});
describe("positiveUniversalMeasureValue", () => {
@@ -46,11 +39,6 @@ describe("values", () => {
it("should throw on invalid values", () => {
expect(() => positiveUniversalMeasureValue("-9mm")).to.throw();
expect(() => positiveUniversalMeasureValue("-0.5in")).to.throw();
- expect(() => positiveUniversalMeasureValue("100pp")).to.throw();
- expect(() => positiveUniversalMeasureValue("foo")).to.throw();
- expect(() => positiveUniversalMeasureValue("--in")).to.throw();
- expect(() => positiveUniversalMeasureValue("NaNpc")).to.throw();
- expect(() => positiveUniversalMeasureValue("50")).to.throw();
});
});
@@ -116,7 +104,6 @@ describe("values", () => {
});
it("should throw on invalid values", () => {
expect(() => signedTwipsMeasureValue(NaN)).to.throw();
- expect(() => signedTwipsMeasureValue("foo")).to.throw();
});
});
@@ -129,7 +116,6 @@ describe("values", () => {
it("should throw on invalid values", () => {
expect(() => twipsMeasureValue(-12)).to.throw();
expect(() => twipsMeasureValue(NaN)).to.throw();
- expect(() => twipsMeasureValue("foo")).to.throw();
expect(() => twipsMeasureValue("-5mm")).to.throw();
});
});
@@ -154,7 +140,6 @@ describe("values", () => {
});
it("should throw on invalid values", () => {
expect(() => hpsMeasureValue(NaN)).to.throw();
- expect(() => hpsMeasureValue("5FF")).to.throw();
});
});
@@ -165,11 +150,6 @@ describe("values", () => {
expect(percentageValue("100%")).to.eq("100%");
expect(percentageValue("1000%")).to.eq("1000%");
});
- it("should throw on invalid values", () => {
- expect(() => percentageValue("0%%")).to.throw();
- expect(() => percentageValue("20")).to.throw();
- expect(() => percentageValue("FF%")).to.throw();
- });
});
describe("measurementOrPercentValue", () => {
@@ -181,8 +161,6 @@ describe("values", () => {
});
it("should throw on invalid values", () => {
expect(() => measurementOrPercentValue(NaN)).to.throw();
- expect(() => measurementOrPercentValue("10%%")).to.throw();
- expect(() => measurementOrPercentValue("10F")).to.throw();
});
});
diff --git a/src/util/values.ts b/src/util/values.ts
index f44e2eb1d9..4776210e69 100644
--- a/src/util/values.ts
+++ b/src/util/values.ts
@@ -4,6 +4,23 @@
// Most of the rest of the types not defined here are either aliases of existing types or enumerations.
// Enumerations should probably just be implemented as enums, with instructions to end-users, without a runtime check.
+// -?[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)
+export type UniversalMeasure = `${"-" | ""}${number}${"mm" | "cm" | "in" | "pt" | "pc" | "pi"}`;
+
+//
+//
+//
+//
+//
+export type PositiveUniversalMeasure = `${number}${"mm" | "cm" | "in" | "pt" | "pc" | "pi"}`;
+
+//
+//
+//
+//
+//
+export type Percentage = `${"-" | ""}${number}%`;
+
//
//
//
@@ -70,30 +87,23 @@ export const uCharHexNumber = (val: string): string => hexBinary(val, 1);
//
//
//
-export const universalMeasureValue = (val: string): string => {
+export const universalMeasureValue = (val: UniversalMeasure): UniversalMeasure => {
const unit = val.slice(-2);
- if (!universalMeasureUnits.includes(unit)) {
- throw new Error(`Invalid unit '${unit}' specified. Valid units are ${universalMeasureUnits.join(", ")}`);
- }
const amount = val.substring(0, val.length - 2);
- if (isNaN(Number(amount))) {
- throw new Error(`Invalid value '${amount}' specified. Expected a valid number.`);
- }
- return `${Number(amount)}${unit}`;
+ return `${Number(amount)}${unit}` as UniversalMeasure;
};
-const universalMeasureUnits = ["mm", "cm", "in", "pt", "pc", "pi"];
//
//
//
//
//
-export const positiveUniversalMeasureValue = (val: string): string => {
+export const positiveUniversalMeasureValue = (val: PositiveUniversalMeasure): PositiveUniversalMeasure => {
const value = universalMeasureValue(val);
if (parseFloat(value) < 0) {
throw new Error(`Invalid value '${value}' specified. Expected a positive number.`);
}
- return value;
+ return value as PositiveUniversalMeasure;
};
//
@@ -123,25 +133,25 @@ export const hexColorValue = (val: string): string => {
//
//
//
-export const signedTwipsMeasureValue = (val: string | number): string | number =>
+export const signedTwipsMeasureValue = (val: UniversalMeasure | number): UniversalMeasure | number =>
typeof val === "string" ? universalMeasureValue(val) : decimalNumber(val);
//
//
//
-export const hpsMeasureValue = (val: string | number): string | number =>
+export const hpsMeasureValue = (val: PositiveUniversalMeasure | number): string | number =>
typeof val === "string" ? positiveUniversalMeasureValue(val) : unsignedDecimalNumber(val);
//
//
//
-export const signedHpsMeasureValue = (val: string | number): string | number =>
+export const signedHpsMeasureValue = (val: UniversalMeasure | number): string | number =>
typeof val === "string" ? universalMeasureValue(val) : decimalNumber(val);
//
//
//
-export const twipsMeasureValue = (val: string | number): string | number =>
+export const twipsMeasureValue = (val: PositiveUniversalMeasure | number): PositiveUniversalMeasure | number =>
typeof val === "string" ? positiveUniversalMeasureValue(val) : unsignedDecimalNumber(val);
//
@@ -149,14 +159,8 @@ export const twipsMeasureValue = (val: string | number): string | number =>
//
//
//
-export const percentageValue = (val: string): string => {
- if (val.slice(-1) !== "%") {
- throw new Error(`Invalid value '${val}'. Expected percentage value (eg '55%')`);
- }
+export const percentageValue = (val: Percentage): Percentage => {
const percent = val.substring(0, val.length - 1);
- if (isNaN(Number(percent))) {
- throw new Error(`Invalid value '${percent}' specified. Expected a valid number.`);
- }
return `${Number(percent)}%`;
};
@@ -172,14 +176,14 @@ export const percentageValue = (val: string): string => {
//
//
-export const measurementOrPercentValue = (val: number | string): number | string => {
+export const measurementOrPercentValue = (val: number | Percentage | UniversalMeasure): number | UniversalMeasure | Percentage => {
if (typeof val === "number") {
return decimalNumber(val);
}
if (val.slice(-1) === "%") {
- return percentageValue(val);
+ return percentageValue(val as Percentage);
}
- return universalMeasureValue(val);
+ return universalMeasureValue(val as UniversalMeasure);
};
//